zoukankan      html  css  js  c++  java
  • SSM-员工管理项目实战-CRUD-增删改查

    SSM-CRUD

    一、项目简介

    主界面演示

    截屏2021-03-27 14.15.06

    功能点

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

    技术点

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

    二、基础环境搭建

    1、创建 Maven 工程 ssm_crud_study

    截屏2021-03-27 14.20.09

    3、添加 web 框架

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

    截屏2021-03-27 14.35.46

    (2)选择 Web Application

    截屏2021-03-27 14.36.50

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

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

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.chen</groupId>
        <artifactId>ssm-crud</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <!--  pagehelper 分页插件      -->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper</artifactId>
                <version>5.0.0</version>
            </dependency>
    
            <!--   MBG     -->
            <dependency>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-core</artifactId>
                <version>1.3.5</version>
            </dependency>
            
            <!-- Spring MVC -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>4.3.7.RELEASE</version>
            </dependency>
    
            <!--  返回 json 字符串的支持 -->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.8.8</version>
            </dependency>
    
            <!--  JS303 数据校验支持      -->
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>5.4.1.Final</version>
            </dependency>
            
            <!-- Spring Jdbc -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>4.3.7.RELEASE</version>
            </dependency>
    
            <!--  Spring Test      -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.3.7.RELEASE</version>
                <scope>test</scope>
            </dependency>
    
            <!-- 面向切面编程 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>4.3.7.RELEASE</version>
            </dependency>
    
            <!-- Mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.2</version>
            </dependency>
    
            <!-- MyBatis 适配包 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.1</version>
            </dependency>
    
            <!-- 数据库连接池 -->
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.2</version>
            </dependency>
    
            <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.21</version>
            </dependency>
    
            <!-- jstl -->
            <dependency>
                <groupId>jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
    
            <!-- servlet-api -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.0.1</version>
                <scope>provided</scope>
            </dependency>
            
            <!-- junit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.0</version>
                <scope>provided</scope>
            </dependency>
            
        </dependencies>
        
    </project>
    

    4、引入 bootstrap 前端框架

    (1)前往 bootstrap 官网下载

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

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

    截屏2021-03-27 20.12.03

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

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

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

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

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

    (1)配置 web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
    
        <!--  1、启动  Spring 的容器 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <!-- 2、配置 SpringMVC 前端控制器
            默认会加载 WEB-INF 下的 <servletName>-servlet.xml 配置文件
            即 dispatcherServlet-servlet.xml
        -->
        <servlet>
            <servlet-name>dispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!-- 3、字符编码过滤器,一定要放在所有过滤器之前  -->
        <filter>
            <filter-name>characterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>utf-8</param-value>
            </init-param>
            <init-param>
                <param-name>forceRequestEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <param-name>forceResponseEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>characterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- 4、使用 Rest 风格的 URI,将页面普通的 post 请求转为指定的 delete 或者 put 请求  -->
        <filter>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>httpPutFormContentFilter</filter-name>
            <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>httpPutFormContentFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

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

    截屏2021-03-27 15.01.57

    (2)配置 springmvc 配置文件

    WEB-INF 下加入 dispatcherServlet-servlet.xml

    截屏2021-03-27 15.14.19

    src/main/java 创建包结构

    截屏2021-03-27 15.17.27

    **配置 dispatcherServlet-servlet.xml **

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

    (3) 配置 spring 配置文件

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

    src/main/resources 下加入 dbconfig.properties

    截屏2021-03-27 15.23.43

    dbconfig.properties

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

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

    截屏2021-03-27 15.27.41

    配置 applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    
           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">
    
        <context:component-scan base-package="com.chen">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
        
        <!--  Spring 的配置文件,主要配置与业务逻辑相关的文件 -->
        <!--  数据源、事务控制 ...  -->
        <context:property-placeholder location="classpath:dbconfig.properties"/>
        
        <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
            <property name="driverClass" value="${jdbc.driverClass}"/>
            <property name="user" value="${jdbc.user}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
    
        <!--  ================================ 配置和 MyBatis 的整合 =============================== -->
        <bean id="sqlSessionFactoryBean"  class="org.mybatis.spring.SqlSessionFactoryBean">
            <!--    指定 MyBatis 全局配置文件的位置    -->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="dataSource" ref="pooledDataSource"/>
            <!--   指定 MyBatis mapper 文件的位置     -->
            <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        </bean>
    
        <!--  配置一个执行批量的 sqlSession  -->
        <bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
            <constructor-arg name="executorType" value="BATCH"/>
        </bean>
    
        <!--  配置扫描器,将 MyBatis 接口的实现加入到 ioc 容器中  -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!--   扫描所有 dao 接口的实现,加到 ioc 容器中     -->
            <property name="sqlSessionTemplateBeanName" value="sessionTemplate"/>
            <property name="basePackage" value="com.study"/>
        </bean>
    
        <!--  事务控制的配置  -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--  控制住数据源      -->
            <property name="dataSource" ref="pooledDataSource"/>
        </bean>
    
        <!--  开启基于注解的事务,使用 xml 配置形式的事务(必要主要的都是使用配置式)  -->
        <aop:config>
            <!--  切入点表达式      -->
            <aop:pointcut id="txPoint" expression="execution(* com.chen.crud.service..*(..))"/>
            <!--  配置事务增强      -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
        </aop:config>
    
        <!--  配置事务增强,事务如何切入  -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!--  所有方法都是事务方法          -->
                <tx:method name="*"/>
                <!--  以 get 开始的所有方法          -->
                <tx:method name="get*" read-only="true"/>
            </tx:attributes>
        </tx:advice>
    </beans>
    

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

    截屏2021-03-27 15.29.06

    (4)配置 mybatis 文件

    mybatis-config.xml

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

    6、创建数据库

    CREATE DATABASE ssm_crud_study;
    
    CREATE TABLE `ssm_crud_study`.`tbl_emp` (
      `emp_id` INT NOT NULL AUTO_INCREMENT,
      `emp_name` VARCHAR(255) NOT NULL,
      `gender` CHAR(1) NULL,
      `email` VARCHAR(255) NULL,
      `d_id` INT NULL,
      PRIMARY KEY (`emp_id`));
      
    CREATE TABLE `ssm_crud_study`.`tbl_dept` (
      `dept_id` INT NOT NULL,
      `dept_name` VARCHAR(255) NOT NULL,
      PRIMARY KEY (`dept_id`));
    
    ALTER TABLE `ssm_crud_study`.`tbl_emp` 
    ADD INDEX `dept_id_idx` (`d_id` ASC) VISIBLE;
    ;
    ALTER TABLE `ssm_crud_study`.`tbl_emp` 
    ADD CONSTRAINT `dept_id`
      FOREIGN KEY (`d_id`)
      REFERENCES `ssm_crud_study`.`tbl_dept` (`dept_id`)
      ON DELETE NO ACTION
      ON UPDATE NO ACTION;
    
    截屏2021-03-27 15.48.58

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

    在工程中添加 mbg.xml

    截屏2021-03-27 15.53.16

    配置 mbg.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
    
        <context id="DB2Tables" targetRuntime="MyBatis3">
            <commentGenerator>
                <!-- 去除生成的 bean、mapper 中的注释 -->
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
    
            <!--  配置数据库连接      -->
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/ssm_crud_study?useUnicode=true&amp;characterEncoding=utf8"
                            userId="root"
                            password="root">
            </jdbcConnection>
    
            <javaTypeResolver >
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
    
            <!--   指定 javaBean 生成的位置     -->
            <javaModelGenerator targetPackage="com.study.crud.bean" targetProject="src/main/java">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
    
            <!--   指定 sql 映射文件生成的位置     -->
            <sqlMapGenerator targetPackage="mapper"  targetProject="src/main/resources">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>
    
            <!--   指定 dao 接口生成的位置     -->
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.study.crud.dao"  targetProject="src/main/java">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
    
            <!--  table 指定每个表的生成策略      -->
            <table tableName="tbl_emp" domainObjectName="Employee">
    
            </table>
            <table tableName="tbl_dept" domainObjectName="Department"></table>
    
        </context>
    </generatorConfiguration>
    
    

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

    截屏2021-03-27 16.00.24
    public class MBGTest {
    
        public static void main(String[] args) throws Exception {
            List<String> warnings = new ArrayList<String>();
            boolean overwrite = true;
            File configFile = new File("mbg.xml");
            ConfigurationParser cp = new ConfigurationParser(warnings);
            Configuration config = cp.parseConfiguration(configFile);
            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
        }
    }
    

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

    截屏2021-03-27 16.05.47

    8、测试 mapper

    在数据库中添加数据

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

    src/test/java 创建 MapperTest

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

    截屏2021-03-27 16.24.57

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

    截屏2021-03-27 16.28.48

    向数据库中插入 1000 条数据

    // 使用 Spring Test
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
    public class MapperTest {
    
        @Autowired
        DepartmentMapper departmentMapper;
    
        // 可以执行批量操作的 sqlSession
        @Autowired
        SqlSession sqlSession;
    
        @Test
        public void testCRUD() {
    //        System.out.println(departmentMapper);
    //        Department department = departmentMapper.selectByPrimaryKey(1);
    //        System.out.println("dept_id=" + department.getDeptId() + ",dept_name=" + department.getDeptName());
    
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            for (int i = 0; i < 1000; i++) {
                // 使用 UUID 工具类,随机生成用户名
                String empName = UUID.randomUUID().toString().substring(0, 5);
                // 需要在 Employee 中添加有参构造,!!!添加有参构造后必须添加无参构造 !!!
                mapper.insertSelective(new Employee(null, empName, "M", empName + "@qq.com", 1));
            }
        }
    }
    
    截屏2021-03-27 17.23.27

    三、CRUD开发

    1、index.jsp

    流程

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

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

    截屏2021-03-27 19.09.13

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

    截屏2021-03-27 19.11.16

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

    截屏2021-03-27 19.12.51

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

    截屏2021-03-27 19.14.09

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

    截屏2021-03-27 19.20.24 截屏2021-03-27 19.45.13

    EmployeeMapper.xml 中添加 SQL

    <resultMap id="WithDeptResultMap" type="com.study.crud.bean.Employee">
        <id column="emp_id" jdbcType="INTEGER" property="empId" />
        <result column="emp_name" jdbcType="VARCHAR" property="empName" />
        <result column="gender" jdbcType="CHAR" property="gender" />
        <result column="email" jdbcType="VARCHAR" property="email" />
        <result column="d_id" jdbcType="INTEGER" property="dId" />
        <association property="department" javaType="com.study.crud.bean.Department">
            <id column="dept_id" property="deptId"/>
            <result column="dept_name" property="deptName"/>
        </association>
    </resultMap>
    
    <sql id="WithDept_Column_List">
    e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
    </sql>
    
    <!--  List<Employee> selectByExampleWithDept(EmployeeExample example);
    Employee selectByPrimaryKeyWithDept(Integer empId);-->
    <select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="WithDept_Column_List" />
    FROM tbl_emp e
    LEFT JOIN tbl_dept d ON e.d_id = d.dept_id
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
    </select>
    <select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
    select
    <include refid="WithDept_Column_List" />
    FROM tbl_emp e
    LEFT JOIN tbl_dept d ON e.d_id = d.dept_id
    where emp_id = #{empId,jdbcType=INTEGER}
    </select>
    

    EmployeeService 中添加 getAll() 方法

    截屏2021-03-27 19.29.22

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

    截屏2021-03-27 19.30.59

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

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

    测试结果

    截屏2021-03-27 19.48.05

    2、list.jsp

    /static 下加入 jquery

    截屏2021-03-27 20.10.57

    list.jsp 中引入 bootstrap、jquery

    截屏2021-03-27 19.52.28

    前往 Bootstrap 官网,查看文档

    截屏2021-03-27 19.59.01

    截屏2021-03-27 19.56.34 截屏2021-03-27 19.57.09

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

    截屏2021-03-27 20.13.27

    查看效果

    截屏2021-03-27 20.13.02

    给按钮添加样式

    截屏2021-03-27 20.14.09 截屏2021-03-27 20.16.18

    查看样式

    截屏2021-03-27 20.16.49

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

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>员工列表</title>
        <% pageContext.setAttribute("APP_PATH", request.getContextPath()); %>
    
        <%--
            不以 / 开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
            以 / 开始的相对路径,找资源,以服务器的路径为标准 (http://localhost:8080),需要加上项目名
                        http://localhost:8080/crud
        --%>
    
        <%--  引入 jquery  --%>
        <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
        <%--  引入样式  --%>
        <link rel="stylesheet" href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container">
            <!-- 标题 -->
            <!-- class="row" 为栅格系统的行 -->
            <div class="row">
                <!-- col-md-xx 数字代表列数  col-md-offset-xx 数字代表偏移-->
                <div class="col-md-12">
                    <h1>SSM-CRUD</h1>
                </div>
            </div>
    
            <div class="row">
                <div class="col-md-4 col-md-offset-8">
                    <button type="button" class="btn-primary">新建</button>
                    <button type="button" class="btn-danger">删除</button>
                </div>
            </div>
    
            <!-- 显示表格数据 -->
            <div class="row">
                <div class="col-md-12">
                    <!-- .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应。
                        .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式。
                     -->
                    <table class="table table-hover table-striped">
                        <tr>
                            <th>#</th>
                            <th>lastName</th>
                            <th>email</th>
                            <th>gender</th>
                            <th>deptName</th>
                            <th>操作</th>
                        </tr>
                        <c:forEach items="${pageInfo.list}" var="emp">
                            <tr>
                                <th>${emp.empId}</th>
                                <th>${emp.empName}</th>
                                <th>${emp.email}</th>
                                <th>${emp.gender == 'M' ? '男' : '女'}</th>
                                <th>${emp.department.deptName}</th>
                                <th>
                                    <button class="btn btn-primary btn-sm">
                                        <!-- 铅笔图标 -->
                                        <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
                                        编辑
                                    </button>
                                    <button class="btn btn-danger btn-sm">
                                        <!-- 垃圾桶图标 -->
                                        <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
                                        删除
                                    </button>
                                </th>
                            </tr>
                        </c:forEach>
                    </table>
                </div>
            </div>
    
    
        </div>
    </body>
    </html>
    

    查看效果

    截屏2021-03-27 20.24.58

    编写分页条

    <!-- 显示分页信息 -->
    <div class="row">
        <!-- 分页文字信息 -->
        <div class="col-md-6">
            当前第 ${pageInfo.pageNum} 页,共有 ${pageInfo.pages} 页,总计 ${pageInfo.total} 条记录
        </div>
        <!-- 分页条信息 -->
        <div class="col-md-6">
            <nav aria-label="Page navigation">
                <ul class="pagination">
    
                    <li><a href="${APP_PATH}/emps?pn=1">首页</a></li>
    
                    <c:if test="${pageInfo.hasPreviousPage}">
                        <li>
                            <a href="${APP_PATH}/emps?pn=${pageInfo.prePage}" aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                    </c:if>
    
                    <c:forEach items="${pageInfo.navigatepageNums}" var="page_Num">
                        <c:if test="${page_Num == pageInfo.pageNum}">
                            <li class="active"><a href="#">${page_Num}</a> </li>
                        </c:if>
                        <c:if test="${page_Num != pageInfo.pageNum}">
                            <li><a href="${APP_PATH}/emps?pn=${page_Num}">${page_Num}</a></li>
                        </c:if>
                    </c:forEach>
    
                    <li>
                        <a href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
    
                    <li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">尾页</a></li>
                </ul>
            </nav>
        </div>
    </div>
    

    查看效果

    截屏2021-03-27 20.33.33

    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 相关的标签

    得到如下

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
      <title>员工列表</title>
      <% pageContext.setAttribute("APP_PATH", request.getContextPath()); %>
    
      <%--
          不以 / 开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
          以 / 开始的相对路径,找资源,以服务器的路径为标准 (http://localhost:8080),需要加上项目名
                      http://localhost:8080/crud
      --%>
    
      <%--  引入 jquery  --%>
      <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
      <%--  引入样式  --%>
      <link rel="stylesheet" href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
      <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container">
      <!-- 标题 -->
      <!-- class="row" 为栅格系统的行 -->
      <div class="row">
        <!-- col-md-xx 数字代表列数  col-md-offset-xx 数字代表偏移-->
        <div class="col-md-12">
          <h1>SSM-CRUD</h1>
        </div>
      </div>
    
      <div class="row">
        <div class="col-md-4 col-md-offset-8">
          <button type="button" class="btn-primary">新建</button>
          <button type="button" class="btn-danger">删除</button>
        </div>
      </div>
    
      <!-- 显示表格数据 -->
      <div class="row">
        <div class="col-md-12">
          <!-- .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应。
              .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式。
           -->
          <table class="table table-hover table-striped">
            <tr>
              <th>#</th>
              <th>lastName</th>
              <th>email</th>
              <th>gender</th>
              <th>deptName</th>
              <th>操作</th>
            </tr>
    
          </table>
        </div>
      </div>
    
      <!-- 显示分页信息 -->
      <div class="row">
        <!-- 分页文字信息 -->
        <div class="col-md-6">
    
        </div>
        <!-- 分页条信息 -->
        <div class="col-md-6">
    
        </div>
      </div>
    </div>
    </body>
    </html>
    

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

    截屏2021-03-27 21.01.31

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

    截屏2021-03-27 21.00.53

    (4) 编写消息类

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

    com.study.crud.bean 中创建 Msg

    public class Msg {
    
        public static final int CODE_SUCCESS = 100;
        public static final int CODE_FAIL = 200;
        
        // 状态码
        private int code;
        
        // 提示信息
        private String msg;
        
        // 返回给浏览器的数据
        private Map<String, Object> extend = new HashMap<String, Object>();
        
        public static Msg success() {
            Msg msg = new Msg();
            msg.setCode(CODE_SUCCESS);
            msg.setMsg("处理成功");
            return msg;
        }
        
        public static Msg fail() {
            Msg msg = new Msg();
            msg.setCode(CODE_FAIL);
            msg.setMsg("处理失败");
            return msg;
        }
    
        // 向 Msg 中添加数据
        public Msg add(String key, Object value) {
            this.extend.put(key, value);
            return this;
        }
        
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public Map<String, Object> getExtend() {
            return extend;
        }
    
        public void setExtend(Map<String, Object> extend) {
            this.extend = extend;
        }
    }
    

    改写 getEmpsWithJson()

    截屏2021-03-28 10.20.51

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

    截屏2021-03-28 10.22.37

    (4) **编写 js **

    添加 id 值

    截屏2021-03-28 14.14.52

    添加 js

    <script type="text/javascript">
      var lastPage, currentPage, totalRecord;
    
      // 1、页面加载完成以后,直接去发送一个 ajax 请求,要到分页数据
      $(function () {
        // 去首页
        to_page(1);
      });
    
      function to_page(pn) {
        $.ajax({
          url:"${APP_PATH}/emps",
          data:"pn=" + pn,
          type:"get",
          success:function (result) {
            // console.log(result);
            // 1、解析并显示员工数据
            build_emps_table(result);
            // 2、解析并显示分页信息
            build_page_info(result);
            // 3、解析显示分页条数据
            build_page_nav(result);
          }
        });
      }
    
      function build_emps_table(result) {
        // 清空表格
        $("#emps_table tbody").empty();
        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
          var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
          var empIdTd = $("<td></td>").append(item.empId);
          var empNameTd = $("<td></td>").append(item.empName);
          var gender = item.gender == 'M' ? '男' : '女';
          var genderTd = $("<td></td>").append(gender);
          var emailTd = $("<td></td>").append(item.email);
          var deptNameTd = $("<td></td>").append(item.department.deptName);
          /**
           *  <button class="btn btn-primary btn-sm">
           <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
           编辑
           </button>
           */
          var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn")
                  .append($("<span></span>")).addClass("glyphicon glyphicon-pencil").append("编辑");
          editBtn.attr("edit-id", item.empId);
          var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
                  .append($("<span></span>")).addClass("glyphicon glyphicon-trash").append("删除");
          deleteBtn.attr("del-id", item.empId);
          var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
    
          // append 方法执行完成以后还是返回原来的元素 所以可以链式操作
          $("<tr></tr>").append(checkBoxTd)
                  .append(empIdTd)
                  .append(empNameTd)
                  .append(genderTd)
                  .append(emailTd)
                  .append(deptNameTd)
                  .append(btnTd)
                  .appendTo("#emps_table tbody");
        })
      }
    
      function build_page_info(result) {
        $("#page_info_area").empty();
        var pageInfo = result.extend.pageInfo;
        $("#page_info_area").append("当前 " + pageInfo.pageNum + " 页,"
                + "总 " + pageInfo.pages + " 页,"
                + "总 " + pageInfo.total + " 条记录"
        );
        lastPage = pageInfo.pages;
        totalRecord= pageInfo.total;
        currentPage = pageInfo.pageNum;
      }
    
      function build_page_nav(result) {
        $("#page_nav_area").empty();
        var pageInfo = result.extend.pageInfo;
        var ul = $("<ul></ul>").addClass("pagination");
        var firstPageLi = $("<li></li>").append($("<a></a>").append("首页"));
        var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;"));
        if (pageInfo.hasPreviousPage == false) {
          firstPageLi.addClass("disabled");
          prePageLi.addClass("disabled");
        } else {
          firstPageLi.click(function () {
            to_page(1);
          });
          prePageLi.click(function () {
            to_page(pageInfo.pageNum - 1);
          });
        }
        ul.append(firstPageLi).append(prePageLi);
    
        $.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
          var numLi = $("<li></li>").append($("<a></a>").append(item));
          if (pageInfo.pageNum == item) {
            numLi.addClass("active");
          }
          numLi.click(function () {
            to_page(item);
          });
          ul.append(numLi);
        });
    
        var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
        var lastPageLi = $("<li></li>").append($("<a></a>").append("尾页"));
        if (pageInfo.hasNextPage == false) {
          nextPageLi.addClass("disabled");
          lastPageLi.addClass("disabled");
        } else {
          nextPageLi.click(function () {
            to_page(pageInfo.pageNum + 1);
          });
          lastPageLi.click(function () {
            to_page(pageInfo.pages);
          });
        }
        ul.append(nextPageLi).append(lastPageLi);
    
        var navEle = $("<nav></nav>").append(ul);
        navEle.appendTo("#page_nav_area");
      }
    </script>
    

    查看结果

    截屏2021-03-28 14.18.13

    4、业务逻辑

    (1)新增员工信息

    添加 员工添加的模态框

    <!-- 员工添加的模态框 -->
    <div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">员工添加</h4>
          </div>
          <div class="modal-body">
            <form class="form-horizontal">
              <div class="form-group">
                <label class="col-sm-2 control-label">empName</label>
                <div class="col-sm-10">
                  <input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
                  <span class="help-block"></span>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">email</label>
                <div class="col-sm-10">
                  <input type="text" name="email" class="form-control" id="email_add_input" placeholder="email@atguigu.com">
                  <span class="help-block"></span>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">gender</label>
                <div class="col-sm-10">
                  <label class="radio-inline">
                    <input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked"> 男
                  </label>
                  <label class="radio-inline">
                    <input type="radio" name="gender" id="gender2_add_input" value="F"> 女
                  </label>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">deptName</label>
                <div class="col-sm-4">
                  <!-- 部门提交部门id即可 -->
                  <select class="form-control" name="dId">
                  </select>
                </div>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            <button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
          </div>
        </div>
      </div>
    </div>
    

    新建按钮处添加 id

    截屏2021-03-28 14.29.09

    编写 js

    //清空表单样式及内容
      function reset_form(ele) {
        $(ele)[0].reset();
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
      }
    
      function getDepts(ele) {
        // 清空之前下拉列表的值
        $(ele).empty();
        $.ajax({
          url: "${APP_PATH}/depts",
          type: "get",
          success:function (result) {
            //{"code":100,"msg":"处理成功!",
            //"extend":{"depts":[{"deptId":1,"deptName":"开发部"},{"deptId":2,"deptName":"测试部"}]}}
            //console.log(result);
            //显示部门信息在下拉列表中
            //$("#empAddModal select").append("")
            $.each(result.extend.depts,function(){
              var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId);
              optionEle.appendTo(ele);
            });
          }
        });
      }
    
      // 点击新增按钮弹出模态框。
      $("#emp_add_modal_btn").click(function () {
        //清除表单数据(表单完整重置(表单的数据,表单的样式))
        reset_form("#empAddModal form");
        //s$("")[0].reset();
        //发送ajax请求,查出部门信息,显示在下拉列表中
        getDepts("#empAddModal select");
        //弹出模态框
        $("#empAddModal").modal({
          backdrop:"static"
        });
      });
    

    查看 添加模态框

    截屏2021-03-28 14.30.54

    创建 DepartmentController 映射 getDepts 请求

    @Controller
    public class DepartmentController {
    
        @Autowired
        DepartmentService departmentService;
    
        @RequestMapping("/depts")
        @ResponseBody
        public Msg getDeptsWithJson() {
            List<Department> depts = departmentService.getDepts();
            return Msg.success().add("depts", depts);
        }
    }
    
    @Service
    public class DepartmentService {
    
        @Autowired
        DepartmentMapper departmentMapper;
    
        public List<Department> getDepts() {
            return departmentMapper.selectByExample(null);
        }
    }
    

    查看是否显示部门信息

    截屏2021-03-28 16.01.23

    (2)数据校验

    **js校验 **

    // 检验表单数据
      function validate_add_form() {
        var empName = $("#empName_add_input").val();
        var regName = /(^[a-zA-Z0-9]{6,16}$)|(^[u2E80-u9FFF]{2,5})/;
        if (!regName.test(empName)) {
          show_validate_msg("#empName_add_input", "error", "用户名可以是 2-5 位中文或者 6-16 位英文和数字的组合");
          return false;
        } else {
          show_validate_msg("#empName_add_input", "success", "");
        }
    
        var email = $("#email_add_input").val();
        var regEmail = /^([a-z0-9_.-]+)@([da-z.-]+).([a-z.]{2,6})$/;
        if (!regEmail.test(email)) {
          show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
          return false;
        } else {
          show_validate_msg("#email_add_input", "success", "");
        }
        return true;
      }
    
      // 显示校验结果的提示信息
      function show_validate_msg(ele, status, msg) {
        $(ele).parent().removeClass("has-success has-error");
        $(ele).next("span").text("");
        if ("success" == status) {
          $(ele).parent().addClass("has-success");
          $(ele).next("span").text(msg);
        } else {
          $(ele).parent().addClass("has-error");
          $(ele).next("span").text(msg);
        }
      }
    
      // 校验用户名是否可用
      $("#empName_add_input").change(function () {
        var empName = this.value;
        $.ajax({
          url:"${APP_PATH}/checkuser",
          data:"empName="+empName,
          type:"post",
          success:function (result) {
            if (result.code == 100) {
              show_validate_msg("#empName_add_input", "success", "用户名可用");
              $("emp_save_btn").attr("ajax-va", "success");
            } else {
              show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
              $("emp_save_btn").attr("ajax-va", "error");
            }
          }
        });
      });
    

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

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

    EmployeeService 中添加检验方法

    public boolean checkUser(String empName) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpNameEqualTo(empName);
        long count = employeeMapper.countByExample(example);
        return count == 0;
    }
    

    查看校验结果

    截屏2021-03-28 16.10.20 截屏2021-03-28 16.10.51

    (3) 保存员工

    添加 js

    // 点击保存,保存员工
      $("#emp_save_btn").click(function () {
        // 1、模态框中填写的数据提交给服务器进行保存
        // 1、先对要提交给服务器的数据进行校验
        if (!validate_add_form()) {
          return false;
        }
        // 1、判断之前的 ajax 用户名校验是否成功
        if ($(this).attr("ajax-va") == "error") {
          return false;
        }
    
        // 2、发送 ajax 请求保存员工
        $.ajax({
          url:"${APP_PATH}/emp",
          type:"post",
          data:$("#empAddModal form").serialize(),
          success:function(result) {
            if (result.code == 100) {
              // 员工保存成功
              // 1、关闭模态框
              $("#empAddModal").modal("hide");
              // 2、来到最后一页,显示刚才保存的数据
              if (totalRecord % 5 == 0) {
                lastPage++;
                currentPage = lastPage;
              }
              totalRecord++;
              to_page(lastPage);
            } else {
              // 显示失败信息
              if (undefined != result.extend.errorFields.email) {
                // 显示邮箱错误信息
                show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
              }
              if (undefined != result.extend.errorFields.empName) {
                // 显示员工名字的错误信息
                show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
              }
            }
          }
        });
      });
    

    Employee 中使用JSR303 数据校验

    截屏2021-03-28 16.17.42

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

    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    @ResponseBody
    public Msg saveEmp(@Valid Employee employee, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, Object> map = new HashMap<String, Object>();
            List<FieldError> errors = result.getFieldErrors();
            for (FieldError fieldError : errors) {
                System.out.println("错误的字段名:" + fieldError.getField());
                System.out.println("错误信息:" + fieldError.getDefaultMessage());
                map.put(fieldError.getField(), fieldError.getDefaultMessage());
            }
            return Msg.fail().add("errorFields", map);
        } else {
            employeeService.saveEmp(employee);
            return Msg.success();
        }
    }
    

    EmployeeService 中添加保存员工的方法

    public void saveEmp(Employee employee) {
        employeeMapper.insertSelective(employee);
    }
    
    截屏2021-03-28 16.20.14 截屏2021-03-28 16.20.43

    (4) 修改员工信息

    添加员工修改模态框

    <!-- 员工修改的模态框 -->
    <div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title">员工修改</h4>
          </div>
          <div class="modal-body">
            <form class="form-horizontal">
              <div class="form-group">
                <label class="col-sm-2 control-label">empName</label>
                <div class="col-sm-10">
                  <p class="form-control-static" id="empName_update_static"></p>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">email</label>
                <div class="col-sm-10">
                  <input type="text" name="email" class="form-control" id="email_update_input" placeholder="email@atguigu.com">
                  <span class="help-block"></span>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">gender</label>
                <div class="col-sm-10">
                  <label class="radio-inline">
                    <input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked"> 男
                  </label>
                  <label class="radio-inline">
                    <input type="radio" name="gender" id="gender2_update_input" value="F"> 女
                  </label>
                </div>
              </div>
              <div class="form-group">
                <label class="col-sm-2 control-label">deptName</label>
                <div class="col-sm-4">
                  <!-- 部门提交部门id即可 -->
                  <select class="form-control" name="dId">
                  </select>
                </div>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            <button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
          </div>
        </div>
      </div>
    </div>
    

    添加 js

    // 1、如果在编辑和删除按钮创建之前绑定 click 是绑定不上的
      // 1)可以在创建按钮的时候绑定
      // 2)绑定点击 .live()
      $(document).on("click", ".edit_btn", function () {
        // 1、查处部门信息,并显示部门列表
        getDepts("#empUpdateModal select");
        // 2、查处员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));
    
        // 3、把员工的 id 传递给模态框的更新按钮
        $("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
        $("#empUpdateModal").modal({
          backdrop: "static"
        });
      });
    
      function getEmp(id) {
        $.ajax({
          url:"${APP_PATH}/emp/" + id,
          type:"get",
          success:function (result) {
            var empData = result.extend.emp;
            $("#empName_update_static").text(empData.empName);
            $("#email_update_input").val(empData.email);
            $("#empUpdateModal input[name=gender]").val([empData.gender]);
            $("#empUpdateModal select").val([empData.dId]);
          }
        });
      }
    
      // 点击更新,更新员工信息
      $("#emp_update_btn").click(function () {
        // 验证邮箱是否合法
        // 1、校验邮箱信息
        var email = $("#email_update_input").val();
        var regEmail = /^([a-z0-9_.-]+)@([da-z.-]+).([a-z.]{2,6})$/;
        if (!regEmail.test(email)) {
          show_validate_msg("#email_update_input", "error", "邮箱格式不正确");
          return false;
        } else {
          show_validate_msg("#email_update_input", "success", "");
        }
    
        // 2、发送 ajax 请求保存更新的员工数据
        $.ajax({
          url:"${APP_PATH}/emp/" + $(this).attr("edit-id"),
          type:"put",
          data:$("#empUpdateModal form").serialize(),
          success:function (result) {
            $("#empUpdateModal").modal("hide");
            to_page(currentPage);
          }
        });
      });
    

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

    @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Msg getEmp(@PathVariable("id") Integer id) {
        Employee employee = employeeService.getEmp(id);
        return Msg.success().add("emp", employee);
    }
    
    @RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
    @ResponseBody
    public Msg updateEmp(Employee employee, HttpServletRequest request) {
        employeeService.updateEmp(employee);
        return Msg.success();
    }
    

    EmployeeService 中添加 getEmp 方法和 update 方法

    public Employee getEmp(Integer id) {
        return employeeMapper.selectByPrimaryKeyWithDept(id);
    }
    
    public void updateEmp(Employee employee) {
        employeeMapper.updateByPrimaryKeySelective(employee);
    }
    

    查看效果

    截屏2021-03-28 16.38.29截屏2021-03-28 16.39.26

    截屏2021-03-28 16.39.45

    (5) 添加全选功能

    添加全选按钮

    截屏2021-03-28 16.43.39

    添加 js

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

    添加删除功能

    给删除按键添加 id

    截屏2021-03-28 16.53.57

    添加 js

      // 单个删除
      $(document).on("click", ".delete_btn", function () {
        var empName = $(this).parents("tr").find("td:eq(2)").text();
        var empId = $(this).attr("del-id");
        // 弹出是否确认删除对话框
        if (confirm("确认删除【" + empName + "】吗?")) {
          $.ajax({
            url:"${APP_PATH}/emp/" + empId,
            type:"delete",
            success:function (result) {
              alert(result.msg);
              to_page(1);
            }
          });
        }
      });
    
      // 点击全部删除、就批量删除
      $("#emp_delete_all_btn").click(function () {
        var empNames = "";
        var del_ids = "";
        $.each($(".check_item:checked"), function () {
          empNames += $(this).parents("tr").find("td:eq(2)").text() + ",";
          del_ids += $(this).parents("tr").find("td:eq(1)").text() + "-";
        });
        empNames = empNames.substring(0, empNames.length - 1);
        del_ids = del_ids.substring(0, del_ids.length - 1);
        if (confirm("确认删除【" + empNames + "】吗?")) {
          $.ajax({
            url:"${APP_PATH}/emp/" + del_ids,
            type:"delete",
            success:function (result) {
              alert(result.msg);
              to_page(1);
            }
          });
        }
      });
    

    EmployeeController 中添加删除方法

    @RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmp(@PathVariable("ids") String ids) {
        // 批量删除
        if (ids.contains("-")) {
            List<Integer> del_ids = new ArrayList<Integer>();
            String[] str_ids = ids.split("-");
            for (String str : str_ids) {
                del_ids.add(Integer.parseInt(str));
            }
            employeeService.deleteBatch(del_ids);
        } else {
            Integer id = Integer.parseInt(ids);
            employeeService.deleteEmp(id);
        }
        return Msg.success();
    }
    

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

    public void deleteBatch(List<Integer> del_ids) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpIdIn(del_ids);
        employeeMapper.deleteByExample(example);
    }
    
    public void deleteEmp(Integer id) {
        employeeMapper.deleteByPrimaryKey(id);
    }
    

    查看效果

    截屏2021-03-28 16.49.42 截屏2021-03-28 16.54.52 截屏2021-03-28 16.55.11

    四、总结

    image-20210328170831074
  • 相关阅读:
    谷歌云服务器XShell登录
    PGI 遇到的坑
    Matlab处理数据导出Paraview可读的vtk文件(二)
    Matlab处理数据导出Paraview可读的vtk文件(一)
    Windows7 + OSG3.6 + VS2017 + Qt5.11
    CentOS安装指定版本GCC
    利用ncurses库开发终端工具箱(1)—— ToDoList小工具开发
    Winform Post请求传递Json格式参数的写法
    把Java代码转成c#可用的dll
    Image.FromStream(ms) 提示参数无效
  • 原文地址:https://www.cnblogs.com/Code-CHAN/p/14589451.html
Copyright © 2011-2022 走看看