SSM整合项目

  • 项目简介
    • 主要实现的功能
    • 涉及的技术
    • 最终效果图
  • 一、搭建环境
    • 1. 添加依赖,打包方式为 war
    • 2. 创建webapp目录,添加web.xml
    • 3. 配置tomcat服务器
    • 4. 引入 BootStrap 前端框架
    • 5. 引入jquery
  • 二、整合SSM
    • 1. 配置web.xml
    • 2. 配置application.xml
    • 3. 配置spring-mvc.xml
    • 4. 配置mybatis-config.xml
    • 5. 创建数据库表
    • 6. Mybatis 逆向工程
    • 7. 项目完整的结构
    • 8. Spring 整合 Junit 4测试 Mapper 添加数据
  • 三、规定RESTful 风格的URI
  • 四、创建index.jsp
  • 五、查询
    • 1. 需要实现的功能
    • 2. controller
    • 3. service
    • 4. spring 整合 Junit 4测试 MVC
    • 5. 添加 Msg 类引入链式编程
    • 6. 修改 controller
    • 7. 补充前端代码,采用Ajax发送请求
    • 8. 效果
  • 六、新增数据
    • 1. 需要实现的功能
    • 2. 添加模态框
    • 3 查询部门列表
    • 4. jQuery 前端校验格式
    • 5. Ajax 校验用户名是否重复
    • 6. 后端校验 + 保存
    • 7. 效果
  • 七、修改数据
    • 1. 需要实现的功能
    • 2. 添加模态框
    • 3. 获取要修改的员工信息
    • 4. 保存员工信息
    • 5. 效果
  • 八、删除数据
    • 1. 需要实现的功能
    • 2. Controller
    • 3. Service
    • 4. 单个删除
    • 5. 批量删除
    • 6. 效果
  • 九、项目总结

项目简介

使用 SSM 框架搭建出一套简单的 CRUD 项目示例,主要涉及两张表:员工表和部门表,其中每个员工都对应一个部门

主要实现的功能

1、分页查询所有员工信息并展示列表。

2、添加一条员工的信息。

3、新增数据需要校验:

  • jQuery 前端校验用户名和邮箱是否合法。
  • Ajax 请求校验用户名是否重复。
  • JSR 303 后端校验用户名、邮箱是否合法以及用户名是否重复。

4、编辑修改某条员工的信息。

5、删除某条员工的信息,批量删除所选员工的信息。

6、RESTful 风格的URI。

涉及的技术

1、后端框架:SSM(Spring 5 + Spring MVC + MyBatis 3)+ Maven 3.6.3

2、MyBatis 分页插件:PageHelper

3、MyBatis 逆向工程:MyBatis Generator

4、数据库:MySQL 5.7 + Druid 数据库连接池

5、前端框架:BootStrap 5

最终效果图

一、搭建环境

1. 添加依赖,打包方式为 war

<packaging>war</packaging><dependencies><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.0.0</version></dependency><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.5</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.3.7.RELEASE</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.8</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.4.1.Final</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.3.7.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.7.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>4.3.7.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.2</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.7</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.41</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies><build><plugins><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><dependencies><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.7</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.41</version></dependency></dependencies></plugin></plugins></build>

2. 创建webapp目录,添加web.xml

注意路径:\src\main\webapp\web.xml

3. 配置tomcat服务器

4. 引入 BootStrap 前端框架

Bootstrap 官网:https://getbootstrap.com/,图标资源官网:https://icons.getbootstrap.com/

中文第3版Bootstrap的学习资料:https://v3.bootcss.com/getting-started/

5. 引入jquery

二、整合SSM

1. 配置web.xml

<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"><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><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><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><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>

2. 配置application.xml

Spring 的配置文件,主要配置业务逻辑相关的内容:数据源、与MyBatis的整合、事务控制等。

(1)先创建一个 dbconfig.properties,用来保存数据库驱动的配置信息

jdbc.url=jdbc:mysql://localhost:3306/ssm_crudjdbc.driver=com.mysql.jdbc.Driverjdbc.username=rootjdbc.password=123456

(2)在配置文件中进行配置

<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.study.ssm"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><context:property-placeholder location="classpath:dbconfig.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"></property><property name="driverClassName" value="${jdbc.driver}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="configLocation" value="classpath:mybatis-config.xml"></property><property name="mapperLocations" value="classpath:com/study/ssm/dao/*.xml"></property></bean><bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg><constructor-arg name="executorType" value="BATCH"></constructor-arg></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.study.ssm.dao"></property></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><aop:config><aop:pointcut id="txPoint" expression="execution(* com.study.ssm.service..*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor></aop:config><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*"/><tx:method name="get*" read-only="true"/></tx:attributes></tx:advice></beans>

3. 配置spring-mvc.xml

Spring MVC 的配置文件,主要包含网站跳转逻辑的控制、配置。

<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"><context:component-scan base-package="com.study.ssm" 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/js/"></property><property name="suffix" value=".jsp"></property></bean><mvc:default-servlet-handler/><mvc:annotation-driven/></beans>

4. 配置mybatis-config.xml

<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings><typeAliases><package name="com.study.ssm.bean"/></typeAliases><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><property name="reasonable" value="true"/></plugin></plugins></configuration>

5. 创建数据库表

CREATE TABLE `tbl_emp` (`emp_id` int(11)PRIMARY KEY AUTO_INCREMENT NOT NULL,`emp_name` varchar(255) DEFAULT NULL,`gender` char(1) DEFAULT NULL,`email` varchar(255) DEFAULT NULL,`d_id` int(11) DEFAULT NULL,FOREIGN KEY (d_id) REFERENCES tbl_dept(dept_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `tbl_dept` (`dept_id` int(11) PRIMARY KEY AUTO_INCREMENT NOT NULL,`dept_name` varchar(255) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;

6. Mybatis 逆向工程

(1)配置 generatorConfig.xml 逆向工程配置文件(必须叫这名)

<!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.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/ssm_crud" userId="root"password="123456"></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><javaModelGenerator targetPackage="com.study.ssm.bean"targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!--  的 targetPackage属性 最好与  的targetPackage属性一致--><sqlMapGenerator targetPackage="com/study/ssm/dao" targetProject=".\src\main\resources"><property name="enableSubPackages" value="true" /></sqlMapGenerator><javaClientGenerator type="XMLMAPPER" targetPackage="com.study.ssm.dao" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><table tableName="tbl_emp" domainObjectName="Employee"></table><table tableName="tbl_dept" domainObjectName="Department"></table></context></generatorConfiguration>

(2)使用逆向工程插件

7. 项目完整的结构

修改 Employee 类,添加部门属性

...private Department department;public Employee() {}public Employee(Integer empId, String empName, String gender, String email, Integer dId) {this.empId = empId;this.empName = empName;this.gender = gender;this.email = email;this.dId = dId;}@Overridepublic String toString() {return "Employee{" +"empId=" + empId +", empName='" + empName + '\'' +", gender='" + gender + '\'' +", email='" + email + '\'' +", dId=" + dId +", department=" + department +'}';} ...

修改 EmployeeMapper 接口,增加下面内容

...//带上部门查询的条件查询List<Employee> selectByExampleWithDept(EmployeeExample example);//带上部门的主键查询Employee selectByPrimaryKeyWithDept(Integer empId);...

修改 EmployeeMapper.xml,增加下面内容

<resultMap id="WithDeptResultMap" type="com.study.ssm.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.ssm.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 selectByExampleWithDept(EmployeeExample example);--><select id="selectByExampleWithDept"parameterType="com.study.ssm.bean.EmployeeExample"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"parameterType="java.lang.Integer"resultMap="WithDeptResultMap">select<include refid="WithDept_Column_List" />from tbl_emp e left join tbl_dept d on e.d_id=d.dept_idwhere emp_id = #{empId,jdbcType=INTEGER}</select>

8. Spring 整合 Junit 4测试 Mapper 添加数据

/** * 推荐Spring的项目就可以使用Spring的单元测试,可以自动注入我们需要的组件 * 1、导入SpringTest模块 * 2、@ContextConfiguration指定Spring配置文件的位置 * 3、直接autowired要使用的组件即可 *///指定单元测试类型@RunWith(SpringJUnit4ClassRunner.class)//指定配置文件@ContextConfiguration(locations = {"classpath:application.xml"})public class MapperTest {@AutowiredDepartmentMapper departmentMapper;@AutowiredEmployeeMapper employeeMapper;@AutowiredSqlSession sqlSession;@Testpublic void testCRUD() {System.out.println(departmentMapper);//1.插入几个部门departmentMapper.insertSelective(new Department(null, "开发部"));departmentMapper.insertSelective(new Department(null, "测试部"));//插入一条员工数据employeeMapper.insertSelective(new Employee(null, "张三", "M", "zhangsan@qq.com", 1));employeeMapper.insertSelective(new Employee(null, "李四", "M", "lisi@163.com", 1));employeeMapper.insertSelective(new Employee(null, "王五", "M", "wangwu@sina.com", 1));//批量插入员工数据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, "W", uid + "@gmail.com", 2));}}}

三、规定RESTful 风格的URI

URI请求方式功能
/empsGET获取所有员工信息
/empPOST保存新增用户信息
/checkEmpGET检查用户是否重名
/emp/{id}GET根据id获取用户信息
/emp/{empId}PUT保存修改用户信息
/emp/{empId}DELETE删除用户

四、创建index.jsp

基本的骨架搭建

首页

SSM-CRUD

#empNamegenderemaildeptName操作
// 完善前端代码...

五、查询

1. 需要实现的功能

(1)第一步,用 JSTL 实现(URI:/emps):

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

(2)第二步,用 Ajax 实现:

  • index.jsp 页面直接发送 Ajax 请求,进行员工分页数据的查询。
  • 服务器将查出来的数据,通过 JSON 字符串的形式返回给浏览器。
  • 浏览器收到 JSON 字符串后,用 JS 对JSON 解析,通过 DOM 增删改查页面。
  • 返回 JSON,实现客户端的无关性。

2. controller

@Controllerpublic class EmployeeController {@AutowiredEmployeeService employeeService;@RequestMapping("/emps")public String getEmps(@RequestParam(value = "pn", defaultValue = "1") Integer pn,Model model) {// 这不是一个分页查询;// 引入PageHelper分页插件// 在查询之前只需要调用,传入页码,以及每页的大小PageHelper.startPage(pn, 5);// startPage后面紧跟的这个查询就是一个分页查询List<Employee> emps = employeeService.getAll();// 使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就行了。// 封装了详细的分页信息,包括有我们查询出来的数据,传入连续显示的页数PageInfo page = new PageInfo(emps, 5);model.addAttribute("pageInfo", page);return "list";}}

3. service

@Servicepublic class EmployeeService {@AutowiredEmployeeMapper employeeMapper;public List<Employee> getAllEmps() {EmployeeExample example = new EmployeeExample();example.setOrderByClause("emp_id");return employeeMapper.selectByExampleWithDept(example);}}

4. spring 整合 Junit 4测试 MVC

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

5. 添加 Msg 类引入链式编程

public class Msg {private String code;private String msg;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;}...}

6. 修改 controller

修改为使用 JSON 格式传输数据,需要 Jackson 的依赖。

@ResponseBody@RequestMapping(value = "/emps", method = RequestMethod.GET)public Msg getEmpsWithJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn) {PageHelper.startPage(pn, 5);List<Employee> emps = employeeService.getAllEmps();PageInfo pageInfo = new PageInfo(emps, 5);return Msg.success().add("pageInfo", pageInfo);}

7. 补充前端代码,采用Ajax发送请求

中补充

//总记录数var 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) {//清空table表格$("#emps_table tbody").empty();//获得分页数据var emps = result.extend.pageInfo.list;//循环遍历分页数据$.each(emps, function (index, item) {//每行数据var checkBoxTd = $("");var empIdTd = $("").append(item.empId);var empNameTd = $("").append(item.empName);var genderTd = $("").append(item.gender == 'M' " />"男" : "女");var emailTd = $("").append(item.email);var deptNameTd = $("").append(item.department.deptName);//创建编辑按钮,并添加样式var editBtn = $("").addClass("btn btn-primary btn-sm edit_btn").append($("").addClass("glyphicon glyphicon-pencil")).append("编辑");//为编辑按钮添加一个自定义的属性,来表示当前员工ideditBtn.attr("edit-id", item.empId);//创建删除按钮,并添加样式var delBtn = $("").addClass("btn btn-danger btn-sm delete_btn").append($("").addClass("glyphicon glyphicon-trash")).append("删除");//为删除按钮添加一个自定义的属性来表示当前删除的员工iddelBtn.attr("del-id", item.empId);//将两个按钮放在同一个表格中var btnTd = $("").append(editBtn).append(" ").append(delBtn);//将每行数据以及对应的按钮加入到表格的标签中//append方法执行完成以后还是返回原来的元素$("").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.total;currentPage = result.extend.pageInfo.pageNum;}//解析显示分页条,点击分页要能去下一页....function build_page_nav(result) {//清空$("#page_nav_area").empty();//添加列表属性,并添加样式var ul = $("
    "
    ).addClass("pagination");//构建元素//首页,默认进入页面是第一页,不允许点击var firstPageLi = $("
  • "
    ).append($("").append("首页").attr("href", "#"));//上一页var prePageLi = $("
  • "
    ).append($("").append("«"));//没有上一页,不允许点击if (result.extend.pageInfo.hasPreviousPage == false) {//添加不允许点击的样式(css)firstPageLi.addClass("disabled");prePageLi.addClass("disabled");} else {//为元素添加点击翻页的事件firstPageLi.click(function () {to_page(1);});prePageLi.click(function () {to_page(result.extend.pageInfo.pageNum - 1);});}//下一页var nextPageLi = $("
  • "
    ).append($("").append("»"));//末页var lastPageLi = $("
  • "
    ).append($("").append("末页").attr("href", "#"));//如果没有下一页,不允许点击if (result.extend.pageInfo.hasNextPage == false) {//添加不允许点击的样式(css)nextPageLi.addClass("disabled");lastPageLi.addClass("disabled");//为元素添加点击翻页的事件} else {nextPageLi.click(function () {to_page(result.extend.pageInfo.pageNum + 1);});lastPageLi.click(function () {to_page(result.extend.pageInfo.pages);});}//添加首页和前一页 的提示ul.append(firstPageLi).append(prePageLi);//1,2,3遍历给ul中添加页码提示//添加页码框$.each(result.extend.pageInfo.navigatepageNums, function (index, item) {//为每个页码添加超链接以及显示的内容(即:所在页码)var numLi = $("
  • "
    ).append($("").append(item));//页码为当前页码,不允许点击if (result.extend.pageInfo.pageNum == item) {//添加不允许点击的样式(css)numLi.addClass("active");}//为元素添加点击翻页的事件numLi.click(function () {to_page(item);});ul.append(numLi);});//添加下一页和末页 的提示ul.append(nextPageLi).append(lastPageLi);//把ul加入到navvar navEle = $("").append(ul);//添加到id为page_nav_area的元素中navEle.appendTo("#page_nav_area");}

    8. 效果

    启动服务,直接显示首页:

    六、新增数据

    1. 需要实现的功能

    • 在 index.jsp 页面点击“新增”弹出对话框

    • 去数据库中查询部门列表,显示在对话框内

    • 对用户输入的数据进行校验

      • jQuery 前端校验格式
      • Ajax 校验用户名是否重复
      • 后端校验(JSR 303)
    • 保存用户数据

    2. 添加模态框

    在标签的开头处添加

    <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">×</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"><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>

    3 查询部门列表

    Controller

    @Controllerpublic class DepartmentController {@Autowiredprivate DepartmentService departmentService;@ResponseBody@RequestMapping("/depts")public Msg getDeptsWithJson() {List<Department> depts = departmentService.getAllDepts();return Msg.success().add("depts", depts);}}

    Service

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

    补充前端代码

    //清空表单样式及内容function reset_form(ele){$(ele)[0].reset();//清空表单样式$(ele).find("*").removeClass("has-error has-success");$(ele).find(".help-block").text("");}//点击新增按钮弹出模态框。$("#emp_add_modal_btn").click(function(){//清除表单数据(表单完整重置(表单的数据,表单的样式))reset_form("#empAddModal form");//发送ajax请求,查出部门信息,显示在下拉列表中getDepts("#empAddModal select");//弹出模态框$("#empAddModal").modal({backdrop:"static"});});//查出所有的部门信息并显示在下拉列表中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);//显示部门信息在下拉列表中$.each(result.extend.depts,function(){var optionEle = $("").append(this.deptName).attr("value",this.deptId);optionEle.appendTo(ele);});}});}

    4. jQuery 前端校验格式

    //校验表单数据function validate_add_form(){//1、拿到要校验的数据,使用正则表达式var empName = $("#empName_add_input").val();var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;if(!regName.test(empName)){//alert("用户名可以是2-5位中文或者6-16位英文和数字的组合");show_validate_msg("#empName_add_input", "error", "用户名可以是2-5位中文或者6-16位英文和数字的组合");return false;}else{show_validate_msg("#empName_add_input", "success", "");};//2、校验邮箱信息var email = $("#email_add_input").val();var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;if(!regEmail.test(email)){//alert("邮箱格式不正确");//应该清空这个元素之前的样式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 if("error" == status){$(ele).parent().addClass("has-error");$(ele).next("span").text(msg);}}

    5. Ajax 校验用户名是否重复

    Controller

    /*** 检查用户名是否可用*/@ResponseBody@RequestMapping("/checkuser")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", "用户名不可用");}}

    Service

    public boolean checkEmp(String empName) {EmployeeExample example = new EmployeeExample();example.createCriteria().andEmpNameEqualTo(empName);return employeeMapper.countByExample(example) == 0;}

    补充前端代码

    //校验用户名是否可用$("#empName_add_input").change(function(){//发送ajax请求校验用户名是否可用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","用户名可用");//添加定义属性ajax-va,值为"success"$("#emp_save_btn").attr("ajax-va","success");}else{show_validate_msg("#empName_add_input","error",result.extend.va_msg);//添加定义属性ajax-va,值为"error"$("#emp_save_btn").attr("ajax-va","error");}}});});

    6. 后端校验 + 保存

    Controller

    /*** 校验用户是否可用*/@RequestMapping(value = "/emp", method = RequestMethod.POST)@ResponseBody/*** @Valid: 使用JSR303对employee属性进行校验, 校验规则在属性注解的@Pattern中设置* BindingResult result: 校验后,返回的结果*/public Msg saveEmp(@Valid Employee employee, BindingResult result) {if (result.hasErrors()) {//校验失败,应该返回失败,在模态框中显示校验失败的错误信息Map<String, Object> map = new HashMap<>();List<FieldError> errors = result.getFieldErrors();for (FieldError fieldError : errors) {//fieldError.getField(): 错误的字段名//fieldError.getDefaultMessage(): 错误信息map.put(fieldError.getField(), fieldError.getDefaultMessage());}return Msg.fail().add("errorFields", map);} else {employeeService.saveEmp(employee);return Msg.success();}}

    Service

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

    补充前端代码

    //点击保存,保存员工。$("#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){//alert(result.msg);if(result.code == 100){//员工保存成功;//1、关闭模态框$("#empAddModal").modal('hide');//2、来到最后一页,显示刚才保存的数据//发送ajax请求显示最后一页数据即可to_page(totalRecord);}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);}}}});});

    7. 效果

    七、修改数据

    1. 需要实现的功能

    • 点击编辑按钮,弹出用户修改的模态框。
    • 模态框可以回显用户的信息。
    • 点击更新,完成修改操作。

    2. 添加模态框

    <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">×</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"><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>

    3. 获取要修改的员工信息

    Controller

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

    Service

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

    补充前端代码

    //1、我们是按钮创建之前就绑定了click,所以绑定不上。//1)、可以在创建按钮的时候绑定。2)、绑定点击.live()//jquery新版没有live,使用on进行替代$(document).on("click",".edit_btn",function(){//alert("edit");//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){//console.log(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]);}});}

    4. 保存员工信息

    Controller

    @ResponseBody@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)public Msg saveEmp(Employee employee) {employeeService.updateEmp(employee);System.out.println(employee);return Msg.success();}

    Service

    public void updateEmp(Employee employee) {employeeMapper.updateByPrimaryKeySelective(employee);}

    补充前端代码

    //点击更新,更新员工信息$("#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){//alert(result.msg);//1、关闭对话框$("#empUpdateModal").modal("hide");//2、回到本页面to_page(currentPage);}});});

    5. 效果

    八、删除数据

    1. 需要实现的功能

    • 单个删除,点击某条用户的删除按钮,弹出提示框,点击确定即可删除

    • 批量删除

    2. Controller

    @ResponseBody@RequestMapping(value = "/emp/{empId}", method = RequestMethod.DELETE)public Msg deleteEmp(@PathVariable("empId") String ids) {//判断批量删除还是单个删除if (ids.contains("-")) {ArrayList<Integer> list = new ArrayList<>();String[] str_ids = ids.split("-");for (String str_id : str_ids) {list.add(Integer.parseInt(str_id));}employeeService.deleteBatch(list);} else {int id = Integer.parseInt(ids);employeeService.deleteEmp(id);}return Msg.success();}

    3. Service

    public void deleteEmp(Integer empId) {employeeMapper.deleteByPrimaryKey(empId);}public void deleteBatch(ArrayList<Integer> list) {EmployeeExample example = new EmployeeExample();example.createCriteria().andEmpIdIn(list);employeeMapper.deleteByExample(example);}

    4. 单个删除

    补充前端代码

    //单个删除$(document).on("click",".delete_btn",function(){//1、弹出是否确认删除对话框var empName = $(this).parents("tr").find("td:eq(2)").text();var empId = $(this).attr("del-id");//alert($(this).parents("tr").find("td:eq(1)").text());if(confirm("确认删除【"+empName+"】吗?")){//确认,发送ajax请求删除即可$.ajax({url:"${APP_PATH}/emp/"+empId,type:"DELETE",success:function(result){alert(result.msg);//回到本页to_page(currentPage);}});}});

    5. 批量删除

    补充前端代码

    //完成全选/全不选功能$("#check_all").click(function(){//attr获取checked是undefined;//我们这些dom原生的属性;attr获取自定义属性的值;//prop修改和读取dom原生属性的值$(".check_item").prop("checked",$(this).prop("checked"));});//check_item$(document).on("click",".check_item",function(){//判断当前选择中的元素是否5个var flag = $(".check_item:checked").length==$(".check_item").length;$("#check_all").prop("checked",flag);});//点击全部删除,就批量删除$("#emp_delete_all_btn").click(function(){//var empNames = "";var del_idstr = "";$.each($(".check_item:checked"),function(){//thisempNames += $(this).parents("tr").find("td:eq(2)").text()+",";//组装员工id字符串del_idstr += $(this).parents("tr").find("td:eq(1)").text()+"-";});//去除empNames多余的,empNames = empNames.substring(0, empNames.length-1);//去除删除的id多余的-del_idstr = del_idstr.substring(0, del_idstr.length-1);if(confirm("确认删除【"+empNames+"】吗?")){//发送ajax请求删除$.ajax({url:"${APP_PATH}/emp/"+del_idstr,type:"DELETE",success:function(result){alert(result.msg);//回到当前页面to_page(currentPage);//每次删除完后,取消全选$("#check_all").prop("checked",false);}});}});

    6. 效果

    单个删除

    批量删除

    九、项目总结