SSM-CRUD

一、项目简介

主界面演示

功能点

  • 分页
  • 数据校验
  • ajax
  • Rest 风格的 URI

技术点

  • 基础框架 - ssmSpring + SpringMVC + MyBatis
  • 数据库 - MySQL
  • 前端框架 - bootstrap (快速简洁美观的界面)
  • 项目的依赖管理 - Maven
  • 分页 - pagehelper
  • 逆向工程 - MyBatis Generator

二、基础环境搭建

1、创建 Maven 工程 ssm_crud_study

3、添加 web 框架

(1)右键工程,点击 Add Framework Suppor

(2)选择 Web Application

3、在 pom.xml 中引入项目依赖

  • Spring
  • SpringMVC
  • MyBatis
  • 数据库连接池,驱动包
  • 其他(jstl,servlet-api,junit)

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.chen</groupId>
  7. <artifactId>ssm-crud</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <dependencies>
  10. <!-- pagehelper 分页插件 -->
  11. <dependency>
  12. <groupId>com.github.pagehelper</groupId>
  13. <artifactId>pagehelper</artifactId>
  14. <version>5.0.0</version>
  15. </dependency>
  16. <!-- MBG -->
  17. <dependency>
  18. <groupId>org.mybatis.generator</groupId>
  19. <artifactId>mybatis-generator-core</artifactId>
  20. <version>1.3.5</version>
  21. </dependency>
  22. <!-- Spring MVC -->
  23. <dependency>
  24. <groupId>org.springframework</groupId>
  25. <artifactId>spring-webmvc</artifactId>
  26. <version>4.3.7.RELEASE</version>
  27. </dependency>
  28. <!-- 返回 json 字符串的支持 -->
  29. <dependency>
  30. <groupId>com.fasterxml.jackson.core</groupId>
  31. <artifactId>jackson-databind</artifactId>
  32. <version>2.8.8</version>
  33. </dependency>
  34. <!-- JS303 数据校验支持 -->
  35. <dependency>
  36. <groupId>org.hibernate</groupId>
  37. <artifactId>hibernate-validator</artifactId>
  38. <version>5.4.1.Final</version>
  39. </dependency>
  40. <!-- Spring Jdbc -->
  41. <dependency>
  42. <groupId>org.springframework</groupId>
  43. <artifactId>spring-jdbc</artifactId>
  44. <version>4.3.7.RELEASE</version>
  45. </dependency>
  46. <!-- Spring Test -->
  47. <dependency>
  48. <groupId>org.springframework</groupId>
  49. <artifactId>spring-test</artifactId>
  50. <version>4.3.7.RELEASE</version>
  51. <scope>test</scope>
  52. </dependency>
  53. <!-- 面向切面编程 -->
  54. <dependency>
  55. <groupId>org.springframework</groupId>
  56. <artifactId>spring-aspects</artifactId>
  57. <version>4.3.7.RELEASE</version>
  58. </dependency>
  59. <!-- Mybatis -->
  60. <dependency>
  61. <groupId>org.mybatis</groupId>
  62. <artifactId>mybatis</artifactId>
  63. <version>3.4.2</version>
  64. </dependency>
  65. <!-- MyBatis 适配包 -->
  66. <dependency>
  67. <groupId>org.mybatis</groupId>
  68. <artifactId>mybatis-spring</artifactId>
  69. <version>1.3.1</version>
  70. </dependency>
  71. <!-- 数据库连接池 -->
  72. <dependency>
  73. <groupId>com.mchange</groupId>
  74. <artifactId>c3p0</artifactId>
  75. <version>0.9.2</version>
  76. </dependency>
  77. <!-- mysql -->
  78. <dependency>
  79. <groupId>mysql</groupId>
  80. <artifactId>mysql-connector-java</artifactId>
  81. <version>8.0.21</version>
  82. </dependency>
  83. <!-- jstl -->
  84. <dependency>
  85. <groupId>jstl</groupId>
  86. <artifactId>jstl</artifactId>
  87. <version>1.2</version>
  88. </dependency>
  89. <!-- servlet-api -->
  90. <dependency>
  91. <groupId>javax.servlet</groupId>
  92. <artifactId>javax.servlet-api</artifactId>
  93. <version>3.0.1</version>
  94. <scope>provided</scope>
  95. </dependency>
  96. <!-- junit -->
  97. <dependency>
  98. <groupId>junit</groupId>
  99. <artifactId>junit</artifactId>
  100. <version>4.12</version>
  101. <scope>test</scope>
  102. </dependency>
  103. <!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
  104. <dependency>
  105. <groupId>javax.servlet</groupId>
  106. <artifactId>jsp-api</artifactId>
  107. <version>2.0</version>
  108. <scope>provided</scope>
  109. </dependency>
  110. </dependencies>
  111. </project>

4、引入 bootstrap 前端框架

(1)前往 bootstrap 官网下载

下载地址: https://v3.bootcss.com,选择用于生产环境的 Bootstrap

(2)解压后将文件夹添加到工程中 /static

5、编写 ssm 整合的关键配置文件

  • **web.xml,主要用于配置 Filter、Listener、Servlet **

  • springmvc 配置文件,主要控制网站逻辑的跳转

  • spring 配置文件,主要配置与业务逻辑相关的文件

  • mybatis 配置文件,主要用于配置 MyBatis

(1)配置 web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. <!-- 1、启动 Spring 的容器 -->
  7. <context-param>
  8. <param-name>contextConfigLocation</param-name>
  9. <param-value>classpath:applicationContext.xml</param-value>
  10. </context-param>
  11. <listener>
  12. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  13. </listener>
  14. <!-- 2、配置 SpringMVC 前端控制器
  15. 默认会加载 WEB-INF 下的 <servletName>-servlet.xml 配置文件
  16. 即 dispatcherServlet-servlet.xml
  17. -->
  18. <servlet>
  19. <servlet-name>dispatcherServlet</servlet-name>
  20. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  21. <load-on-startup>1</load-on-startup>
  22. </servlet>
  23. <servlet-mapping>
  24. <servlet-name>dispatcherServlet</servlet-name>
  25. <url-pattern>/</url-pattern>
  26. </servlet-mapping>
  27. <!-- 3、字符编码过滤器,一定要放在所有过滤器之前 -->
  28. <filter>
  29. <filter-name>characterEncodingFilter</filter-name>
  30. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  31. <init-param>
  32. <param-name>encoding</param-name>
  33. <param-value>utf-8</param-value>
  34. </init-param>
  35. <init-param>
  36. <param-name>forceRequestEncoding</param-name>
  37. <param-value>true</param-value>
  38. </init-param>
  39. <init-param>
  40. <param-name>forceResponseEncoding</param-name>
  41. <param-value>true</param-value>
  42. </init-param>
  43. </filter>
  44. <filter-mapping>
  45. <filter-name>characterEncodingFilter</filter-name>
  46. <url-pattern>/*</url-pattern>
  47. </filter-mapping>
  48. <!-- 4、使用 Rest 风格的 URI,将页面普通的 post 请求转为指定的 delete 或者 put 请求 -->
  49. <filter>
  50. <filter-name>hiddenHttpMethodFilter</filter-name>
  51. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  52. </filter>
  53. <filter-mapping>
  54. <filter-name>hiddenHttpMethodFilter</filter-name>
  55. <url-pattern>/*</url-pattern>
  56. </filter-mapping>
  57. <filter>
  58. <filter-name>httpPutFormContentFilter</filter-name>
  59. <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
  60. </filter>
  61. <filter-mapping>
  62. <filter-name>httpPutFormContentFilter</filter-name>
  63. <url-pattern>/*</url-pattern>
  64. </filter-mapping>
  65. </web-app>

在 src/main/resources/ 下加入 applicationContext.xml, 防止 idea 报错

(2)配置 springmvc 配置文件

WEB-INF 下加入 dispatcherServlet-servlet.xml

src/main/java 创建包结构

**配置 dispatcherServlet-servlet.xml **

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  7. <!-- Spring MVC 的配置文件,主要控制网站逻辑的跳转 -->
  8. <context:component-scan base-package="com.study" use-default-filters="false">
  9. <!-- 只扫描控制器 -->
  10. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  11. </context:component-scan>
  12. <!-- 配置视图解析器,方便页面返回 -->
  13. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  14. <property name="prefix" value="/WEB-INF/views/"/>
  15. <property name="suffix" value=".jsp"/>
  16. </bean>
  17. <!-- 两个标准配置 -->
  18. <!-- 将 Spring MVC 不能处理的请求交给 Tomcat -->
  19. <mvc:default-servlet-handler/>
  20. <!-- Spring MVC 更高级的一些功能,JSR303 检验,快捷的 ajax ... 映射动态请求 -->
  21. <mvc:annotation-driven/>
  22. </beans>

(3) 配置 spring 配置文件

配置 dbconfig.properties ,配置数据库连接信息

src/main/resources 下加入 dbconfig.properties

dbconfig.properties

  1. jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud_study?useUnicode=true&characterEncoding=utf8
  2. jdbc.driverClass=com.mysql.cj.jdbc.Driver
  3. jdbc.user=root
  4. jdbc.password=root

src/main/resources 下创建 mybatis-config.xml、mapper文件夹

配置 applicationContext.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
  7. <context:component-scan base-package="com.chen">
  8. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  9. </context:component-scan>
  10. <!-- Spring 的配置文件,主要配置与业务逻辑相关的文件 -->
  11. <!-- 数据源、事务控制 ... -->
  12. <context:property-placeholder location="classpath:dbconfig.properties"/>
  13. <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  14. <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
  15. <property name="driverClass" value="${jdbc.driverClass}"/>
  16. <property name="user" value="${jdbc.user}"/>
  17. <property name="password" value="${jdbc.password}"/>
  18. </bean>
  19. <!-- ================================ 配置和 MyBatis 的整合 =============================== -->
  20. <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
  21. <!-- 指定 MyBatis 全局配置文件的位置 -->
  22. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  23. <property name="dataSource" ref="pooledDataSource"/>
  24. <!-- 指定 MyBatis mapper 文件的位置 -->
  25. <property name="mapperLocations" value="classpath:mapper/*.xml"/>
  26. </bean>
  27. <!-- 配置一个执行批量的 sqlSession -->
  28. <bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
  29. <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
  30. <constructor-arg name="executorType" value="BATCH"/>
  31. </bean>
  32. <!-- 配置扫描器,将 MyBatis 接口的实现加入到 ioc 容器中 -->
  33. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  34. <!-- 扫描所有 dao 接口的实现,加到 ioc 容器中 -->
  35. <property name="sqlSessionTemplateBeanName" value="sessionTemplate"/>
  36. <property name="basePackage" value="com.study"/>
  37. </bean>
  38. <!-- 事务控制的配置 -->
  39. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  40. <!-- 控制住数据源 -->
  41. <property name="dataSource" ref="pooledDataSource"/>
  42. </bean>
  43. <!-- 开启基于注解的事务,使用 xml 配置形式的事务(必要主要的都是使用配置式) -->
  44. <aop:config>
  45. <!-- 切入点表达式 -->
  46. <aop:pointcut id="txPoint" expression="execution(* com.chen.crud.service..*(..))"/>
  47. <!-- 配置事务增强 -->
  48. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
  49. </aop:config>
  50. <!-- 配置事务增强,事务如何切入 -->
  51. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  52. <tx:attributes>
  53. <!-- 所有方法都是事务方法 -->
  54. <tx:method name="*"/>
  55. <!-- 以 get 开始的所有方法 -->
  56. <tx:method name="get*" read-only="true"/>
  57. </tx:attributes>
  58. </tx:advice>
  59. </beans>

此处目前会报错,是因为此时 mapper 文件夹目录下没有 .xml 文件,目前可忽略

(4)配置 mybatis 文件

mybatis-config.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <settings>
  7. <!-- 开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn -->
  8. <setting name="mapUnderscoreToCamelCase" value="true"/>
  9. </settings>
  10. <typeAliases>
  11. <!-- 类型别名可为 Java 类型设置一个缩写名字
  12. 每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author
  13. -->
  14. <package name="com.study.crud.bean"/>
  15. </typeAliases>
  16. <plugins>
  17. <!-- 分页插件 -->
  18. <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
  19. </plugins>
  20. </configuration>

6、创建数据库

  1. CREATE DATABASE ssm_crud_study;
  2. CREATE TABLE `ssm_crud_study`.`tbl_emp` (
  3. `emp_id` INT NOT NULL AUTO_INCREMENT,
  4. `emp_name` VARCHAR(255) NOT NULL,
  5. `gender` CHAR(1) NULL,
  6. `email` VARCHAR(255) NULL,
  7. `d_id` INT NULL,
  8. PRIMARY KEY (`emp_id`));
  9. CREATE TABLE `ssm_crud_study`.`tbl_dept` (
  10. `dept_id` INT NOT NULL,
  11. `dept_name` VARCHAR(255) NOT NULL,
  12. PRIMARY KEY (`dept_id`));
  13. ALTER TABLE `ssm_crud_study`.`tbl_emp`
  14. ADD INDEX `dept_id_idx` (`d_id` ASC) VISIBLE;
  15. ;
  16. ALTER TABLE `ssm_crud_study`.`tbl_emp`
  17. ADD CONSTRAINT `dept_id`
  18. FOREIGN KEY (`d_id`)
  19. REFERENCES `ssm_crud_study`.`tbl_dept` (`dept_id`)
  20. ON DELETE NO ACTION
  21. ON UPDATE NO ACTION;

7、使用 mapper 的逆向工程生成 bean、mapper

在工程中添加 mbg.xml

配置 mbg.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6. <context id="DB2Tables" targetRuntime="MyBatis3">
  7. <commentGenerator>
  8. <!-- 去除生成的 bean、mapper 中的注释 -->
  9. <property name="suppressAllComments" value="true" />
  10. </commentGenerator>
  11. <!-- 配置数据库连接 -->
  12. <jdbcConnection driverClass="com.mysql.jdbc.Driver"
  13. connectionURL="jdbc:mysql://localhost:3306/ssm_crud_study?useUnicode=true&amp;characterEncoding=utf8"
  14. userId="root"
  15. password="root">
  16. </jdbcConnection>
  17. <javaTypeResolver >
  18. <property name="forceBigDecimals" value="false" />
  19. </javaTypeResolver>
  20. <!-- 指定 javaBean 生成的位置 -->
  21. <javaModelGenerator targetPackage="com.study.crud.bean" targetProject="src/main/java">
  22. <property name="enableSubPackages" value="true" />
  23. <property name="trimStrings" value="true" />
  24. </javaModelGenerator>
  25. <!-- 指定 sql 映射文件生成的位置 -->
  26. <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
  27. <property name="enableSubPackages" value="true" />
  28. </sqlMapGenerator>
  29. <!-- 指定 dao 接口生成的位置 -->
  30. <javaClientGenerator type="XMLMAPPER" targetPackage="com.study.crud.dao" targetProject="src/main/java">
  31. <property name="enableSubPackages" value="true" />
  32. </javaClientGenerator>
  33. <!-- table 指定每个表的生成策略 -->
  34. <table tableName="tbl_emp" domainObjectName="Employee">
  35. </table>
  36. <table tableName="tbl_dept" domainObjectName="Department"></table>
  37. </context>
  38. </generatorConfiguration>

src/test/java 中创建 MBGTest 用于生成 bean、mapper

  1. public class MBGTest {
  2. public static void main(String[] args) throws Exception {
  3. List<String> warnings = new ArrayList<String>();
  4. boolean overwrite = true;
  5. File configFile = new File("mbg.xml");
  6. ConfigurationParser cp = new ConfigurationParser(warnings);
  7. Configuration config = cp.parseConfiguration(configFile);
  8. DefaultShellCallback callback = new DefaultShellCallback(overwrite);
  9. MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
  10. myBatisGenerator.generate(null);
  11. }
  12. }

运行结果:自动生成 bean、mapper

8、测试 mapper

在数据库中添加数据

  1. INSERT INTO `ssm_crud_study`.`tbl_dept` (`dept_id`, `dept_name`) VALUES ('1', '开发部');
  2. INSERT INTO `ssm_crud_study`.`tbl_dept` (`dept_id`, `dept_name`) VALUES ('2', '测试部');
  3. INSERT INTO `ssm_crud_study`.`tbl_emp` (`emp_id`, `emp_name`, `gender`, `email`, `d_id`) VALUES ('1', 'Jerry', 'M', 'jerry@163.com', '1');

src/test/java 创建 MapperTest

首先测验能否连接到获得 mapper 实例

测试能否获取数据库中信息

向数据库中插入 1000 条数据

  1. // 使用 Spring Test
  2. @RunWith(SpringJUnit4ClassRunner.class)
  3. @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
  4. public class MapperTest {
  5. @Autowired
  6. DepartmentMapper departmentMapper;
  7. // 可以执行批量操作的 sqlSession
  8. @Autowired
  9. SqlSession sqlSession;
  10. @Test
  11. public void testCRUD() {
  12. // System.out.println(departmentMapper);
  13. // Department department = departmentMapper.selectByPrimaryKey(1);
  14. // System.out.println("dept_id=" + department.getDeptId() + ",dept_name=" + department.getDeptName());
  15. EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
  16. for (int i = 0; i < 1000; i++) {
  17. // 使用 UUID 工具类,随机生成用户名
  18. String empName = UUID.randomUUID().toString().substring(0, 5);
  19. // 需要在 Employee 中添加有参构造,!!!添加有参构造后必须添加无参构造 !!!
  20. mapper.insertSelective(new Employee(null, empName, "M", empName + "@qq.com", 1));
  21. }
  22. }
  23. }

三、CRUD开发

1、index.jsp

流程

  • 访问 index.jsp 页面
  • index.jsp 页面发送出查询员工列表请求
  • EmployeeController 来接收请求,查处员工数据
  • 来到 list.jsp 页面进行展示
  • pageHelper 分页插件完成分页查询功能

index.jsp 添加标签 jsp:forward 跳转到 /emps

com.study.crud.controller 中添加 EmployeeController,并编写映射请求

/WEB-INF/viwes/ 下添加 list.jsp

启动服务器,查看是否跳转成功

我们查询员工时,希望能够查询出部门的信息,所以需要在 EmployeeMapper 中添加新的查询方法,并在 Employee 中添加 Department 属性,和 get、set 方法


EmployeeMapper.xml 中添加 SQL

  1. <resultMap id="WithDeptResultMap" type="com.study.crud.bean.Employee">
  2. <id column="emp_id" jdbcType="INTEGER" property="empId" />
  3. <result column="emp_name" jdbcType="VARCHAR" property="empName" />
  4. <result column="gender" jdbcType="CHAR" property="gender" />
  5. <result column="email" jdbcType="VARCHAR" property="email" />
  6. <result column="d_id" jdbcType="INTEGER" property="dId" />
  7. <association property="department" javaType="com.study.crud.bean.Department">
  8. <id column="dept_id" property="deptId"/>
  9. <result column="dept_name" property="deptName"/>
  10. </association>
  11. </resultMap>
  12. <sql id="WithDept_Column_List">
  13. e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
  14. </sql>
  15. <!-- List<Employee> selectByExampleWithDept(EmployeeExample example);
  16. Employee selectByPrimaryKeyWithDept(Integer empId);-->
  17. <select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
  18. select
  19. <if test="distinct">
  20. distinct
  21. </if>
  22. <include refid="WithDept_Column_List" />
  23. FROM tbl_emp e
  24. LEFT JOIN tbl_dept d ON e.d_id = d.dept_id
  25. <if test="_parameter != null">
  26. <include refid="Example_Where_Clause" />
  27. </if>
  28. <if test="orderByClause != null">
  29. order by ${orderByClause}
  30. </if>
  31. </select>
  32. <select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
  33. select
  34. <include refid="WithDept_Column_List" />
  35. FROM tbl_emp e
  36. LEFT JOIN tbl_dept d ON e.d_id = d.dept_id
  37. where emp_id = #{empId,jdbcType=INTEGER}
  38. </select>

EmployeeService 中添加 getAll() 方法

EmployeeController.getEmps() 中引入分页插件

src/test/ 下添加测试,测试分页插件

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @WebAppConfiguration
  3. @ContextConfiguration(locations = {"classpath:applicationContext.xml", "file:web/WEB-INF/dispatcherServlet-servlet.xml"})
  4. public class MVCTest {
  5. // 传入 Spring MVC 的 ioc
  6. @Autowired
  7. WebApplicationContext context;
  8. // 虚拟 mvc 请求,获取到处理结果
  9. MockMvc mockMvc;
  10. @Before
  11. public void initMockMvc() {
  12. mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
  13. }
  14. @Test
  15. public void testPage() throws Exception {
  16. // 模拟请求拿到返回值
  17. MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "5")).andReturn();
  18. // 请求成功以后,请求域中会有 pageInfo
  19. MockHttpServletRequest request = result.getRequest();
  20. PageInfo page = (PageInfo) request.getAttribute("pageInfo");
  21. System.out.println("当前页码:" + page.getPageNum());
  22. System.out.println("总页码:" + page.getPages());
  23. System.out.println("总记录数:" + page.getTotal());
  24. System.out.println("在页面需要连续显示的页码");
  25. int[] nums = page.getNavigatepageNums();
  26. for (int num : nums)
  27. System.out.print(" " + num);
  28. System.out.println();
  29. List<Employee> emps = page.getList();
  30. for (Employee emp : emps)
  31. System.out.println("ID:" + emp.getEmpId() + "==>Name:" + emp.getEmpName());
  32. }
  33. }

测试结果

2、list.jsp

/static 下加入 jquery

list.jsp 中引入 bootstrap、jquery

前往 Bootstrap 官网,查看文档


根据文档创建 新建 删除 按钮

查看效果

给按钮添加样式


查看样式

根据文档可以写出表格界面

  1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  3. <html>
  4. <head>
  5. <title>员工列表</title>
  6. <% pageContext.setAttribute("APP_PATH", request.getContextPath()); %>
  7. <%--
  8. 不以 / 开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
  9. / 开始的相对路径,找资源,以服务器的路径为标准 (http://localhost:8080),需要加上项目名
  10. http://localhost:8080/crud
  11. --%>
  12. <%-- 引入 jquery --%>
  13. <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
  14. <%-- 引入样式 --%>
  15. <link rel="stylesheet" href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
  16. <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
  17. </head>
  18. <body>
  19. <div class="container">
  20. <!-- 标题 -->
  21. <!-- class="row" 为栅格系统的行 -->
  22. <div class="row">
  23. <!-- col-md-xx 数字代表列数 col-md-offset-xx 数字代表偏移-->
  24. <div class="col-md-12">
  25. <h1>SSM-CRUD</h1>
  26. </div>
  27. </div>
  28. <div class="row">
  29. <div class="col-md-4 col-md-offset-8">
  30. <button type="button" class="btn-primary">新建</button>
  31. <button type="button" class="btn-danger">删除</button>
  32. </div>
  33. </div>
  34. <!-- 显示表格数据 -->
  35. <div class="row">
  36. <div class="col-md-12">
  37. <!-- .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应。
  38. .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式。
  39. -->
  40. <table class="table table-hover table-striped">
  41. <tr>
  42. <th>#</th>
  43. <th>lastName</th>
  44. <th>email</th>
  45. <th>gender</th>
  46. <th>deptName</th>
  47. <th>操作</th>
  48. </tr>
  49. <c:forEach items="${pageInfo.list}" var="emp">
  50. <tr>
  51. <th>${emp.empId}</th>
  52. <th>${emp.empName}</th>
  53. <th>${emp.email}</th>
  54. <th>${emp.gender == 'M' ? '男' : '女'}</th>
  55. <th>${emp.department.deptName}</th>
  56. <th>
  57. <button class="btn btn-primary btn-sm">
  58. <!-- 铅笔图标 -->
  59. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
  60. 编辑
  61. </button>
  62. <button class="btn btn-danger btn-sm">
  63. <!-- 垃圾桶图标 -->
  64. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
  65. 删除
  66. </button>
  67. </th>
  68. </tr>
  69. </c:forEach>
  70. </table>
  71. </div>
  72. </div>
  73. </div>
  74. </body>
  75. </html>

查看效果

编写分页条

  1. <!-- 显示分页信息 -->
  2. <div class="row">
  3. <!-- 分页文字信息 -->
  4. <div class="col-md-6">
  5. 当前第 ${pageInfo.pageNum} 页,共有 ${pageInfo.pages} 页,总计 ${pageInfo.total} 条记录
  6. </div>
  7. <!-- 分页条信息 -->
  8. <div class="col-md-6">
  9. <nav aria-label="Page navigation">
  10. <ul class="pagination">
  11. <li><a href="${APP_PATH}/emps?pn=1">首页</a></li>
  12. <c:if test="${pageInfo.hasPreviousPage}">
  13. <li>
  14. <a href="${APP_PATH}/emps?pn=${pageInfo.prePage}" aria-label="Previous">
  15. <span aria-hidden="true">&laquo;</span>
  16. </a>
  17. </li>
  18. </c:if>
  19. <c:forEach items="${pageInfo.navigatepageNums}" var="page_Num">
  20. <c:if test="${page_Num == pageInfo.pageNum}">
  21. <li class="active"><a href="#">${page_Num}</a> </li>
  22. </c:if>
  23. <c:if test="${page_Num != pageInfo.pageNum}">
  24. <li><a href="${APP_PATH}/emps?pn=${page_Num}">${page_Num}</a></li>
  25. </c:if>
  26. </c:forEach>
  27. <li>
  28. <a href="#" aria-label="Next">
  29. <span aria-hidden="true">&raquo;</span>
  30. </a>
  31. </li>
  32. <li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">尾页</a></li>
  33. </ul>
  34. </nav>
  35. </div>
  36. </div>

查看效果

3、ajax

至此已经完成了基本的界面开发,但是目前的设计有着很大的缺陷,每次换页都需要重新加载整个网页。

由此引入 AJAX

AJAX = 异步 JavaScriptXML

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

基于 ajax 查询员工数据

  1. index.jsp 页面直接发送 ajax 请求
  2. 服务器将查处的数据,以 json 字符串的形式返回给浏览器
  3. 浏览器收到 json 字符串,可以使用 jsjson 进行解析,js 通过 dom 增删改改变页面
  4. 返回 json。实现客户端的无关性

(1)去除 index.jsp 中的 <jsp:forward> 标签,将 list.jsp 中的内容复制到 index.jsp

(2)删除 index.jsp 页面中带有从 EmployeeController.getEmps() 得到的 pageInfo 相关的标签

得到如下

  1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  3. <html>
  4. <head>
  5. <title>员工列表</title>
  6. <% pageContext.setAttribute("APP_PATH", request.getContextPath()); %>
  7. <%--
  8. 不以 / 开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
  9. / 开始的相对路径,找资源,以服务器的路径为标准 (http://localhost:8080),需要加上项目名
  10. http://localhost:8080/crud
  11. --%>
  12. <%-- 引入 jquery --%>
  13. <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
  14. <%-- 引入样式 --%>
  15. <link rel="stylesheet" href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
  16. <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
  17. </head>
  18. <body>
  19. <div class="container">
  20. <!-- 标题 -->
  21. <!-- class="row" 为栅格系统的行 -->
  22. <div class="row">
  23. <!-- col-md-xx 数字代表列数 col-md-offset-xx 数字代表偏移-->
  24. <div class="col-md-12">
  25. <h1>SSM-CRUD</h1>
  26. </div>
  27. </div>
  28. <div class="row">
  29. <div class="col-md-4 col-md-offset-8">
  30. <button type="button" class="btn-primary">新建</button>
  31. <button type="button" class="btn-danger">删除</button>
  32. </div>
  33. </div>
  34. <!-- 显示表格数据 -->
  35. <div class="row">
  36. <div class="col-md-12">
  37. <!-- .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应。
  38. .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式。
  39. -->
  40. <table class="table table-hover table-striped">
  41. <tr>
  42. <th>#</th>
  43. <th>lastName</th>
  44. <th>email</th>
  45. <th>gender</th>
  46. <th>deptName</th>
  47. <th>操作</th>
  48. </tr>
  49. </table>
  50. </div>
  51. </div>
  52. <!-- 显示分页信息 -->
  53. <div class="row">
  54. <!-- 分页文字信息 -->
  55. <div class="col-md-6">
  56. </div>
  57. <!-- 分页条信息 -->
  58. <div class="col-md-6">
  59. </div>
  60. </div>
  61. </div>
  62. </body>
  63. </html>

(3) EmployeeController 中添加返回 json 的映射请求

在浏览器中查看返回的 json 字符串

(4) 编写消息类

我们需要将返回的类封装到一个消息类中,以便获取更多的信息

com.study.crud.bean 中创建 Msg

  1. public class Msg {
  2. public static final int CODE_SUCCESS = 100;
  3. public static final int CODE_FAIL = 200;
  4. // 状态码
  5. private int code;
  6. // 提示信息
  7. private String msg;
  8. // 返回给浏览器的数据
  9. private Map<String, Object> extend = new HashMap<String, Object>();
  10. public static Msg success() {
  11. Msg msg = new Msg();
  12. msg.setCode(CODE_SUCCESS);
  13. msg.setMsg("处理成功");
  14. return msg;
  15. }
  16. public static Msg fail() {
  17. Msg msg = new Msg();
  18. msg.setCode(CODE_FAIL);
  19. msg.setMsg("处理失败");
  20. return msg;
  21. }
  22. // 向 Msg 中添加数据
  23. public Msg add(String key, Object value) {
  24. this.extend.put(key, value);
  25. return this;
  26. }
  27. public int getCode() {
  28. return code;
  29. }
  30. public void setCode(int code) {
  31. this.code = code;
  32. }
  33. public String getMsg() {
  34. return msg;
  35. }
  36. public void setMsg(String msg) {
  37. this.msg = msg;
  38. }
  39. public Map<String, Object> getExtend() {
  40. return extend;
  41. }
  42. public void setExtend(Map<String, Object> extend) {
  43. this.extend = extend;
  44. }
  45. }

改写 getEmpsWithJson()

查看改写后的映射请求返回的数据

(4) **编写 js **

添加 id 值

添加 js

  1. <script type="text/javascript">
  2. var lastPage, currentPage, totalRecord;
  3. // 1、页面加载完成以后,直接去发送一个 ajax 请求,要到分页数据
  4. $(function () {
  5. // 去首页
  6. to_page(1);
  7. });
  8. function to_page(pn) {
  9. $.ajax({
  10. url:"${APP_PATH}/emps",
  11. data:"pn=" + pn,
  12. type:"get",
  13. success:function (result) {
  14. // console.log(result);
  15. // 1、解析并显示员工数据
  16. build_emps_table(result);
  17. // 2、解析并显示分页信息
  18. build_page_info(result);
  19. // 3、解析显示分页条数据
  20. build_page_nav(result);
  21. }
  22. });
  23. }
  24. function build_emps_table(result) {
  25. // 清空表格
  26. $("#emps_table tbody").empty();
  27. var emps = result.extend.pageInfo.list;
  28. $.each(emps, function (index, item) {
  29. var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
  30. var empIdTd = $("<td></td>").append(item.empId);
  31. var empNameTd = $("<td></td>").append(item.empName);
  32. var gender = item.gender == 'M' ? '男' : '女';
  33. var genderTd = $("<td></td>").append(gender);
  34. var emailTd = $("<td></td>").append(item.email);
  35. var deptNameTd = $("<td></td>").append(item.department.deptName);
  36. /**
  37. * <button class="btn btn-primary btn-sm">
  38. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
  39. 编辑
  40. </button>
  41. */
  42. var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn")
  43. .append($("<span></span>")).addClass("glyphicon glyphicon-pencil").append("编辑");
  44. editBtn.attr("edit-id", item.empId);
  45. var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
  46. .append($("<span></span>")).addClass("glyphicon glyphicon-trash").append("删除");
  47. deleteBtn.attr("del-id", item.empId);
  48. var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
  49. // append 方法执行完成以后还是返回原来的元素 所以可以链式操作
  50. $("<tr></tr>").append(checkBoxTd)
  51. .append(empIdTd)
  52. .append(empNameTd)
  53. .append(genderTd)
  54. .append(emailTd)
  55. .append(deptNameTd)
  56. .append(btnTd)
  57. .appendTo("#emps_table tbody");
  58. })
  59. }
  60. function build_page_info(result) {
  61. $("#page_info_area").empty();
  62. var pageInfo = result.extend.pageInfo;
  63. $("#page_info_area").append("当前 " + pageInfo.pageNum + " 页,"
  64. + "总 " + pageInfo.pages + " 页,"
  65. + "总 " + pageInfo.total + " 条记录"
  66. );
  67. lastPage = pageInfo.pages;
  68. totalRecord= pageInfo.total;
  69. currentPage = pageInfo.pageNum;
  70. }
  71. function build_page_nav(result) {
  72. $("#page_nav_area").empty();
  73. var pageInfo = result.extend.pageInfo;
  74. var ul = $("<ul></ul>").addClass("pagination");
  75. var firstPageLi = $("<li></li>").append($("<a></a>").append("首页"));
  76. var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;"));
  77. if (pageInfo.hasPreviousPage == false) {
  78. firstPageLi.addClass("disabled");
  79. prePageLi.addClass("disabled");
  80. } else {
  81. firstPageLi.click(function () {
  82. to_page(1);
  83. });
  84. prePageLi.click(function () {
  85. to_page(pageInfo.pageNum - 1);
  86. });
  87. }
  88. ul.append(firstPageLi).append(prePageLi);
  89. $.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
  90. var numLi = $("<li></li>").append($("<a></a>").append(item));
  91. if (pageInfo.pageNum == item) {
  92. numLi.addClass("active");
  93. }
  94. numLi.click(function () {
  95. to_page(item);
  96. });
  97. ul.append(numLi);
  98. });
  99. var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
  100. var lastPageLi = $("<li></li>").append($("<a></a>").append("尾页"));
  101. if (pageInfo.hasNextPage == false) {
  102. nextPageLi.addClass("disabled");
  103. lastPageLi.addClass("disabled");
  104. } else {
  105. nextPageLi.click(function () {
  106. to_page(pageInfo.pageNum + 1);
  107. });
  108. lastPageLi.click(function () {
  109. to_page(pageInfo.pages);
  110. });
  111. }
  112. ul.append(nextPageLi).append(lastPageLi);
  113. var navEle = $("<nav></nav>").append(ul);
  114. navEle.appendTo("#page_nav_area");
  115. }
  116. </script>

查看结果

4、业务逻辑

(1)新增员工信息

添加 员工添加的模态框

  1. <!-- 员工添加的模态框 -->
  2. <div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  3. <div class="modal-dialog" role="document">
  4. <div class="modal-content">
  5. <div class="modal-header">
  6. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  7. <h4 class="modal-title" id="myModalLabel">员工添加</h4>
  8. </div>
  9. <div class="modal-body">
  10. <form class="form-horizontal">
  11. <div class="form-group">
  12. <label class="col-sm-2 control-label">empName</label>
  13. <div class="col-sm-10">
  14. <input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
  15. <span class="help-block"></span>
  16. </div>
  17. </div>
  18. <div class="form-group">
  19. <label class="col-sm-2 control-label">email</label>
  20. <div class="col-sm-10">
  21. <input type="text" name="email" class="form-control" id="email_add_input" placeholder="email@atguigu.com">
  22. <span class="help-block"></span>
  23. </div>
  24. </div>
  25. <div class="form-group">
  26. <label class="col-sm-2 control-label">gender</label>
  27. <div class="col-sm-10">
  28. <label class="radio-inline">
  29. <input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked">
  30. </label>
  31. <label class="radio-inline">
  32. <input type="radio" name="gender" id="gender2_add_input" value="F">
  33. </label>
  34. </div>
  35. </div>
  36. <div class="form-group">
  37. <label class="col-sm-2 control-label">deptName</label>
  38. <div class="col-sm-4">
  39. <!-- 部门提交部门id即可 -->
  40. <select class="form-control" name="dId">
  41. </select>
  42. </div>
  43. </div>
  44. </form>
  45. </div>
  46. <div class="modal-footer">
  47. <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
  48. <button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
  49. </div>
  50. </div>
  51. </div>
  52. </div>

新建按钮处添加 id

编写 js

  1. //清空表单样式及内容
  2. function reset_form(ele) {
  3. $(ele)[0].reset();
  4. //清空表单样式
  5. $(ele).find("*").removeClass("has-error has-success");
  6. $(ele).find(".help-block").text("");
  7. }
  8. function getDepts(ele) {
  9. // 清空之前下拉列表的值
  10. $(ele).empty();
  11. $.ajax({
  12. url: "${APP_PATH}/depts",
  13. type: "get",
  14. success:function (result) {
  15. //{"code":100,"msg":"处理成功!",
  16. //"extend":{"depts":[{"deptId":1,"deptName":"开发部"},{"deptId":2,"deptName":"测试部"}]}}
  17. //console.log(result);
  18. //显示部门信息在下拉列表中
  19. //$("#empAddModal select").append("")
  20. $.each(result.extend.depts,function(){
  21. var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId);
  22. optionEle.appendTo(ele);
  23. });
  24. }
  25. });
  26. }
  27. // 点击新增按钮弹出模态框。
  28. $("#emp_add_modal_btn").click(function () {
  29. //清除表单数据(表单完整重置(表单的数据,表单的样式))
  30. reset_form("#empAddModal form");
  31. //s$("")[0].reset();
  32. //发送ajax请求,查出部门信息,显示在下拉列表中
  33. getDepts("#empAddModal select");
  34. //弹出模态框
  35. $("#empAddModal").modal({
  36. backdrop:"static"
  37. });
  38. });

查看 添加模态框

创建 DepartmentController 映射 getDepts 请求

  1. @Controller
  2. public class DepartmentController {
  3. @Autowired
  4. DepartmentService departmentService;
  5. @RequestMapping("/depts")
  6. @ResponseBody
  7. public Msg getDeptsWithJson() {
  8. List<Department> depts = departmentService.getDepts();
  9. return Msg.success().add("depts", depts);
  10. }
  11. }
  12. @Service
  13. public class DepartmentService {
  14. @Autowired
  15. DepartmentMapper departmentMapper;
  16. public List<Department> getDepts() {
  17. return departmentMapper.selectByExample(null);
  18. }
  19. }

查看是否显示部门信息

(2)数据校验

**js校验 **

  1. // 检验表单数据
  2. function validate_add_form() {
  3. var empName = $("#empName_add_input").val();
  4. var regName = /(^[a-zA-Z0-9]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
  5. if (!regName.test(empName)) {
  6. show_validate_msg("#empName_add_input", "error", "用户名可以是 2-5 位中文或者 6-16 位英文和数字的组合");
  7. return false;
  8. } else {
  9. show_validate_msg("#empName_add_input", "success", "");
  10. }
  11. var email = $("#email_add_input").val();
  12. var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
  13. if (!regEmail.test(email)) {
  14. show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
  15. return false;
  16. } else {
  17. show_validate_msg("#email_add_input", "success", "");
  18. }
  19. return true;
  20. }
  21. // 显示校验结果的提示信息
  22. function show_validate_msg(ele, status, msg) {
  23. $(ele).parent().removeClass("has-success has-error");
  24. $(ele).next("span").text("");
  25. if ("success" == status) {
  26. $(ele).parent().addClass("has-success");
  27. $(ele).next("span").text(msg);
  28. } else {
  29. $(ele).parent().addClass("has-error");
  30. $(ele).next("span").text(msg);
  31. }
  32. }
  33. // 校验用户名是否可用
  34. $("#empName_add_input").change(function () {
  35. var empName = this.value;
  36. $.ajax({
  37. url:"${APP_PATH}/checkuser",
  38. data:"empName="+empName,
  39. type:"post",
  40. success:function (result) {
  41. if (result.code == 100) {
  42. show_validate_msg("#empName_add_input", "success", "用户名可用");
  43. $("emp_save_btn").attr("ajax-va", "success");
  44. } else {
  45. show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
  46. $("emp_save_btn").attr("ajax-va", "error");
  47. }
  48. }
  49. });
  50. });

EmployeeController 中添加检验用户名映射请求

  1. // EmployeeController
  2. @RequestMapping("/checkuser")
  3. @ResponseBody
  4. public Msg checkuser(@RequestParam("empName") String empName) {
  5. String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})";
  6. if (!empName.matches(regx)) {
  7. return Msg.fail().add("va_msg", "用户名必须是 6-16 位数字和字母的组合或者 2-5 位中文");
  8. }
  9. boolean b = employeeService.checkUser(empName);
  10. if (b) {
  11. return Msg.success();
  12. } else {
  13. return Msg.fail().add("va_msg", "用户名已存在");
  14. }
  15. }

EmployeeService 中添加检验方法

  1. public boolean checkUser(String empName) {
  2. EmployeeExample example = new EmployeeExample();
  3. EmployeeExample.Criteria criteria = example.createCriteria();
  4. criteria.andEmpNameEqualTo(empName);
  5. long count = employeeMapper.countByExample(example);
  6. return count == 0;
  7. }

查看校验结果


(3) 保存员工

添加 js

  1. // 点击保存,保存员工
  2. $("#emp_save_btn").click(function () {
  3. // 1、模态框中填写的数据提交给服务器进行保存
  4. // 1、先对要提交给服务器的数据进行校验
  5. if (!validate_add_form()) {
  6. return false;
  7. }
  8. // 1、判断之前的 ajax 用户名校验是否成功
  9. if ($(this).attr("ajax-va") == "error") {
  10. return false;
  11. }
  12. // 2、发送 ajax 请求保存员工
  13. $.ajax({
  14. url:"${APP_PATH}/emp",
  15. type:"post",
  16. data:$("#empAddModal form").serialize(),
  17. success:function(result) {
  18. if (result.code == 100) {
  19. // 员工保存成功
  20. // 1、关闭模态框
  21. $("#empAddModal").modal("hide");
  22. // 2、来到最后一页,显示刚才保存的数据
  23. if (totalRecord % 5 == 0) {
  24. lastPage++;
  25. currentPage = lastPage;
  26. }
  27. totalRecord++;
  28. to_page(lastPage);
  29. } else {
  30. // 显示失败信息
  31. if (undefined != result.extend.errorFields.email) {
  32. // 显示邮箱错误信息
  33. show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
  34. }
  35. if (undefined != result.extend.errorFields.empName) {
  36. // 显示员工名字的错误信息
  37. show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
  38. }
  39. }
  40. }
  41. });
  42. });

Employee 中使用JSR303 数据校验

EmployeeController 中添加保存员工的映射请求

  1. @RequestMapping(value = "/emp", method = RequestMethod.POST)
  2. @ResponseBody
  3. public Msg saveEmp(@Valid Employee employee, BindingResult result) {
  4. if (result.hasErrors()) {
  5. Map<String, Object> map = new HashMap<String, Object>();
  6. List<FieldError> errors = result.getFieldErrors();
  7. for (FieldError fieldError : errors) {
  8. System.out.println("错误的字段名:" + fieldError.getField());
  9. System.out.println("错误信息:" + fieldError.getDefaultMessage());
  10. map.put(fieldError.getField(), fieldError.getDefaultMessage());
  11. }
  12. return Msg.fail().add("errorFields", map);
  13. } else {
  14. employeeService.saveEmp(employee);
  15. return Msg.success();
  16. }
  17. }

EmployeeService 中添加保存员工的方法

  1. public void saveEmp(Employee employee) {
  2. employeeMapper.insertSelective(employee);
  3. }


(4) 修改员工信息

添加员工修改模态框

  1. <!-- 员工修改的模态框 -->
  2. <div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  3. <div class="modal-dialog" role="document">
  4. <div class="modal-content">
  5. <div class="modal-header">
  6. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  7. <h4 class="modal-title">员工修改</h4>
  8. </div>
  9. <div class="modal-body">
  10. <form class="form-horizontal">
  11. <div class="form-group">
  12. <label class="col-sm-2 control-label">empName</label>
  13. <div class="col-sm-10">
  14. <p class="form-control-static" id="empName_update_static"></p>
  15. </div>
  16. </div>
  17. <div class="form-group">
  18. <label class="col-sm-2 control-label">email</label>
  19. <div class="col-sm-10">
  20. <input type="text" name="email" class="form-control" id="email_update_input" placeholder="email@atguigu.com">
  21. <span class="help-block"></span>
  22. </div>
  23. </div>
  24. <div class="form-group">
  25. <label class="col-sm-2 control-label">gender</label>
  26. <div class="col-sm-10">
  27. <label class="radio-inline">
  28. <input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked">
  29. </label>
  30. <label class="radio-inline">
  31. <input type="radio" name="gender" id="gender2_update_input" value="F">
  32. </label>
  33. </div>
  34. </div>
  35. <div class="form-group">
  36. <label class="col-sm-2 control-label">deptName</label>
  37. <div class="col-sm-4">
  38. <!-- 部门提交部门id即可 -->
  39. <select class="form-control" name="dId">
  40. </select>
  41. </div>
  42. </div>
  43. </form>
  44. </div>
  45. <div class="modal-footer">
  46. <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
  47. <button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
  48. </div>
  49. </div>
  50. </div>
  51. </div>

添加 js

  1. // 1、如果在编辑和删除按钮创建之前绑定 click 是绑定不上的
  2. // 1)可以在创建按钮的时候绑定
  3. // 2)绑定点击 .live()
  4. $(document).on("click", ".edit_btn", function () {
  5. // 1、查处部门信息,并显示部门列表
  6. getDepts("#empUpdateModal select");
  7. // 2、查处员工信息,显示员工信息
  8. getEmp($(this).attr("edit-id"));
  9. // 3、把员工的 id 传递给模态框的更新按钮
  10. $("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
  11. $("#empUpdateModal").modal({
  12. backdrop: "static"
  13. });
  14. });
  15. function getEmp(id) {
  16. $.ajax({
  17. url:"${APP_PATH}/emp/" + id,
  18. type:"get",
  19. success:function (result) {
  20. var empData = result.extend.emp;
  21. $("#empName_update_static").text(empData.empName);
  22. $("#email_update_input").val(empData.email);
  23. $("#empUpdateModal input[name=gender]").val([empData.gender]);
  24. $("#empUpdateModal select").val([empData.dId]);
  25. }
  26. });
  27. }
  28. // 点击更新,更新员工信息
  29. $("#emp_update_btn").click(function () {
  30. // 验证邮箱是否合法
  31. // 1、校验邮箱信息
  32. var email = $("#email_update_input").val();
  33. var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
  34. if (!regEmail.test(email)) {
  35. show_validate_msg("#email_update_input", "error", "邮箱格式不正确");
  36. return false;
  37. } else {
  38. show_validate_msg("#email_update_input", "success", "");
  39. }
  40. // 2、发送 ajax 请求保存更新的员工数据
  41. $.ajax({
  42. url:"${APP_PATH}/emp/" + $(this).attr("edit-id"),
  43. type:"put",
  44. data:$("#empUpdateModal form").serialize(),
  45. success:function (result) {
  46. $("#empUpdateModal").modal("hide");
  47. to_page(currentPage);
  48. }
  49. });
  50. });

EmployeeController 中添加按 id 获取员工的映射请求 和 更新员工的请求

  1. @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
  2. @ResponseBody
  3. public Msg getEmp(@PathVariable("id") Integer id) {
  4. Employee employee = employeeService.getEmp(id);
  5. return Msg.success().add("emp", employee);
  6. }
  7. @RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
  8. @ResponseBody
  9. public Msg updateEmp(Employee employee, HttpServletRequest request) {
  10. employeeService.updateEmp(employee);
  11. return Msg.success();
  12. }

EmployeeService 中添加 getEmp 方法和 update 方法

  1. public Employee getEmp(Integer id) {
  2. return employeeMapper.selectByPrimaryKeyWithDept(id);
  3. }
  4. public void updateEmp(Employee employee) {
  5. employeeMapper.updateByPrimaryKeySelective(employee);
  6. }

查看效果

(5) 添加全选功能

添加全选按钮

添加 js

  1. // 完成全选、全不选功能
  2. $("#check_all").click(function () {
  3. $(".check_item").prop("checked", $(this).prop("checked"));
  4. });
  5. $(document).on("click", ".check_item", function () {
  6. var flag = $(".check_item:checked").length == $(".check_item").length;
  7. $("#check_all").prop("checked", flag);
  8. });

添加删除功能

给删除按键添加 id

添加 js

  1. // 单个删除
  2. $(document).on("click", ".delete_btn", function () {
  3. var empName = $(this).parents("tr").find("td:eq(2)").text();
  4. var empId = $(this).attr("del-id");
  5. // 弹出是否确认删除对话框
  6. if (confirm("确认删除【" + empName + "】吗?")) {
  7. $.ajax({
  8. url:"${APP_PATH}/emp/" + empId,
  9. type:"delete",
  10. success:function (result) {
  11. alert(result.msg);
  12. to_page(1);
  13. }
  14. });
  15. }
  16. });
  17. // 点击全部删除、就批量删除
  18. $("#emp_delete_all_btn").click(function () {
  19. var empNames = "";
  20. var del_ids = "";
  21. $.each($(".check_item:checked"), function () {
  22. empNames += $(this).parents("tr").find("td:eq(2)").text() + ",";
  23. del_ids += $(this).parents("tr").find("td:eq(1)").text() + "-";
  24. });
  25. empNames = empNames.substring(0, empNames.length - 1);
  26. del_ids = del_ids.substring(0, del_ids.length - 1);
  27. if (confirm("确认删除【" + empNames + "】吗?")) {
  28. $.ajax({
  29. url:"${APP_PATH}/emp/" + del_ids,
  30. type:"delete",
  31. success:function (result) {
  32. alert(result.msg);
  33. to_page(1);
  34. }
  35. });
  36. }
  37. });

EmployeeController 中添加删除方法

  1. @RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
  2. @ResponseBody
  3. public Msg deleteEmp(@PathVariable("ids") String ids) {
  4. // 批量删除
  5. if (ids.contains("-")) {
  6. List<Integer> del_ids = new ArrayList<Integer>();
  7. String[] str_ids = ids.split("-");
  8. for (String str : str_ids) {
  9. del_ids.add(Integer.parseInt(str));
  10. }
  11. employeeService.deleteBatch(del_ids);
  12. } else {
  13. Integer id = Integer.parseInt(ids);
  14. employeeService.deleteEmp(id);
  15. }
  16. return Msg.success();
  17. }

EmployeeService中添加单个删除和多个删除的方法

  1. public void deleteBatch(List<Integer> del_ids) {
  2. EmployeeExample example = new EmployeeExample();
  3. EmployeeExample.Criteria criteria = example.createCriteria();
  4. criteria.andEmpIdIn(del_ids);
  5. employeeMapper.deleteByExample(example);
  6. }
  7. public void deleteEmp(Integer id) {
  8. employeeMapper.deleteByPrimaryKey(id);
  9. }

查看效果



四、总结

SSM-员工管理项目实战-CRUD-增删改查的更多相关文章

  1. 使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序

    使用ASP.NET Core MVC 和 Entity Framework Core 开发一个CRUD(增删改查)的应用程序 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻 ...

  2. django之创建第8-1个项目-数据库之增删改查/数据库数据显示在html页面

    1.为test.DB数据库预先创建下面数据 1    张三    16    2015-01-02    12    李四    17    2015-01-04    13    王五    14  ...

  3. 第二百七十六节,MySQL数据库,【显示、创建、选定、删除数据库】,【用户管理、对用户增删改查以及授权】

    MySQL数据库,[显示.创建.选定.删除数据库],[用户管理.对用户增删改查以及授权] 1.显示数据库 SHOW DATABASES;显示数据库 SHOW DATABASES; mysql - 用户 ...

  4. 前端的CRUD增删改查的小例子

    前端的CRUD增删改查的小例子 1.效果演示 2.相关代码: <!DOCTYPE html> <html lang="en"> <head> & ...

  5. yii2-basic后台管理功能开发之二:创建CRUD增删改查

    昨天实现了后台模板的嵌套,今天我们可以试着创建CRUD模型啦 刚开始的应该都是“套用”,不再打算细说,只把关键的地方指出来. CRUD即数据库增删改查操作.可以理解为yii2为我们做了一个组件,来实现 ...

  6. 创建支持CRUD(增删改查)操作的Web API(二)

    一:准备工作 你可以直接下载源码查看 Download the completed project.     下载完整的项目 CRUD是指“创建(C).读取(R).更新(U)和删除(D)”,它们是四个 ...

  7. 【EF6学习笔记】(二)操练 CRUD 增删改查

    本篇原文链接: Implementing Basic CRUD Functionality 说明:学习笔记参考原文中的流程,为了增加实际操作性,并能够深入理解,部分地方根据实际情况做了一些调整:并且根 ...

  8. EF6 学习笔记(二):操练 CRUD 增删改查

    EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...

  9. SSM框架入门——整合SSM并实现对数据的增删改查功能(Eclipse平台)

    一.搭建框架环境 整个项目结构如下: 搭建SSM步骤如下: (1)准备好三大框架的jar包,如图所示 (2)在Eclipse中创建一个web project ,并把这些jar包粘贴到lib文件夹中. ...

  10. MybatisPlus核心功能——实现CRUD增删改查操作 (包含条件构造器)

    CRUD 官方文档:https://baomidou.com/ (建议多看看官方文档,每种功能里面都有讲解)[本文章使用的mybatisplus版本为3.5.2] 条件构造器 一般都是用service ...

随机推荐

  1. HBuilderX All In One

    HBuilderX All In One uni-app https://uniapp.dcloud.io/quickstart-hx 目录结构 一个uni-app工程,默认包含如下目录及文件: $ ...

  2. Web 开发之 HTTP/2 & SPDY & HTTP 1.1 & HTTP 对比分析详解!

    1 https://zh.wikipedia.org/wiki/HTTP/2 HTTP/2 维基百科,自由的百科全书                         HTTP/2(超文本传输协议第2版 ...

  3. React Transforming Elements All In One

    React Transforming Elements All In One https://reactjs.org/docs/react-api.html#transforming-elements ...

  4. node.js 中间件

    node.js 中间件 node.js middleware Express middleware body-parser cookie-parser cookie-session cors csur ...

  5. GitHub 500 error

    GitHub 500 error 无法访问了, GitHub 挂了又! error reports Downdetector Github down? Current service status a ...

  6. react-parent-child-lifecycle-order

    react-parent-child-lifecycle-order react parent child lifecycle order live demo https://33qrr.csb.ap ...

  7. js currying & js 科里化

    js currying & js 科里化 var test = ( function (a){ console.log(`a2 =`, a);// 1 // console.log(`b2 = ...

  8. PAUL ADAMS ARCHITECT:薪资追不上房价美一半家庭难买房

    尽管上一年度美国经济遭受重创,但美国房价依旧持续蹿扬,据最新调查显示,美国大部分地区的房价已经到了一般家庭无法负担的水准. 美国房价上涨持续强劲,主要受益美国人居家办公需求(受大环境影响,目前美国有7 ...

  9. 炒币亏损一万美金?不如抢SPC空投!

    币圈的市场可以用风云变幻来形容,1月9日的时候比特币震荡,其他币种争先上涨,连平时都不涨的币种都拉出了10%-20%的领先涨幅,市场惊呼牛市来了,但喜悦还没有维持一天,1月10日(昨天)市场就走向另一 ...

  10. 19_MySQL表的内连接

    本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...