该笔记为尚硅谷SSM实战演练丨ssm整合快速开发CRUD学习笔记
github项目地址:https://github.com/xjhqre/sgg-ssm-demo
使用SSM框架搭建出一套简单的CRUD项目示例,包括分页查询、Ajax请求、数据校验等。
相关配置文件的创建请见SSM整合配置模板,这里主要写下不同的地方。
步骤:
SpringMVC、Spring:
Spring-Jdbc:
Spring面向切面编程:
Mybatis:
mybatis整合Spring:
数据库连接池:
MySQL驱动:
其他(jstl,servlet-api,junit):
provided
注意spring包的版本都要相同
pom.xml文件:
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>ssm-demoartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.17version>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
dependencies>
project>
步骤:
index.jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--引入jQuery--%>
<%--引入样式--%>
步骤:
contextConfigLocation
和 ContextLoaderListener
,contextConfigLocation
设置spring配置文件的位置,在resources目录下创建applicationContext.xml文件CharacterEncodingFilter
,初始化参数 encoding、forceRequestEncoding、forceResponseEncoding,设置过滤所有请求 /*,一定要放在所有过滤器之前HiddenHttpMethodFilter
,将指定的 post 转化为 delete 或者是 put 请求。过滤所有请求/*wen.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>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
<init-param>
<param-name>forceRequestEncodingparam-name>
<param-value>trueparam-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
步骤:
dispatcherServlet-servlet.xml:
<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">
<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>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
beans>
步骤:
applicationContext.xml:
<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">
<context:component-scan base-package="com.xjhqre.crud">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
context:component-scan>
<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>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="pooledDataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xjhqre.crud.dao"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<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>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
<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>
DOCTYPE configuration
PUBLIC "-//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>
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
);
使用mybatis的逆向工程生成对应的bean以及mapper
步骤:
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.3.7version>
dependency>
在当前工程目录下创建 mbg.xml 文件(与pom.xml同级目录)
配置mgb.xml文件
DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true" />
commentGenerator>
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm?useSSL=false&serverTimezone=UTC"
userId="root"
password="123456">
jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
javaTypeResolver>
<javaModelGenerator targetPackage="com.xjhqre.crud.pojo"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.xjhqre.crud.dao" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
<table tableName="t_emp" domainObjectName="Employee"/>
<table tableName="t_dept" domainObjectName="Department"/>
context>
generatorConfiguration>
@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);
}
逆向工程不能生成联合查询。我们需要在mybatis逆向工程生成的mapper映射文件基础上添加新功能,查询员工时带上他的部门信息
步骤:
EmployeeMapper
接口上新添加两个方法:List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
在Employee
员工类上新增属性private Department department;
,并添加 get和set方法
在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>
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>
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>
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>
spring项目推荐使用spring的单元测试,可以自动注入我们需要的组件
需要导入spring-test包
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.14version>
<scope>testscope>
dependency>
测试代码:
在Department
类和Employee
类中添加构造函数
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {
@Autowired
DepartmentMapper departmentMapper;
@Autowired
EmployeeMapper employeeMapper;
@Autowired
SqlSession sqlSession;
@Test
public 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));
}
}
}
步骤:
发送请求为 /emps
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
员工列表
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
* @return 员工信息
*/
public List<Employee> queryAllEmployees() {
return employeeMapper.selectByExampleWithDept(null);
}
}
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.1.2version>
dependency>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
plugins>
@Controller
public class EmployeeController {
@Autowired
EmployeeService 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 页面
}
}
/**
* 使用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
@Autowired
WebApplicationContext context;
// 虚拟MVC请求,获取到处理结果
MockMvc mockMvc;
@Before
public void initMokcMvc() {
// 初始化mockMvc
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public 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());
}
}
}
引入 jsp 依赖包,不引入无法使用pageContext
的setAttribute
方法
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
<scope>providedscope>
dependency>
list.jsp页面:
pageInfo
中取出取出员工信息显示<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
员工列表
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<%-- 搭建显示页面 --%>
<%-- 标题 --%>
SSM_CRUD
<%-- 按钮 --%>
<%-- 显示表格数据 --%>
#
empName
gender
email
deptName
操作
${emp.empId}
${emp.empName}
${emp.empGender}
${emp.empEmail}
${emp.department.deptName}
<%-- 显示分页信息 --%>
<%--分页条信息--%>
<%--分页文字信息 --%>
当前第${pageInfo.pageNum}页,总页数:${pageInfo.pages}, 总记录数:${pageInfo.total}
步骤:
类中定义状态码、提示信息、返回给用户的数据、以及相关的 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;
}
}
返回 json 数据,需要导入jackson包
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.12.3version>
dependency>
EmployeeController:
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
/**
* 查询员工数据
* @return 员工信息
*/
@RequestMapping("/emps")
@ResponseBody
public 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);
}
}
在 index.jsp 页面加载完后 发送 Ajax 请求,将返回的 JSON 数据解析。删除原来的
<%@ 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());
%>
<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_CRUDh1>
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>empNameth>
<th>genderth>
<th>emailth>
<th>deptNameth>
<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 = $("").append(item.empId);
var empNameTd = $("").append(item.empName)
var genderTd = $("").append(item.empGender == "M" ? "男" : "女")
var emailTd = $("").append(item.empEmail)
var deptNameTd = $("").append(item.department.deptName)
// 注入按钮数据
var editBtn = $("").addClass("btn btn-primary btn-sm")
.append($("").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
var delBtn = $("").addClass("btn btn-danger btn-sm")
.append($("").addClass("glyphicon glyphicon-trash"))
.append("删除");
var btnTd = $("").append(editBtn).append(" ").append(delBtn);
$("").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 = $("
").addClass("pagination")
var firstPageLi = $("").append($("").append("首页").attr("href", "#"));
var prePageLi = $("").append($("").append("«").attr("href", "#"));
var nextPageLi = $("").append($("").append("»").attr("href", "#"));
var lastPageLi = $("").append($("").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 = $("").append($("").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 = $("").append(ul)
navEle.appendTo("#page_nav_area");
}
script>
body>
html>
步骤:
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
public List<Department> quireAllDepartments() {
return departmentMapper.selectByExample(null);
}
}
@Controller
public class DepartmentController {
@Autowired
DepartmentService departmentService;
@RequestMapping("/depts")
@ResponseBody
public Msg quireAllDepartments() {
List<Department> departments = departmentService.quireAllDepartments();
return Msg.success().add("depts", departments);
}
}
规定URI:
public void saveEmp(Employee employee) {
employeeMapper.insertSelective(employee);
}
@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(Employee employee) {
employeeService.saveEmp(employee);
return Msg.success();
}
在添加用户后跳转到最后一页,传入跳转的页数为总记录数,需要设置分页助手参数合理化。否则会跳转到其他非法地址
在 mybatis 核心配置文件中配置
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="reasonable" value="true"/>
plugin>
plugins>
reasonable:分页合理化参数,默认值为 false
,当该参数为 true
时,pageNum<=0
时会查询第一页,pageNum
(超过总数时),会查询最后一页,默认 false
时,直接根据参数进行查询
因为员工姓名可能存在重复的情况,所以检查邮箱是否已存在
当输入完邮箱后失去焦点,页面发送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();
}
}
重要数据使用 JSR303 进行校验
需要导入 Hibernate-Validator
:
JSR303数据校验支持:tomcat7及以上的服务器,tomcat7以下的服务器:el表达式。额外给服务器的lib包中替换新的标准的el
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>6.1.0.Finalversion>
dependency>
给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;
@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();
}
}
// 模态框保存按钮点击事件
$("#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", "员工名称格式不正确")
}
}
}
})
})
<%@ 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());
%>
<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">×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">empNamelabel>
<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">Emaillabel>
<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">empGenderlabel>
<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">deptIdlabel>
<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_CRUDh1>
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>empNameth>
<th>genderth>
<th>emailth>
<th>deptNameth>
<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 = $("").append(item.empId);
var empNameTd = $("").append(item.empName)
var genderTd = $("").append(item.empGender == "M" ? "男" : "女")
var emailTd = $("").append(item.empEmail)
var deptNameTd = $("").append(item.department.deptName)
// 注入按钮数据
var editBtn = $("").addClass("btn btn-primary btn-sm")
.append($("").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
var delBtn = $("").addClass("btn btn-danger btn-sm")
.append($("").addClass("glyphicon glyphicon-trash"))
.append("删除");
var btnTd = $("").append(editBtn).append(" ").append(delBtn);
$("").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 = $("
").addClass("pagination")
var firstPageLi = $("").append($("").append("首页").attr("href", "#"));
var prePageLi = $("").append($("").append("«").attr("href", "#"));
var nextPageLi = $("").append($("").append("»").attr("href", "#"));
var lastPageLi = $("").append($("").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 = $("").append($("").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 = $("").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 = $("").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请求不检验中文,如果发送对象中含中文则用POST
success: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>
步骤:
<%-- 修改员工模态框 --%>
<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" 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">empNamelabel>
<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">Emaillabel>
<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">empGenderlabel>
<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">deptIdlabel>
<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>
给员工列表的修改和删除按钮添加样式:edit_btn、del_btn
// 注入按钮数据
var editBtn = $("").addClass("btn btn-primary btn-sm edit_btn")
.append($("").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
var delBtn = $("").addClass("btn btn-danger btn-sm del_btn")
.append($("").addClass("glyphicon glyphicon-trash"))
.append("删除");
新增下拉列表的重置
// 重置添加员工表单数据和样式
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()
}
// 为修改员工按钮添加事件
// 因为是先绑定事件后在生成的按钮,所以不能用click
// 早先版本的jQuery可以使用live方法
// 这里使用 on 方法绑定
$(document).on("click", ".edit_btn", function () {
// 1. 查询部门信息显示
getDepts("#deptId_update_select")
// 2. 回显员工信息
// 3. 跳出模态框
$("#empUpdateModal").modal({
backdrop: "static"
})
})
/**
* 根据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);
}
public Employee getEmpById(Integer id) {
return employeeMapper.selectByPrimaryKey(id);
}
// 根据id查询员工信息函数
function getEmpById(id) {
$.ajax({
url:"${APP_PATH}/emp/" + id,
type:"GET",
success:function (result) {
console.log(result)
}
})
}
在定义editBtn按钮之后添加empId属性,用于修改员工时传递id值
// 添加自定义属性,用于修改员工时传递id值
editBtn.attr("empId_for_edit", item.empId)
这里传入的是部门id,而回显的是部门名称的原因:
value
属性设置的。该方法大多用于 input
元素。// 根据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);
}
})
}
// 为修改员工按钮添加事件
// 因为是先绑定事件后在生成的按钮,所以不能用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"
})
})
步骤:
注意事项
@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
上述代码里的 {empId} ,大括号中的名称必须和对象类的属性名相同
如果直接使用ajax=PUT的请求
存在问题:
原因:
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();
}
}
/**
* 根据id更新员工数据
* @param employee 页面传来的员工数据
*/
public void updateEmpById(Employee employee) {
employeeMapper.updateByPrimaryKey(employee);
}
将编辑按钮的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"
})
})
在web.xml设置 HttpPutFormContentFilter
作用:
request.getParameter()
被重写,就会从自己封装的map中获取数据<filter>
<filter-name>HttpPutFormContentFilterfilter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
/**
* 根据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();
}
删除单个员工
/**
* 根据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);
}
全选按钮:
<tr>
<th>
<input type="checkbox" id="check_all"/>
th>
<th>#th>
<th>empNameth>
<th>genderth>
<th>emailth>
<th>deptNameth>
<th>操作th>
tr>
选项按钮:
$.each(emps, function (index, item) {
var checkBoxTd = $("")
var empIdTd = $("").append(item.empId);
var empNameTd = $("").append(item.empName)
var genderTd = $("").append(item.empGender == "M" ? "男" : "女")
var emailTd = $("").append(item.empEmail)
var deptNameTd = $("").append(item.department.deptName)
// 注入按钮数据
var editBtn = $("").addClass("btn btn-primary btn-sm edit_btn")
.append($("").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
// 添加自定义属性,用于修改员工时传递id值
editBtn.attr("empId_for_edit", item.empId)
var delBtn = $("").addClass("btn btn-danger btn-sm del_btn")
.append($("").addClass("glyphicon glyphicon-trash"))
.append("删除");
var btnTd = $("").append(editBtn).append(" ").append(delBtn);
$("").append(checkBoxTd)
.append(empIdTd)
.append(empNameTd)
.append(genderTd)
.append(emailTd)
.append(deptNameTd)
.append(btnTd)
.appendTo("#emps_table tbody");
});
全选按钮绑定事件
// 全选按钮绑定事件
$("#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)
})
// 单个删除按钮事件
$(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)
}
})
}
})
添加删除所有员工按钮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)
}
})
}
})
<%@ 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">×</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">×</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 = $("")
var empIdTd = $("").append(item.empId);
var empNameTd = $("").append(item.empName)
var genderTd = $("").append(item.empGender == "M" ? "男" : "女")
var emailTd = $("").append(item.empEmail)
var deptNameTd = $("").append(item.department.deptName)
// 注入按钮数据
var editBtn = $("").addClass("btn btn-primary btn-sm edit_btn")
.append($("").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
// 添加自定义属性,用于修改员工时传递id值
editBtn.attr("empId_for_edit", item.empId)
var delBtn = $("").addClass("btn btn-danger btn-sm del_btn")
.append($("").addClass("glyphicon glyphicon-trash"))
.append("删除");
var btnTd = $("").append(editBtn).append(" ").append(delBtn);
$("").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("«").attr("href", "#"));
var nextPageLi = $("").append($("").append("»").attr("href", "#"));
var lastPageLi = $("").append($("").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 = $("").append($("").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 = $("").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 = $("").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请求不检验中文,如果发送对象中含中文则用POST
async: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>