文章目录

  • 前言
  • 一、SSM整合
    • 1、项目介绍
    • 2、功能点
    • 3、技术点
  • 二、基础环境搭建
    • 1、创建maven工程
    • 2、引入依赖jar包
    • 3、引入BootStrap
    • 4、SSM整合配置
      • 4.1、配置web.xml
      • 4.2、springMVC配置
      • 4.3、配置spring
    • 5、编写mybatis核心文件
    • 6、创建数据库
    • 7、mybatis逆向工程
    • 8、修改mapper映射文件
    • 9、测试dao接口方法
  • 三、查询功能实现
    • 1、编写 index.jsp 页面:
    • 2、编写list.jsp页面
    • 3、编写EmployeeService类
    • 4、引入PageHelper分页插件
    • 5、编写EmployeeController类
    • 6、虚拟MVC测试
    • 7、完善list.jsp页面
  • 四、改写查询功能
    • 1、创建Msg类
    • 2、改写处理器方法
    • 3、修改 index.jsp
  • 五、编写添加功能
    • 1、编写查询所有部门的业务逻辑
      • 1.1、编写DepartmentService
      • 1.2、编写DepartmentController
    • 2、编写保存员工代码
      • 2.1、编写Service层方法
      • 2.2、编写controller层方法
    • 3、设置分页助手
    • 4、前端校验
      • 4.1、检查邮箱是否已存在
    • 5、后端校验
      • 5.1、导入相关jar包
      • 5.2、修改Employee类
      • 5.3、修改添加员工控制**器**
      • 5.4、修改保存按钮事件函数
      • 5.5、完整jsp页面
  • 六、修改员工信息功能
    • 1、编写修改模态框
    • 2、添加按钮样式
    • 3、修改重置表单函数
    • 4、编辑按钮事件
    • 5、回显用户数据
      • 5.1、编写控制器方法
      • 5.2、编写Service层方法
      • 5.3、网页查询员工信息函数
      • 5.4、为修改员工按钮添加属性
      • 5.5、回显员工信息函数
      • 5.6、完善修改按钮事件
    • 6、更新按钮事件
      • 6.1、控制器方法
      • 6.2、Service层方法
      • 6.3、修改编辑按钮事件
      • 6.4、使用PUT发送请求
  • 七、删除员工
    • 1、控制器方法
    • 2、Srevice方法
    • 3. 添加选择按钮
    • 4、绑定选择按钮事件
    • 4、删除单个员工按钮事件
    • 5、删除全部员工按钮事件
  • 九、最终index页面

前言

该笔记为尚硅谷SSM实战演练丨ssm整合快速开发CRUD学习笔记

github项目地址:https://github.com/xjhqre/sgg-ssm-demo

一、SSM整合

1、项目介绍

使用SSM框架搭建出一套简单的CRUD项目示例,包括分页查询、Ajax请求、数据校验等。

2、功能点

  1. 分页查询
  2. 数据校验:JQuery前端校验+JSR-303后端校验
  3. Ajax请求
  4. REST风格的URI:GET查询、POST新增、DELETE删除、PUT修改

3、技术点

  • 基础框架-SSM(Spring+SpringMVC+Mybatis)
  • 数据库-MySQL
  • 前端框架-Bootstrap
  • 依赖管理-Maven
  • 分页查询-PageHelper
  • 逆向工程-Mybatis Generator

二、基础环境搭建

相关配置文件的创建请见SSM整合配置模板,这里主要写下不同的地方。

1、创建maven工程

步骤:

  1. 创建maven工程快速开始
  2. 修改pom.xml文件,打包方式为war
  3. 创建resources目录
  4. 删除不必要的类和目录
  5. 创建web.xml文件

2、引入依赖jar包

SpringMVC、Spring:

  • spring-webmvc

Spring-Jdbc:

  • spring-jdbc

Spring面向切面编程:

  • spring-aspects

Mybatis:

  • mybatis

mybatis整合Spring:

  • mybatis-spring

数据库连接池:

  • c3p0(不要用druid)

MySQL驱动:

  • mysql-connector-java

其他(jstl,servlet-api,junit):

  • jstl
  • servlet-api 加上 <scope>provided</scope>
  • junit

注意spring包的版本都要相同

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>org.example</groupId><artifactId>ssm-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.14</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.14</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.14</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.17</version></dependency><!-- https://mvnrepository.com/artifact/jstl/jstl --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency></dependencies></project>

3、引入BootStrap

步骤:

  1. 在webapp文件夹下创建static目录存放bootstrap文件和jQuery文件
  2. 创建index.jsp页面,引入jquery和bootstrap

index.jsp代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><%--引入jQuery--%><script type="text/javascript" src="static/js/jquery-1.12.4.min.js"></script><%--引入样式--%><link rel="stylesheet" href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css"><script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<button type="button" class="btn btn-success">(成功)Success</button>
</body>
</html>

4、SSM整合配置

4.1、配置web.xml

步骤:

  1. 启动Spring容器,设置 contextConfigLocationContextLoaderListenercontextConfigLocation设置spring配置文件的位置,在resources目录下创建applicationContext.xml文件
  2. 配置springMVC前端控制器dispatchServlet,拦截所有请求,需要指定springMVC配置文件的位置,若不指定,则需要在同级目录下(webapp目录下)创建一个 servlet-name + -servlet的一个xml文件。让dispatchServlet拦截所有请求:/
  3. 配置字符编码过滤器 CharacterEncodingFilter,初始化参数 encoding、forceRequestEncoding、forceResponseEncoding,设置过滤所有请求 /*,一定要放在所有过滤器之前
  4. 使用Rest风格的URI,配置 HiddenHttpMethodFilter,将指定的 post 转化为 delete 或者是 put 请求。过滤所有请求/*

wen.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的容器  --><!-- needed for ContextLoaderListener --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><!-- Bootstraps the root web application context before servlet initialization --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--2、springmvc的前端控制器,拦截所有请求  --><!-- The front controller of this Spring Web application, responsible for handling all application requests --><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><!-- Map all requests to the DispatcherServlet for handling --><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>
</web-app>

4.2、springMVC配置

步骤:

  1. 配置扫描控制器
  2. 配置视图解析器
  3. 启动Servlet默认处理器,处理springMVC不能处理的请求
  4. 开启MVC注解驱动

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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--SpringMVC的配置文件,包含网站跳转逻辑的控制,配置  --><context:component-scan base-package="com.xjhqre.crud" 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><!--两个标准配置  --><!-- 将springmvc不能处理的请求交给tomcat --><mvc:default-servlet-handler/><!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax...映射动态请求 --><mvc:annotation-driven/></beans>

4.3、配置spring

步骤:

  1. 配置数据源,创建db.properties文件
  2. 配置和mybatis的整合
    1. 指定mybatis的核心配置文件
    2. 指定mybatis的mapper文件
    3. 配置扫描器,将mybatis接口的实现加入到ioc容器中,扫描所有dao接口的实现,加入到ioc容器中
    4. 配置一个可以执行批量的sqlSession,加入到IOC容器里
  3. 事务控制的配置,导入配置好的数据源id
    1. 配置切入点表达式
    2. 配置事务增强
    3. 配置事务如何切入

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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 不扫描Controller注解 --><context:component-scan base-package="com.xjhqre.crud"><context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller" /></context:component-scan><!-- Spring的配置文件,这里主要配置和业务逻辑有关的 --><!--=================== 数据源,事务控制,xxx ========================--><context:property-placeholder location="classpath:db.properties"/><bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="jdbcUrl" value="${jdbc.url}"/><property name="driverClass" value="${jdbc.driverClassName}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--========================== 配置和MyBatis的整合============================= --><!-- 创建sqlSessionFactory工厂对象 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 指定mybatis全局配置文件的位置 --><property name="configLocation" value="classpath:mybatis-config.xml"/><!-- 指定数据源 --><property name="dataSource" ref="pooledDataSource"/><!-- 指定mapper配置文件--><property name="mapperLocations" value="classpath:mapper/*.xml"/></bean><!-- 配置扫描器,将mybatis接口的实现加入到ioc容器中 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--扫描所有dao接口的实现,加入到ioc容器中 --><property name="basePackage" value="com.xjhqre.crud.dao"/></bean><!-- 配置一个可以执行批量的sqlSession --><bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"><!-- 配置SQLSession工厂 --><constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/><!-- 配置执行者类型为批量 --><constructor-arg name="executorType" value="BATCH"/></bean><!-- ============================事务控制的配置 =============================--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 控制数据源 --><property name="dataSource" ref="pooledDataSource"/></bean><!--开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式)  --><!-- 配置事务如何切入--><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- 所有方法都是事务方法 --><tx:method name="*"/><!-- 以get开头的所有方法 --><tx:method name="get*" read-only="true"/></tx:attributes></tx:advice><aop:config><!-- 切入点表达式 --><aop:pointcut id="txPoint" expression="execution(* com.xjhqre.crud.service..*(..))"/><!-- 配置事务增强 --><aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/></aop:config></beans>

5、编写mybatis核心文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!-- 配置驼峰命名规则 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 设置日志 --><setting name="logImpl" value="STDOUT_LOGGING" /></settings>
</configuration>

6、创建数据库

DROP DATABASE IF EXISTS ssm;
CREATE DATABASE ssm;
USE ssm;CREATE TABLE t_emp(`emp_id` INT(11) PRIMARY KEY AUTO_INCREMENT,`emp_name` VARCHAR(255) NOT NULL,`emp_gender` CHAR(1) NOT NULL,`emp_email` VARCHAR(255),`dept_id` INT(11)
);CREATE TABLE t_dept(`dept_id` INT(11) PRIMARY KEY AUTO_INCREMENT,`dept_name` VARCHAR(255) NOT NULL
);

7、mybatis逆向工程

使用mybatis的逆向工程生成对应的bean以及mapper

步骤:

  1. 导入mybatis generator core包
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.7</version>
</dependency>
  1. 在当前工程目录下创建 mbg.xml 文件(与pom.xml同级目录)

  2. 配置mgb.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//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><property name="suppressAllComments" value="true" /></commentGenerator><!-- 配置数据库连接 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/ssm?useSSL=false&amp;serverTimezone=UTC"userId="root"password="123456"></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><!-- 指定javaBean生成的位置 --><javaModelGenerator targetPackage="com.xjhqre.crud.pojo"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接口生成的位置,mapper接口 --><javaClientGenerator type="XMLMAPPER"targetPackage="com.xjhqre.crud.dao" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- table指定每个表的生成策略 --><table tableName="t_emp" domainObjectName="Employee"/><table tableName="t_dept" domainObjectName="Department"/></context>
</generatorConfiguration>
  1. 编写一个测试类运行逆向工程生成mapper和类
@Test
public void mbgTest() 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);
}

8、修改mapper映射文件

逆向工程不能生成联合查询。我们需要在mybatis逆向工程生成的mapper映射文件基础上添加新功能,查询员工时带上他的部门信息

步骤:

  1. EmployeeMapper接口上新添加两个方法:
List<Employee> selectByExampleWithDept(EmployeeExample example);Employee selectByPrimaryKeyWithDept(Integer empId);
  1. Employee员工类上新增属性private Department department;,并添加 get和set方法

  2. EmployeeMapper.xml中编写编写 With_Dept_Column_List:

<sql id="With_Dept_Column_List">e.emp_id, e.emp_name, e.emp_gender, e.emp_email, e.dept_id, d.dept_id, d.dept_name
</sql>
  1. 编写 WithDeptResultMap 返回结果封装:
<resultMap id="WithDeptResultMap" type="com.xjhqre.crud.pojo.Employee"><id column="emp_id" jdbcType="INTEGER" property="empId" /><result column="emp_name" jdbcType="VARCHAR" property="empName" /><result column="emp_gender" jdbcType="CHAR" property="empGender" /><result column="emp_email" jdbcType="VARCHAR" property="empEmail" /><result column="dept_id" jdbcType="INTEGER" property="deptId" /><association property="department" javaType="com.xjhqre.crud.pojo.Department"><id column="dept_id" property="deptId"/><result column="dept_name" property="deptName"/></association>
</resultMap>
  1. 编写 selectByExampleWithDept
<select id="selectByExampleWithDept" parameterType="com.xjhqre.crud.pojo.EmployeeExample"resultMap="WithDeptResultMap">select<if test="distinct">distinct</if><include refid="With_Dept_Column_List"/>from t_emp e left join t_dept d on e.`dept_id`=d.`dept_id`<if test="_parameter != null"><include refid="Example_Where_Clause"/></if><if test="orderByClause != null">order by ${orderByClause}</if>
</select>
  1. 编写 selectByPrimaryKeyWithDept
<select id="selectByPrimaryKeyWithDept" parameterType="java.lang.Integer" resultMap="WithDeptResultMap">select<include refid="With_Dept_Column_List"/>from t_emp e left join t_dept d on e.`dept_id`=d.`dept_id`where emp_id = #{empId,jdbcType=INTEGER}
</select>

9、测试dao接口方法

spring项目推荐使用spring的单元测试,可以自动注入我们需要的组件

需要导入spring-test包

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.3.14</version><scope>test</scope>
</dependency>

测试代码:

Department类和Employee类中添加构造函数

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {@AutowiredDepartmentMapper departmentMapper;@AutowiredEmployeeMapper employeeMapper;@AutowiredSqlSession sqlSession;@Testpublic void test1() {System.out.println(departmentMapper);// 1. 测试插入部门departmentMapper.insertSelective(new Department(null, "技术部"));departmentMapper.insertSelective(new Department(null, "开发部"));// 2、生成员工数据,测试员工插入employeeMapper.insertSelective(new Employee(null, "xjhqre", "M", "xjhqre@126.com", 1));// 3、批量插入多个员工;批量,使用可以执行批量操作的sqlSession。EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);for (int i = 0; i < 100; i++) {String uid = UUID.randomUUID().toString().substring(0, 5) + i;mapper.insertSelective(new Employee(null, uid, "M", uid + "@126.com", 1));}}
}

三、查询功能实现

步骤:

  1. 访问 index.jsp页面
  2. index.jsp 页面发送出查询员工列表请求
  3. EmployeeController来接收请求,查出员工数据
  4. 来到 list.jsp 页面进行展示

1、编写 index.jsp 页面:

发送请求为 /emps

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<jsp:forward page="/emps"></jsp:forward>
<head><title>Title</title>
</head>
<body>
</body>
</html>

2、编写list.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>员工列表</title>
</head>
<body></body>
</html>

3、编写EmployeeService类

@Service
public class EmployeeService {@AutowiredEmployeeMapper employeeMapper;/*** 查询所有员工* @return 员工信息*/public List<Employee> queryAllEmployees() {return employeeMapper.selectByExampleWithDept(null);}
}

4、引入PageHelper分页插件

  1. 在pom.xml文件里引入PageHelper依赖
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.2</version>
</dependency>
  1. 在 mybatis 核心文件中注册插件,写在 <typeAliases>标签后面
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>

5、编写EmployeeController类

@Controller
public class EmployeeController {@AutowiredEmployeeService employeeService;/*** 查询员工数据* @return 员工信息*/@RequestMapping("/emps")public String queryAllEmployees(@RequestParam(value = "pn", defaultValue = "1")Integer pn, Model model) {// 在查询之前调用分页插件,传入页码以及每页分页的大小PageHelper.startPage(pn, 5);// startPage后面紧跟的这个查询就是一个分页查询List<Employee> employees = employeeService.queryAllEmployees();// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面展示PageInfo pageInfo = new PageInfo(employees, 5); // 传入页码显示数量model.addAttribute("pageInfo", pageInfo);return "list"; // 返回到 list.jsp 页面}
}

6、虚拟MVC测试

/*** 使用Spring测试模块提供的测试请求功能,测试curd请求的正确性* Spring4测试的时候,需要servlet3.0的支持** @author lfy*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration // 表示测试的 ApplicationContext 应该是WebApplicationContext
@ContextConfiguration(locations = {"classpath:applicationContext.xml","/WEB-INF/dispatcherServlet-servlet.xml"})
public class MvcTest {// 传入SpringMVC的ioc@AutowiredWebApplicationContext context;// 虚拟MVC请求,获取到处理结果MockMvc mockMvc;@Beforepublic void initMokcMvc() {// 初始化mockMvcmockMvc = MockMvcBuilders.webAppContextSetup(context).build();}@Testpublic void testPage() throws Exception {// 模拟发送get请求, 传入参数名和参数的值,拿到返回值MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "5")).andReturn();// 请求成功以后,请求域中会有pageInfo;我们可以取出pageInfo进行验证MockHttpServletRequest request = result.getRequest();PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");System.out.println("当前页码:" + pageInfo.getPageNum());System.out.println("总页码:" + pageInfo.getPages());System.out.println("总记录数:" + pageInfo.getTotal());System.out.println("在页面需要连续显示的页码");int[] nums = pageInfo.getNavigatepageNums();for (int i : nums) {System.out.print(" "+i);}System.out.println();//获取员工数据List<Employee> list = pageInfo.getList();for (Employee employee : list) {System.out.println("ID:"+employee.getEmpId()+"==>Name:"+employee.getEmpName());}}
}

7、完善list.jsp页面

引入 jsp 依赖包,不引入无法使用pageContextsetAttribute方法

<!-- 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>

list.jsp页面:

  1. pageInfo 中取出取出员工信息显示
  2. 完善分页条
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>员工列表</title><%pageContext.setAttribute("APP_PATH", request.getContextPath());%><!-- web路径:不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名http://localhost:3306/crud--><script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script><link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet"><script src="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"></script>
</head>
<body>
<%-- 搭建显示页面 --%>
<div class="container"><%-- 标题 --%><div class="row"><div class="col-md-12"><h1>SSM_CRUD</h1></div></div><%-- 按钮 --%><div class="row"><div class="col-md-2 col-md-offset-10"><button class="btn btn-primary"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>添加</button><button class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除</button></div></div><%-- 显示表格数据 --%><div class="row"><div class="col-md-12"><table class="table table-striped"><tr><th>#</th><th>empName</th><th>gender</th><th>email</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.empGender}</th><th>${emp.empEmail}</th><th>${emp.department.deptName}</th><th><button class="btn btn-primary"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>编辑</button><button class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除</button></th></tr></c:forEach></table></div></div><%-- 显示分页信息 --%><div class="row"><%--分页条信息--%><div class="col-md-6 col-md-offset-3 text-center"><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.pageNum-1}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li></c:if><c:forEach items="${pageInfo.navigatepageNums}" var="num"><c:if test="${pageInfo.pageNum == num}"><li class="active"><a href="${APP_PATH }/emps?pn=${num}">${num}</a></li></c:if><c:if test="${pageInfo.pageNum != num}"><li><a href="${APP_PATH }/emps?pn=${num}">${num}</a></li></c:if></c:forEach><c:if test="${pageInfo.hasNextPage}"><li><a href="${APP_PATH}/emps?pn=${pageInfo.pageNum+1}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li></c:if><li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">末页</a></li></ul></nav></div></div><div class="row"><%--分页文字信息 --%><div class="col-md-6 col-md-offset-3 text-center">当前第${pageInfo.pageNum}页,总页数:${pageInfo.pages}, 总记录数:${pageInfo.total}</div></div></div>
</body>
</html>

四、改写查询功能

步骤:

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

1、创建Msg类

类中定义状态码、提示信息、返回给用户的数据、以及相关的 get、set方法,还要定义一个 add 方法,返回 Msg 类对象,用于链式调用

public class Msg {// 状态码 100:成功   200:失败private int code;// 提示信息private String msg;// 返回给用户的数据,用map存储private Map<String, Object> extend = new HashMap<>();// 返回成功方法public static Msg success() {Msg result = new Msg();result.setCode(100);result.setMsg("处理成功!");return result;}// 返回失败方法public static Msg fail() {Msg result = new Msg();result.setCode(200);result.setMsg("处理失败!");return result;}// 用于链式添加信息public Msg add(String key,Object value){this.getExtend().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;}
}

2、改写处理器方法

返回 json 数据,需要导入jackson包

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version>
</dependency>

EmployeeController:

@Controller
public class EmployeeController {@AutowiredEmployeeService employeeService;/*** 查询员工数据* @return 员工信息*/@RequestMapping("/emps")@ResponseBodypublic Msg queryAllEmployees(@RequestParam(value = "pn", defaultValue = "1")Integer pn) {PageHelper.startPage(pn, 5);List<Employee> employees = employeeService.queryAllEmployees();PageInfo pageInfo = new PageInfo(employees, 5);return Msg.success().add("pageInfo", pageInfo);}
}

3、修改 index.jsp

在 index.jsp 页面加载完后 发送 Ajax 请求,将返回的 JSON 数据解析。删除原来的 <c:if> 和 <c:foreach> 标签

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>员工列表</title><%pageContext.setAttribute("APP_PATH", request.getContextPath());%><!-- web路径:不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名http://localhost:3306/crud--><script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script><link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet"><script src="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"></script>
</head>
<body>
<%-- 搭建显示页面 --%>
<div class="container"><%-- 标题 --%><div class="row"><div class="col-md-12"><h1>SSM_CRUD</h1></div></div><%-- 按钮 --%><div class="row"><div class="col-md-2 col-md-offset-10"><button class="btn btn-primary"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>添加</button><button class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除</button></div></div><%-- 显示表格数据 --%><div class="row"><div class="col-md-12"><table class="table table-striped" id="emps_table"><thead><tr><th>#</th><th>empName</th><th>gender</th><th>email</th><th>deptName</th><th>操作</th></tr></thead><tbody><%-- 通过函数加载数据 --%></tbody></table></div></div><%-- 显示分页信息 --%><div class="row"><%--分页条信息--%><div class="col-md-6 col-md-offset-3 text-center" id="page_info_area"></div></div><div class="row"><%--分页文字信息 --%><div class="col-md-6 col-md-offset-3 text-center" id="page_nav_area"></div></div></div>
<script type="text/javascript">// 初始化页面时需要调用的函数$(function () {// 去首页to_page(1);});// 页面跳转函数function to_page(pn) {$.ajax({url: "${APP_PATH}/emps",data: "pn=" + pn,type: "GET",success: function (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 empIdTd = $("<td></td>").append(item.empId);var empNameTd = $("<td></td>").append(item.empName)var genderTd = $("<td></td>").append(item.empGender == "M" ? "男" : "女")var emailTd = $("<td></td>").append(item.empEmail)var deptNameTd = $("<td></td>").append(item.department.deptName)// 注入按钮数据var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);$("<tr></tr>").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()$("#page_info_area").append("当前页:" +result.extend.pageInfo.pageNum + ",总页数:" +result.extend.pageInfo.pages + ",总记录数:" +result.extend.pageInfo.total)}// 解析显示分页条function build_page_nav(result) {// 清空原来的分页码$("#page_nav_area").empty();// 构建元素var ul = $("<ul></ul>").addClass("pagination")var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;").attr("href", "#"));var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;").attr("href", "#"));var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));// 添加首页、末页、上一页、下一页禁用 和跳转功能if (result.extend.pageInfo.hasPreviousPage == false) {firstPageLi.addClass("disabled")prePageLi.addClass("disabled")} else {firstPageLi.click(function () {to_page(1)})prePageLi.click(function () {to_page(result.extend.pageInfo.pageNum-1)})}if (result.extend.pageInfo.hasNextPage == false) {nextPageLi.addClass("disabled");lastPageLi.addClass("disabled");} else {lastPageLi.click(function () {to_page(result.extend.pageInfo.pages);});nextPageLi.click(function () {to_page(result.extend.pageInfo.pageNum+1);});}// 添加首页和前一页ul.append(firstPageLi).append(prePageLi)// 构建条码$.each(result.extend.pageInfo.navigatepageNums, function (index, num) {var numLi = $("<li></li>").append($("<a></a>").append(num).attr("href", "#"));// 设置当前页码高亮显示if (result.extend.pageInfo.pageNum == num) {numLi.addClass("active")}// 添加按钮跳转事件numLi.click(function () {to_page(num)})ul.append(numLi)});// 添加末页和后一页ul.append(nextPageLi).append(lastPageLi)var navEle = $("<nav></nav>").append(ul)navEle.appendTo("#page_nav_area");}
</script>
</body>
</html>

五、编写添加功能

步骤:

  1. 在index.jsp页面点击“新增”按钮
  2. 弹出添加模态框
  3. 从数据库中查询出所有部门名称显示在下拉列表中
  4. 用户输入数据
  5. 校验用户名、邮箱格式是否正确、用户名是否重复
  6. 点击“保存”按钮添加数据

1、编写查询所有部门的业务逻辑

1.1、编写DepartmentService

@Service
public class DepartmentService {@AutowiredDepartmentMapper departmentMapper;public List<Department> quireAllDepartments() {return departmentMapper.selectByExample(null);}
}

1.2、编写DepartmentController

@Controller
public class DepartmentController {@AutowiredDepartmentService departmentService;@RequestMapping("/depts")@ResponseBodypublic Msg quireAllDepartments() {List<Department> departments = departmentService.quireAllDepartments();return Msg.success().add("depts", departments);}
}

2、编写保存员工代码

规定URI:

  • /emp/{id} GET查询员工
  • /emp POST保存员工
  • /emp/{id} PUT修改员工
  • /emp/{id} DELETE删除员工

2.1、编写Service层方法

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

2.2、编写controller层方法

@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(Employee employee) {employeeService.saveEmp(employee);return Msg.success();
}

3、设置分页助手

在添加用户后跳转到最后一页,传入跳转的页数为总记录数,需要设置分页助手参数合理化。否则会跳转到其他非法地址

在 mybatis 核心配置文件中配置

<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!-- 分页参数合理化 --><property name="reasonable" value="true"/></plugin>
</plugins>

reasonable:分页合理化参数,默认值为 false,当该参数为 true 时,pageNum<=0 时会查询第一页,pageNum(超过总数时),会查询最后一页,默认 false 时,直接根据参数进行查询

4、前端校验

  • 用户名格式校验
  • 邮箱格式校验
  • 邮箱是否重复校验

4.1、检查邮箱是否已存在

因为员工姓名可能存在重复的情况,所以检查邮箱是否已存在

当输入完邮箱后失去焦点,页面发送Ajax请求查询邮箱是否重复,重复则在页面显示“邮箱地址重复”

发送表单中含有中文,使用POST请求,因为GET请求不校验中文

编写Service层方法

/*** 检查邮箱是否重复* @param empEmail 页面传来的邮箱* @return 返回该邮箱是否可用*/
public boolean checkForDuplicateEmails(String empEmail) {EmployeeExample example = new EmployeeExample();EmployeeExample.Criteria criteria = example.createCriteria();criteria.andEmpEmailEqualTo(empEmail);long count = employeeMapper.countByExample(example);return count == 0;
}

编写Controller层方法

/*** 检查邮箱是否可用* @param empEmail 网页传来的邮箱* @return json数据*/
@RequestMapping("/checkEmail")
@ResponseBody
public Msg checkForDuplicateEmails(@RequestParam("empEmail")String empEmail) {boolean b = employeeService.checkForDuplicateEmails(empEmail);if(b){return Msg.success();}else {return Msg.fail();}
}

5、后端校验

重要数据使用 JSR303 进行校验

5.1、导入相关jar包

需要导入 Hibernate-Validator

JSR303数据校验支持:tomcat7及以上的服务器,tomcat7以下的服务器:el表达式。额外给服务器的lib包中替换新的标准的el

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.1.0.Final</version>
</dependency>

5.2、修改Employee类

给empName和empEmail属性添加校验注解

@Pattern(regexp = "(^[a-zA-Z0-9_-]{3,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",message = "用户名格式错误")
private String empName;@Pattern(regexp = "^[a-z\\d]+(\\.[a-z\\d]+)*@([\\da-z](-[\\da-z])?)+(\\.{1,2}[a-z]+)+$",message = "邮箱格式错误")private String empEmail;

5.3、修改添加员工控制

@Valid:指定要校验的数据

BindingResult:封装校验的结果

打印中文乱码则在tomcat中的虚拟机选项配置:-Dfile.encoding=UTF-8

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

5.4、修改保存按钮事件函数

// 模态框保存按钮点击事件
$("#saveEmpBtn").click(function () {// 校验表单数据if (!isTheUsernameCorrect || !isTheEmailAddressCorrect) {return false}// 发送保存请求$.ajax({url: "${APP_PATH}/emp",type: "POST",data: $("#empAddModal form").serialize(),success: function (result) {if(result.code == 100) {// 员工保存成功// 1. 关闭模态框$("#empAddModal").modal('hide')// 2. 跳转到最后一页显示to_page(totalRecord)} else {// 显示失败信息if(undefined != result.extend.errorFields.empEmail){validate_add_from_information_show("#empEmail_add_input", "error", "邮箱格式不正确")}if(undefined != result.extend.errorFields.empName){validate_add_from_information_show("#empName_add_input", "error", "员工名称格式不正确")}}}})
})

5.5、完整jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>员工列表</title><%pageContext.setAttribute("APP_PATH", request.getContextPath());%><!-- web路径:不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名http://localhost:3306/crud--><script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script><script src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script><link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<%-- 添加员工模态框 --%>
<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 for="empName_add_input" class="col-sm-2 control-label">empName</label><div class="col-sm-10"><input name="empName" type="text" class="form-control" id="empName_add_input"placeholder="empName"><span class="help-block"></span></div></div><div class="form-group"><label for="empEmail_add_input" class="col-sm-2 control-label">Email</label><div class="col-sm-10"><input name="empEmail" type="text" class="form-control" id="empEmail_add_input"placeholder="empEmail"><span class="help-block"></span></div></div><div class="form-group"><label class="col-sm-2 control-label">empGender</label><div class="col-sm-10"><label class="radio-inline"><input type="radio" name="empGender" id="empGender_add_input" value="M" checked="checked"> 男</label><label class="radio-inline"><input type="radio" name="empGender" id="empGender_add_input2" value="F"> 女</label></div></div><div class="form-group"><label class="col-sm-2 control-label">deptId</label><div class="col-sm-4"><select class="form-control" name="deptId" id="deptId_add_select"></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="saveEmpBtn">保存</button></div></div></div>
</div><%-- 搭建显示页面 --%>
<div class="container"><%-- 标题 --%><div class="row"><div class="col-md-12"><h1>SSM_CRUD</h1></div></div><%-- 按钮 --%><div class="row"><div class="col-md-2 col-md-offset-10"><button class="btn btn-primary" id="emp_add_modal_btn"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>添加</button><button class="btn btn-danger"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除</button></div></div><%-- 显示表格数据 --%><div class="row"><div class="col-md-12"><table class="table table-striped" id="emps_table"><thead><tr><th>#</th><th>empName</th><th>gender</th><th>email</th><th>deptName</th><th>操作</th></tr></thead><tbody><%-- 通过函数加载数据 --%></tbody></table></div></div><%-- 显示分页信息 --%><div class="row"><%--分页条信息--%><div class="col-md-6 col-md-offset-3 text-center" id="page_info_area"></div></div><div class="row"><%--分页文字信息 --%><div class="col-md-6 col-md-offset-3 text-center" id="page_nav_area"></div></div></div>
<script type="text/javascript">/* ================================================ 全局变量 ================================================ */var totalRecord; // 用于跳转到末页var isTheUsernameCorrect = false // 用户名是否正确var isTheEmailAddressCorrect = false // 邮箱是否正确/* ================================================ 函数 ================================================ */// 初始化页面时需要调用的函数$(function () {// 去首页to_page(1);});// 页面跳转函数function to_page(pn) {$.ajax({url: "${APP_PATH}/emps",data: "pn=" + pn,type: "GET",success: function (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 empIdTd = $("<td></td>").append(item.empId);var empNameTd = $("<td></td>").append(item.empName)var genderTd = $("<td></td>").append(item.empGender == "M" ? "男" : "女")var emailTd = $("<td></td>").append(item.empEmail)var deptNameTd = $("<td></td>").append(item.department.deptName)// 注入按钮数据var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);$("<tr></tr>").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()$("#page_info_area").append("当前页:" +result.extend.pageInfo.pageNum + ",总页数:" +result.extend.pageInfo.pages + ",总记录数:" +result.extend.pageInfo.total)totalRecord = result.extend.pageInfo.total}// 解析显示分页条函数function build_page_nav(result) {// 清空原来的分页码$("#page_nav_area").empty();// 构建元素var ul = $("<ul></ul>").addClass("pagination")var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;").attr("href", "#"));var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;").attr("href", "#"));var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));// 添加首页、末页、上一页、下一页禁用 和跳转功能if (result.extend.pageInfo.hasPreviousPage == false) {firstPageLi.addClass("disabled")prePageLi.addClass("disabled")} else {firstPageLi.click(function () {to_page(1)})prePageLi.click(function () {to_page(result.extend.pageInfo.pageNum - 1)})}if (result.extend.pageInfo.hasNextPage == false) {nextPageLi.addClass("disabled");lastPageLi.addClass("disabled");} else {lastPageLi.click(function () {to_page(result.extend.pageInfo.pages);});nextPageLi.click(function () {to_page(result.extend.pageInfo.pageNum + 1);});}// 添加首页和前一页ul.append(firstPageLi).append(prePageLi)// 构建条码$.each(result.extend.pageInfo.navigatepageNums, function (index, num) {var numLi = $("<li></li>").append($("<a></a>").append(num).attr("href", "#"));// 设置当前页码高亮显示if (result.extend.pageInfo.pageNum == num) {numLi.addClass("active")}// 添加按钮跳转事件numLi.click(function () {to_page(num)})ul.append(numLi)});// 添加末页和后一页ul.append(nextPageLi).append(lastPageLi)var navEle = $("<nav></nav>").append(ul)navEle.appendTo("#page_nav_area");}// 查询所有部门信息请求函数function getDepts() {$.ajax({url: "${APP_PATH}/depts",type: "GET",success: function (result) {console.log(result)$.each(result.extend.depts, function () {var optionElement = $("<option></option>").append(this.deptName).attr("value", this.deptId)optionElement.appendTo("#deptId_add_select")})}})}// 添加员工表单数据校验信息显示函数function validate_add_from_information_show(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 if ("error" == status) {$(ele).parent().addClass("has-error")$(ele).next("span").text(msg)}}// 重置添加员工表单数据和样式function reset_form(ele) {// 清空表单数据$(ele + " form")[0].reset()// 清空表单样式$(ele + " form").find("*").removeClass("has-success has-error")$(ele + " form").find(".help-block").text("")// 清空下拉列表$(ele + " select").empty()}/* ============================================== 按钮绑定事件区 ============================================== */// 添加员工按钮事件$("#emp_add_modal_btn").click(function () {// 表单重置数据reset_form("#empAddModal")// 发送Ajax请求, 查出部门信息,显示在下拉列表中getDepts()$("#empAddModal").modal({backdrop: "static"})})// 模态框保存按钮点击事件$("#saveEmpBtn").click(function () {// 校验表单数据if (!isTheUsernameCorrect || !isTheEmailAddressCorrect) {return false}// 发送保存请求$.ajax({url: "${APP_PATH}/emp",type: "POST",data: $("#empAddModal form").serialize(),success: function (result) {if(result.code == 100) {// 员工保存成功// 1. 关闭模态框$("#empAddModal").modal('hide')// 2. 跳转到最后一页显示to_page(totalRecord)} else {// 显示失败信息if(undefined != result.extend.errorFields.empEmail){validate_add_from_information_show("#empEmail_add_input", "error", "邮箱格式不正确")}if(undefined != result.extend.errorFields.empName){validate_add_from_information_show("#empName_add_input", "error", "员工名称格式不正确")}}}})})// 用户名栏失去焦点时进行格式检查$("#empName_add_input").blur(function () {var empName = $("#empName_add_input").val();var regName = /(^[a-zA-Z0-9_-]{3,16}$)|(^[\u2E80-\u9FFF]{2,5})/ // 允许英文和中文if(!regName.test(empName)){validate_add_from_information_show("#empName_add_input", "error", "员工名称格式不正确")} else {validate_add_from_information_show("#empName_add_input", "success", "")isTheUsernameCorrect = true}})// 邮箱栏失去焦点时进行格式检查和重复检查$("#empEmail_add_input").blur(function () {var empEmail = $("#empEmail_add_input").val()var regEmail = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/if(!regEmail.test(empEmail)){validate_add_from_information_show("#empEmail_add_input", "error", "邮箱格式不正确")}// 发送Ajax请求判断邮箱是否重复$.ajax({url:"${APP_PATH}/checkEmail",data:"empEmail=" + empEmail,type:"GET",  // get请求不检验中文,如果发送对象中含中文则用POSTsuccess:function (result) {console.log(result)if(result.code == 100 && regEmail.test(empEmail)) {validate_add_from_information_show("#empEmail_add_input", "success", "")isTheEmailAddressCorrect = true} else if (result.code == 200) {validate_add_from_information_show("#empEmail_add_input", "error", "邮箱已存在")}}})})</script>
</body>
</html>

六、修改员工信息功能

步骤:

  1. 点击编辑
  2. 弹出用户修改的模态框(显示用户信息)
  3. 点击更新,完成用户修改

1、编写修改模态框

<%-- 修改员工模态框 --%>
<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" id="updateModalLabel">修改员工</h4></div><div class="modal-body"><%-- 表单 --%><form class="form-horizontal"><div class="form-group"><label for="empName_add_input" class="col-sm-2 control-label">empName</label><div class="col-sm-10"><input name="empName" type="text" class="form-control" id="empName_update_input"placeholder="empName"><span class="help-block"></span></div></div><div class="form-group"><label for="empEmail_add_input" class="col-sm-2 control-label">Email</label><div class="col-sm-10"><input name="empEmail" type="text" class="form-control" id="empEmail_update_input"placeholder="empEmail"><span class="help-block"></span></div></div><div class="form-group"><label class="col-sm-2 control-label">empGender</label><div class="col-sm-10"><label class="radio-inline"><input type="radio" name="empGender" id="empGender_update_input" value="M" checked="checked"> 男</label><label class="radio-inline"><input type="radio" name="empGender" id="empGender_update_input2" value="F"> 女</label></div></div><div class="form-group"><label class="col-sm-2 control-label">deptId</label><div class="col-sm-4"><select class="form-control" name="deptId" id="deptId_update_select"></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="updateEmpBtn">更新</button></div></div></div>
</div>

2、添加按钮样式

给员工列表的修改和删除按钮添加样式:edit_btn、del_btn

// 注入按钮数据
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm del_btn").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");

3、修改重置表单函数

新增下拉列表的重置

// 重置添加员工表单数据和样式
function reset_form(ele) {// 清空表单数据$(ele + " form")[0].reset()// 清空表单样式$(ele + " form").find("*").removeClass("has-success has-error")$(ele + " form").find(".help-block").text("")// 清空下拉列表$(ele + " select").empty()
}

4、编辑按钮事件

// 为修改员工按钮添加事件
// 因为是先绑定事件后在生成的按钮,所以不能用click
// 早先版本的jQuery可以使用live方法
// 这里使用 on 方法绑定
$(document).on("click", ".edit_btn", function () {// 1. 查询部门信息显示getDepts("#deptId_update_select")// 2. 回显员工信息// 3. 跳出模态框$("#empUpdateModal").modal({backdrop: "static"})
})

5、回显用户数据

5.1、编写控制器方法

/*** 根据id查询员工信息* @param id 页面传入的id* @return 员工对象的JSON数据*/
@RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
@ResponseBody
public Msg getEmpById(@PathVariable("id")Integer id) {Employee emp = employeeService.getEmpById(id);return Msg.success().add("emp", emp);
}

5.2、编写Service层方法

public Employee getEmpById(Integer id) {return employeeMapper.selectByPrimaryKey(id);
}

5.3、网页查询员工信息函数

// 根据id查询员工信息函数
function getEmpById(id) {$.ajax({url:"${APP_PATH}/emp/" + id,type:"GET",success:function (result) {console.log(result)}})
}

5.4、为修改员工按钮添加属性

在定义editBtn按钮之后添加empId属性,用于修改员工时传递id值

// 添加自定义属性,用于修改员工时传递id值
editBtn.attr("empId_for_edit", item.empId)

5.5、回显员工信息函数

这里传入的是部门id,而回显的是部门名称的原因:

  1. val() 方法返回或设置被选元素的值。元素的值是通过 value 属性设置的。该方法大多用于 input 元素。
  2. 查询部门信息时,value属性定义的是id,显示的是部门名,页面根据传入的id值选择了相应的部门名
// 根据id查询员工信息函数
function getEmpById(id) {$.ajax({url:"${APP_PATH}/emp/" + id,type:"GET",success:function (result) {var empData = result.extend.empty;$("#empName_update_input").val(empData.empName);$("#empEmail_update_input").val(empData.empEmail);$("#empUpdateModal input[name=empGender]").val(empData.empGender);$("#empUpdateModal select").val(empData.deptId);}})
}

5.6、完善修改按钮事件

// 为修改员工按钮添加事件
// 因为是先绑定事件后在生成的按钮,所以不能用click
// 早先版本的jQuery可以使用live方法
// 这里使用 on 方法绑定
$(document).on("click", ".edit_btn", function () {// 1. 查询部门信息显示getDepts("#deptId_update_select")// 2. 回显员工信息getEmpById($(this).attr("empId_for_edit"))// 3. 跳出模态框$("#empUpdateModal").modal({backdrop: "static"})
})

6、更新按钮事件

步骤:

  1. 绑定更新按钮事件
  2. 前端校验用户名和邮箱格式
  3. 将编辑按钮的id属性传递给更新按钮
  4. 前端发送Ajax请求更新员工数据
  5. 编写更新员工控制器
  6. 编写更新员工Service方法

6.1、控制器方法

注意事项

@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)

上述代码里的 {empId} ,大括号中的名称必须和对象类的属性名相同

如果直接使用ajax=PUT的请求

存在问题:

  • 请求体中有数据,但是Employee对象封装属性失败

原因:

  • Tomcat将请求体中的数据封装为一个map,SpringMVC封装POJO对象的时候,底层使用request.getParameter(“empName”) 从map中取值
  • Tomcat不会封装请求体中的数据为map,只有POST请求才会封装成map

request和connector原码:

org.apache.catalina.connector.Request--parseParameters()
(3111);protected String parseBodyMethods = "POST";if( !getConnector().isParseBodyMethod(getMethod()) ) {success = true;return;
}
/*** 根据id更新员工信息* @param employee 页面传来的员工数据* @param result 校验结果* @return 校验信息*/
@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
@ResponseBody
public Msg updateEmpById(@Valid Employee employee, BindingResult result) {if (result.hasErrors()) {Map<String, Object> map = new HashMap<>();List<FieldError> errors = result.getFieldErrors();for (FieldError error : errors) {System.out.println("错误的字段名:" + error.getField());System.out.println("错误信息:" + error.getDefaultMessage());map.put(error.getField(), error.getDefaultMessage());}return Msg.fail().add("errorFields", map);} else {employeeService.updateEmpById(employee);return Msg.success();}
}

6.2、Service层方法

/*** 根据id更新员工数据* @param employee 页面传来的员工数据*/
public void updateEmpById(Employee employee) {employeeMapper.updateByPrimaryKey(employee);
}

6.3、修改编辑按钮事件

将编辑按钮的id属性传递给更新按钮

// 为修改员工按钮添加事件
// 因为是先绑定事件后在生成的按钮,所以不能用click
// 早先版本的jQuery可以使用live方法
// 这里使用 on 方法绑定
$(document).on("click", ".edit_btn", function () {// 1. 查询部门信息显示getDepts("#deptId_update_select")// 2. 回显员工信息getEmpById($(this).attr("empId_for_edit"))// 3. 传递id給更新按钮$("#updateEmpBtn").attr("empId_for_edit", $(this).attr("empId_for_edit"))// 4. 跳出模态框$("#empUpdateModal").modal({backdrop: "static"})
})

6.4、使用PUT发送请求

在web.xml设置 HttpPutFormContentFilter

作用:

  1. 将请求体中的数据解析包装成一个map
  2. request重新被包装,request.getParameter()被重写,就会从自己封装的map中获取数据
<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>

七、删除员工

1、控制器方法

/*** 根据id删除对应的员工数据* @return 删除是否成功*/
@RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE)
@ResponseBody
public Msg deleteEmp(@PathVariable("id")String id) {String[] ids = id.split("-");List<Integer> idList = new ArrayList<>();for (String s : ids) {idList.add(Integer.valueOf(s));}if (idList.size() == 1) {employeeService.deleteEmpById(idList.get(0));} else {employeeService.deleteBatch(idList);}return Msg.success();
}

2、Srevice方法

删除单个员工

/*** 根据id删除员工* @param id 页面传入的id*/
public void deleteEmpById(Integer id) {employeeMapper.deleteByPrimaryKey(id);
}

删除多个员工

/*** 删除对应列表里id的员工* @param idList id列表*/
public void deleteBatch(List<Integer> idList) {EmployeeExample employeeExample = new EmployeeExample();EmployeeExample.Criteria criteria = employeeExample.createCriteria();criteria.andEmpIdIn(idList);employeeMapper.deleteByExample(employeeExample);
}

3. 添加选择按钮

全选按钮:

<tr><th><input type="checkbox" id="check_all"/></th><th>#</th><th>empName</th><th>gender</th><th>email</th><th>deptName</th><th>操作</th>
</tr>

选项按钮:

$.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 genderTd = $("<td></td>").append(item.empGender == "M" ? "男" : "女")var emailTd = $("<td></td>").append(item.empEmail)var deptNameTd = $("<td></td>").append(item.department.deptName)// 注入按钮数据var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");// 添加自定义属性,用于修改员工时传递id值editBtn.attr("empId_for_edit", item.empId)var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm del_btn").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);$("<tr></tr>").append(checkBoxTd).append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd).append(btnTd).appendTo("#emps_table tbody");
});

4、绑定选择按钮事件

全选按钮绑定事件

// 全选按钮绑定事件
$("#check_all").click(function () {// attr获取checked属性时undefined// dom原生的属性需要用prop获取,attr获取自定义的属性$(".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)
})

4、删除单个员工按钮事件

// 单个删除按钮事件
$(document).on("click", ".del_btn", function (){var empName = $(this).parents("tr").find("td:eq(2)").text()var empId = $(this).parents("tr").find("td:eq(1)").text()if(confirm("确认删除【" + empName + "】吗?")) {// 确认则发送Ajax请求$.ajax({url:"${APP_PATH}/emp/" + empId,type:"DELETE",success:function (result) {console.log(result)// 刷新页面to_page(currentPage)}})}
})

5、删除全部员工按钮事件

添加删除所有员工按钮id

<button class="btn btn-danger" id="delete_all_emp_btn"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除
</button>

绑定按钮事件

// 删除全部选中员工按钮事件
$("#delete_all_emp_btn").click(function () {var empIds = ""alert("dqwdfa")$.each($(".check_item:checked"), function () {empIds += $(this).parents("tr").find("td:eq(1)").text() + "-"})// 删除最后一个 "-"empIds.substring(0, empIds.length-1)if(confirm("确认删除所有员工吗?")) {$.ajax({url:"${APP_PATH}/emp/" + empIds,type:"DELETE",success:function (result) {console.log(result)to_page(currentPage)// 重置全选按钮为未选中状态$("#check_all").prop("checked", false)}})}
})

九、最终index页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>员工列表</title><%pageContext.setAttribute("APP_PATH", request.getContextPath());%><!-- web路径:不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名http://localhost:3306/crud--><script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script><script src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script><link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<%-- 添加员工模态框 --%>
<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 for="empName_add_input" class="col-sm-2 control-label">empName</label><div class="col-sm-10"><input name="empName" type="text" class="form-control" id="empName_add_input"placeholder="empName"><span class="help-block"></span></div></div><div class="form-group"><label for="empEmail_add_input" class="col-sm-2 control-label">Email</label><div class="col-sm-10"><input name="empEmail" type="text" class="form-control" id="empEmail_add_input"placeholder="empEmail"><span class="help-block"></span></div></div><div class="form-group"><label class="col-sm-2 control-label">empGender</label><div class="col-sm-10"><label class="radio-inline"><input type="radio" name="empGender" id="empGender_add_input" value="M" checked="checked"> 男</label><label class="radio-inline"><input type="radio" name="empGender" id="empGender_add_input2" value="F"> 女</label></div></div><div class="form-group"><label class="col-sm-2 control-label">deptId</label><div class="col-sm-4"><select class="form-control" name="deptId" id="deptId_add_select"></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="saveEmpBtn">保存</button></div></div></div>
</div><%-- 修改员工模态框 --%>
<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" id="updateModalLabel">修改员工</h4></div><div class="modal-body"><%-- 表单 --%><form class="form-horizontal"><div class="form-group"><label for="empName_add_input" class="col-sm-2 control-label">empName</label><div class="col-sm-10"><input name="empName" type="text" class="form-control" id="empName_update_input"placeholder="empName"><span class="help-block"></span></div></div><div class="form-group"><label for="empEmail_add_input" class="col-sm-2 control-label">Email</label><div class="col-sm-10"><input name="empEmail" type="text" class="form-control" id="empEmail_update_input"placeholder="empEmail"><span class="help-block"></span></div></div><div class="form-group"><label class="col-sm-2 control-label">empGender</label><div class="col-sm-10"><label class="radio-inline"><input type="radio" name="empGender" id="empGender_update_input" value="M" checked="checked"> 男</label><label class="radio-inline"><input type="radio" name="empGender" id="empGender_update_input2" value="F"> 女</label></div></div><div class="form-group"><label class="col-sm-2 control-label">deptId</label><div class="col-sm-4"><select class="form-control" name="deptId" id="deptId_update_select"></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="updateEmpBtn">更新</button></div></div></div>
</div><%-- 搭建显示页面 --%>
<div class="container"><%-- 标题 --%><div class="row"><div class="col-md-12"><h1>SSM_CRUD</h1></div></div><%-- 按钮 --%><div class="row"><div class="col-md-2 col-md-offset-10"><button class="btn btn-primary" id="emp_add_modal_btn"><span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>添加</button><button class="btn btn-danger" id="delete_all_emp_btn"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除</button></div></div><%-- 显示表格数据 --%><div class="row"><div class="col-md-12"><table class="table table-striped" id="emps_table"><thead><tr><th><input type="checkbox" id="check_all"/></th><th>#</th><th>empName</th><th>gender</th><th>email</th><th>deptName</th><th>操作</th></tr></thead><tbody><%-- 通过函数加载数据 --%></tbody></table></div></div><%-- 显示分页信息 --%><div class="row"><%--分页条信息--%><div class="col-md-6 col-md-offset-3 text-center" id="page_info_area"></div></div><div class="row"><%--分页文字信息 --%><div class="col-md-6 col-md-offset-3 text-center" id="page_nav_area"></div></div></div>
<script type="text/javascript">/* ================================================ 全局变量 ================================================ */var totalRecord; // 用于跳转到末页var currentPage // 用于完成请求后刷新页面/* ================================================ 函数 ================================================ */// 初始化页面时需要调用的函数$(function () {// 去首页to_page(1);});// 页面跳转函数function to_page(pn) {$.ajax({url: "${APP_PATH}/emps",data: "pn=" + pn,type: "GET",success: function (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 genderTd = $("<td></td>").append(item.empGender == "M" ? "男" : "女")var emailTd = $("<td></td>").append(item.empEmail)var deptNameTd = $("<td></td>").append(item.department.deptName)// 注入按钮数据var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn").append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");// 添加自定义属性,用于修改员工时传递id值editBtn.attr("empId_for_edit", item.empId)var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm del_btn").append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);$("<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()$("#page_info_area").append("当前页:" +result.extend.pageInfo.pageNum + ",总页数:" +result.extend.pageInfo.pages + ",总记录数:" +result.extend.pageInfo.total)totalRecord = result.extend.pageInfo.totalcurrentPage = result.extend.pageInfo.pageNum}// 解析显示分页条函数function build_page_nav(result) {// 清空原来的分页码$("#page_nav_area").empty();// 构建元素var ul = $("<ul></ul>").addClass("pagination")var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;").attr("href", "#"));var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;").attr("href", "#"));var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));// 添加首页、末页、上一页、下一页禁用 和跳转功能if (result.extend.pageInfo.hasPreviousPage == false) {firstPageLi.addClass("disabled")prePageLi.addClass("disabled")} else {firstPageLi.click(function () {to_page(1)})prePageLi.click(function () {to_page(result.extend.pageInfo.pageNum - 1)})}if (result.extend.pageInfo.hasNextPage == false) {nextPageLi.addClass("disabled");lastPageLi.addClass("disabled");} else {lastPageLi.click(function () {to_page(result.extend.pageInfo.pages);});nextPageLi.click(function () {to_page(result.extend.pageInfo.pageNum + 1);});}// 添加首页和前一页ul.append(firstPageLi).append(prePageLi)// 构建条码$.each(result.extend.pageInfo.navigatepageNums, function (index, num) {var numLi = $("<li></li>").append($("<a></a>").append(num).attr("href", "#"));// 设置当前页码高亮显示if (result.extend.pageInfo.pageNum == num) {numLi.addClass("active")}// 添加按钮跳转事件numLi.click(function () {to_page(num)})ul.append(numLi)});// 添加末页和后一页ul.append(nextPageLi).append(lastPageLi)var navEle = $("<nav></nav>").append(ul)navEle.appendTo("#page_nav_area");}// 查询所有部门信息请求函数function getDepts(ele) {$.ajax({url: "${APP_PATH}/depts",type: "GET",success: function (result) {console.log(result)$.each(result.extend.depts, function () {var optionElement = $("<option></option>").append(this.deptName).attr("value", this.deptId)optionElement.appendTo(ele)})}})}// 添加员工表单数据校验信息显示函数function validate_add_from_information_show(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 if ("error" == status) {$(ele).parent().addClass("has-error")$(ele).next("span").text(msg)}}// 重置添加员工表单数据和样式function reset_form(ele) {// 清空表单数据$(ele + " form")[0].reset()// 清空表单样式$(ele + " form").find("*").removeClass("has-success has-error")$(ele + " form").find(".help-block").text("")// 清空下拉列表$(ele + " select").empty()}// 根据id查询员工信息函数function getEmpById(id) {$.ajax({url:"${APP_PATH}/emp/" + id,type:"GET",success:function (result) {var empData = result.extend.emp;console.log(result)$("#empName_update_input").val(empData.empName);$("#empEmail_update_input").val(empData.empEmail);$("#empUpdateModal input[name=empGender]").val(empData.empGender);$("#empUpdateModal select").val(empData.deptId);}})}// 校验用户名函数function verifyUsername(ele) {var empName = $(ele).val();var regName = /(^[a-zA-Z0-9_-]{3,16}$)|(^[\u2E80-\u9FFF]{2,5})/ // 允许英文和中文if(!regName.test(empName)){validate_add_from_information_show(ele, "error", "员工名称格式不正确")return false} else {validate_add_from_information_show(ele, "success", "")return true}}// 校验邮箱格式函数function checkMailbox(ele) {var empEmail = $(ele).val()var regEmail = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/if(!regEmail.test(empEmail)){validate_add_from_information_show(ele, "error", "邮箱格式不正确")return false}var isTheEmailAddressCorrect = false// 发送Ajax请求判断邮箱是否重复$.ajax({url:"${APP_PATH}/checkEmail",data:"empEmail=" + empEmail,type:"GET",  // get请求不检验中文,如果发送对象中含中文则用POSTasync:false, // 设置Ajax为同步success:function (result) {console.log(result)if(result.code === 100 && regEmail.test(empEmail)) {validate_add_from_information_show(ele, "success", "")isTheEmailAddressCorrect = true} else if (result.code === 200) {validate_add_from_information_show(ele, "error", "邮箱已存在")isTheEmailAddressCorrect = false}}})return isTheEmailAddressCorrect;}/* ============================================== 按钮绑定事件区 ============================================== */// 添加员工按钮事件$("#emp_add_modal_btn").click(function () {// 表单重置数据reset_form("#empAddModal")// 发送Ajax请求, 查出部门信息,显示在下拉列表中getDepts("#deptId_add_select")$("#empAddModal").modal({backdrop: "static"})})// 模态框保存按钮点击事件$("#saveEmpBtn").click(function () {// 校验表单数据if (!verifyUsername("#empName_add_input") || !checkMailbox("#empEmail_add_input")) {return false}// 发送保存请求$.ajax({url: "${APP_PATH}/emp",type: "POST",data: $("#empAddModal form").serialize(),success: function (result) {console.log(result)if(result.code === 100) {// 员工保存成功// 1. 关闭模态框$("#empAddModal").modal('hide')// 2. 跳转到最后一页显示to_page(totalRecord)} else {// 显示失败信息if(undefined !== result.extend.errorFields.empEmail){validate_add_from_information_show("#empEmail_add_input", "error", "邮箱格式不正确")}if(undefined !== result.extend.errorFields.empName){validate_add_from_information_show("#empName_add_input", "error", "员工名称格式不正确")}}}})})// 为修改员工按钮添加事件// 因为是先绑定事件后在生成的按钮,所以不能用click// 早先版本的jQuery可以使用live方法// 这里使用 on 方法绑定$(document).on("click", ".edit_btn", function () {// 1. 查询部门信息显示getDepts("#deptId_update_select")// 2. 回显员工信息getEmpById($(this).attr("empId_for_edit"))// 3. 传递id給更新按钮$("#updateEmpBtn").attr("empId_for_edit", $(this).attr("empId_for_edit"))// 4. 跳出模态框$("#empUpdateModal").modal({backdrop: "static"})})// 绑定更新按钮单击事件$("#updateEmpBtn").click(function () {// 1. 校验表单数据if (!verifyUsername("#empName_update_input") || !checkMailbox("#empEmail_update_input")) {return false}// 2. 发送更新的Ajax请求$.ajax({url:"${APP_PATH}/emp/" + $(this).attr("empId_for_edit"),type:"PUT",data:$("#empUpdateModal form").serialize(),success:function (result) {console.log(result)if(result.code === 100) {// 员工更新成功// 1. 关闭模态框$("#empUpdateModal").modal('hide')// 2. 刷新页面to_page(currentPage)} else {// 显示失败信息if(undefined !== result.extend.errorFields.empEmail){validate_add_from_information_show("#empEmail_update_input", "error", "邮箱格式不正确")}if(undefined !== result.extend.errorFields.empName){validate_add_from_information_show("#empName_update_input", "error", "员工名称格式不正确")}}}})})// 单个删除按钮事件$(document).on("click", ".del_btn", function (){var empName = $(this).parents("tr").find("td:eq(2)").text()var empId = $(this).parents("tr").find("td:eq(1)").text()if(confirm("确认删除【" + empName + "】吗?")) {// 确认则发送Ajax请求$.ajax({url:"${APP_PATH}/emp/" + empId,type:"DELETE",success:function (result) {console.log(result)// 刷新页面to_page(currentPage)}})}})// 全选按钮绑定事件$("#check_all").click(function () {// attr获取checked属性时undefined// dom原生的属性需要用prop获取,attr获取自定义的属性$(".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)})// 删除全部选中员工按钮事件$("#delete_all_emp_btn").click(function () {var empIds = ""$.each($(".check_item:checked"), function () {empIds += $(this).parents("tr").find("td:eq(1)").text() + "-"})// 删除最后一个 "-"empIds.substring(0, empIds.length-1)if(confirm("确认删除所有员工吗?")) {$.ajax({url:"${APP_PATH}/emp/" + empIds,type:"DELETE",success:function (result) {console.log(result)to_page(currentPage)// 重置全选按钮为未选中状态$("#check_all").prop("checked", false)}})}})</script>
</body>
</html>

尚硅谷ssm整合实战项目笔记相关推荐

  1. 尚硅谷SSM高级整合

    2020.12.5–尚硅谷SSM高级整合 写在前面:本人是看完框神ssm框架系列,然后找的其他的ssm整合的资源来练手的,这个尚硅谷的是用eclipse写的,我觉得可以接受就练习了,需要资源的可以私信 ...

  2. 风云叱咤,尚硅谷云原生实战教程(下篇)发布

    摘要:企业级容器云实战,真正实现云上亿级流量永不宕机! 若逢新雪初霁,满月当空. 他带笑向我们走来, 月色与雪色间,他是第三种绝色. 他浑身上下都是宝, 上知天文,下晓地理,中通人和, 他就是我们的老 ...

  3. Vue数据代理+事件处理+事件修饰符的作用+计算属性的使用,尚硅谷Vue系列教程学习笔记(2)

    尚硅谷Vue系列教程学习笔记(2) 参考课程:<尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通> 参考链接:https://www.bilibili.com/video/ ...

  4. SSM整合APP项目

    SSM整合APP项目 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Ma ...

  5. UNIAPP实战项目笔记43 购物车页面修改收货地址和修改默认地址

    UNIAPP实战项目笔记43 购物车页面修改收货地址和修改默认地址 实际案例图片 修改收货地址和修改默认地址页面布局和功能 具体内容图片自己替换哈,随便找了个图片的做示例 用到了vuex的状态机,具体 ...

  6. UNIAPP实战项目笔记28 商品分享功能点分享按钮分享到微信好友

    UNIAPP实战项目笔记28 商品分享功能点分享按钮分享到微信好友 detail.vue 加生命周期 // 点击分享onNavigationBarButtonTap(e) {if(e.type===' ...

  7. 【学习笔记】尚硅谷Hadoop大数据教程笔记

    本文是尚硅谷Hadoop教程的学习笔记,由于个人的需要,只致力于搞清楚Hadoop是什么,它可以解决什么问题,以及它的原理是什么.至于具体怎么安装.使用和编写代码不在我考虑的范围内. 一.Hadoop ...

  8. UNIAPP实战项目笔记57 发送手机验证码 接入短信SDK

    UNIAPP实战项目笔记57 发送手机验证码 接入短信SDK 注册时候需要发送验证 通过验阿里云或腾讯云等短信sdk供应商 实际案例图片 后端接口文件 index.js var express = r ...

  9. UNIAPP实战项目笔记45 订单页面布局完成和数据渲染

    UNIAPP实战项目笔记45 订单页面布局完成和数据渲染 实际案例图片 订单页面 具体内容图片自己替换哈,随便找了个图片的做示例 具体位置见目录结构 通过 模拟数据list 来实现数据渲染 完善布局页 ...

  10. 尚硅谷_HTML5 核心 实战 笔记

    目录 序 offsetParent & offsetLeft & offsetTop 获取绝对位置和相对位置 自定义的函数 getBoundingClientRect offsetWi ...

最新文章

  1. 在原神里钓鱼,有人竟然用上了深度强化学习,还把它开源了
  2. 《统一沟通-微软-技巧》-14-Exchange 2010 With SP1 OWA Integration
  3. winform 转 JAVA_C#转java
  4. cookie+memcached实现单点登陆
  5. 俺的新书《Sencha Touch实战》终于出版了
  6. 对于Eclipse的正确用法
  7. android 之 百度地图
  8. linux+平均磁盘请求数量_Linux 查看磁盘IO并找出占用IO读写很高的进程
  9. 小米华为鸿蒙,华为鸿蒙比小米MIUI快,老外上手出结果
  10. Jmeter安装TPS插件
  11. ImageButton
  12. 一个字由两个字节组成
  13. Web前端开发的项目开发流程
  14. WEB前端开发学习5大网站,你用过几个?
  15. 蚂蚁金服校招一面有感
  16. html游戏官网界面设计教程,【ideas】游戏官网我们到底应该设计什么?
  17. 解决FileReader读取文本文件中字乱码问题
  18. AI初学者必看的4个顶级人工智能领域岗位
  19. linux md文件 编辑,用Vim写md文档的简单姿势
  20. QQ表情里的股市晴雨表

热门文章

  1. 让对应背景随着轮播的图片变化而改变
  2. Scan2CAD pro中文版
  3. python高级用法使用手册(收藏)
  4. OpenCms登录添加验证码功能
  5. 中国互联网的N个第一
  6. Radius认证协议(一)
  7. Android路由器初始密码,了解路由器用户名和万能密码
  8. 软件架构师的12项修炼
  9. JAVA经纬度互转、计算工具类
  10. 轻松打造企业内部NOD32升级服务器