功能点
- 分页功能
- 新增和修改时的数据校验(前端JQuery校验+后端JSR303)
- Ajax异步请求
- Rest风格的URI(使用不同http协议的请求方式表示对数据的不同操作。GET(查询)、POST(新增)、PUT(修改)、DELETE(删除))
环境与技术
电脑环境:macOS
电脑软件:IDEA、Navicat Premium
基础框架:ssm(Spring+SpringMVC+MyBatis)
前端框架:bootstrap
数据库:MySQL8.0.18
服务器:Tomcat8.5.51
依赖管理:Maven3.5.4
分页工具:pagehelper
逆向工程:MyBatis Generator
最终的效果图
实现的功能:员工信息的新增、修改、单个和多个删除。
项目地址:https://github.com/angenin/ssm_crud/
搭建基本环境
创建maven项目
创建一个maven项目,选用webapp模板,文件名为ssm_crud。
添加基本目录
在src下新建test目录,test下再新建java和resources目录,在main目录下也添加java和resources目录。
引入依赖
- 在pop.xml中先引入基本的依赖的jar包
<!-- 引入依赖的jar包 -->
<dependencies>
<!-- SpringMVC-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- Spring jdbc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- Spring 面向切面编程-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- MyBatis-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- MyBatis整合Spring的适配包-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!-- 数据库连接池-->
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- 数据库驱动-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- jsp-->
<!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
配置tomcat服务器
引入bootstrap前端框架
下载
进入官网下载:https://www.bootcss.com/
引入
在项目的webapp目录下新建static目录,并把下载解压好的文件放入,再在static目录下新建一个js目录,用于存放JQuery文件。
- 在index.jsp中的head标签里写入
html <script type="text/javascript" src="static/js/jquery-3.4.1.min.js"></script> <link href="static/bootstrap-dist/css/bootstrap.min.css" rel="stylesheet"/> <script src="static/bootstrap-dist/js/bootstrap.min.js"></script>
- 也可以直接在index.jsp的head标签里引入下面这两个标签。
应用测试
- 使用bootstrap的样式,点击官网的全局CSS样式。
这里的样式都可以选择使用,我们用按钮来测试效果。
复制到index.jsp中,然后启动。
前端的bootstrap的框架就引入成功了。
创建数据库
create database ssm_crud;
use ssm_crud;
create table tbl_dept(
dept_id int(11) PRIMARY KEY auto_increment,
dept_name varchar(255) not null
);
create table tbl_emp(
emp_id int(11) PRIMARY KEY auto_increment,
emp_name varchar(255) not null,
gender char(1),
email varchar(255) not null,
d_id int(11),
FOREIGN KEY(d_id) REFERENCES tbl_dept(dept_id)
);
编写ssm整合的关键配置文件。
在main下的java目录里新建以下目录:
在main目录下的resources目录添加Spring的配置文件,名为applicationContext.xml。
在main目录下的resources目录添加三个file文件,名为jdbcConfig.properties、springmvc.xml和mybatis-config.xml。
在resources目录下添加mapper目录。
在WEB-INF目录下新建一个名为views的目录。
在WEB-INF目录下新建一个名为dispatcherServlet-Servlet.xml的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 配置webapp/WEB-INF/web.xml文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<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_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!-- 1. 启动Spring的容器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 2. SpringMVC的前端控制器,拦截所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 不指定springmvc配置文件的路径,必须在WEB—INF目录下
新建一个与前端控制器同名并加上-Servlet(即dispatcherServlet-Servlet)
的spring配置文件作为springmvc的配置文件-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 3. 字符编码过滤器(要放在所有过滤器之前)-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 指定字符编码集-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 设置请求和响应的字符编码集-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 4. 使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 配置resources/springmvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ontext="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- SpringMVC的配置文件,包含页面跳转逻辑的控制,配置-->
<ontext:component-scan base-package="com.angenin" use-default-filters="false">
<!-- 只扫描加了Controller的控制器类-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</ontext:component-scan>
<!-- 另一种写法-->
<!-- <context:component-scan base-package="com.angenin.crud.controller"/>-->
<!-- 配置视图解析器,方便页面返回-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 路径:最前面/表示在webapp目录下)-->
<property name="prefix" value="/WEB-INF/views/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 两个标准配置-->
<!-- 将springmvc不能处理的请求交给tomcat-->
<mvc:default-servlet-handler/>
<!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax,映射动态请求等等-->
<mvc:annotation-driven/>
</beans>
- 配置resources/jdbcConfig.properties文件
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=123456
- 配置resources/applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- spring的配置文件,这里主要配置和业务逻辑有关的-->
<!-- Spring配置文件的核心点(数据源、与mybatis的整合、事务控制)-->
<context:component-scan base-package="com.angenin">
<!-- 不扫描加了Controller注解的控制器类-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:property-placeholder location="classpath:jdbcconfig.properties"/>
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--==============================================================-->
<!-- 配置和MyBatis的整合-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis全局配置文件的位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 数据源-->
<property name="dataSource" ref="pooledDataSource"/>
<!-- -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- 配置扫描器,将mybatis接口的实现加入ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描所有dao接口的实现,加入到ioc容器中-->
<property name="basePackage" value="com.angenin.crud.dao"/>
</bean>
<!--==============================================================-->
<!-- 事务控制的配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制住数据源-->
<property name="dataSource" ref="pooledDataSource"/>
</bean>
<!-- 1.开启基于注解的事务;2.使用xml配置形式的事务(必要主要的都是使用配置式)-->
<aop:config>
<!-- 切入点表达式-->
<aop:pointcut id="txPoint" expression="execution(* com.angenin.crud.service..*(..))"/>
<!-- 配置事务增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!-- 配置事务增强,事务如何切入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有方法都是事务方法-->
<tx:method name="*"/>
<!-- 小范围优先-->
<!-- 以get开头的所有方法,只读-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
- 配置mybatis-config.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局配置-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 类型别名-->
<typeAliases>
<package name="com.angenin.crud.bean"/>
</typeAliases>
</configuration>
使用mybatis的逆向工程生成对应的bean、dao和mapper
在pop.xml中的<dependencies></dependencies>
里引入
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<!-- mybatis的逆向工程-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
然后在resources目录下新建generatorConfig.xml文件,并写入
(在<javaModelGenerator>
、<sqlMapGenerator>
和<javaClientGenerator>
标签里的targetProject
属性,因为我是macOS,所有用/
,如果是Windows系统,需要把/
改为\
。)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--导入属性配置-->
<properties resource="jdbcConfig.properties"/>
<!-- context 是逆向工程的主要配置信息 -->
<!-- id:名字,targetRuntime:设置生成的文件适用的mybatis版本 -->
<context id="mbg" targetRuntime="MyBatis3">
<!-- 生成注释为false 不生成为true 【不生成注释时,重复生成会被重复写入而导致报错】 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--jdbc的数据库连接-->
<jdbcConnection connectionURL="${jdbc.jdbcUrl}"
driverClass="${jdbc.driverClass}"
userId="${jdbc.user}"
password="${jdbc.password}"/>
<!--类型处理器,在数据库类型和java类型之间的转换控制-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 指定javaBean生成的位置-->
<javaModelGenerator targetPackage="com.angenin.crud.bean"
targetProject="./src/main/java">
<!-- 是否允许子包 -->
<property name="enableSubPackages" value="true" />
<!-- 是否清理从数据库中查询出的字符串左右两边的空白字符 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 指定sql映射文件生成的位置-->
<!-- targetProject:为文件的硬盘路径 ./为当前工程下(也可以写绝对路径)-->
<sqlMapGenerator targetPackage="mappers"
targetProject="./src/main/resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 指定dao接口生成的位置,mapper接口-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.angenin.crud.dao"
targetProject="./src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- table指定每个表的生成策略-->
<!-- tableName:要生成的表,domainObjectName:表生成对应类名-->
<table tableName="tbl_emp" domainObjectName="Employee"/>
<table tableName="tbl_dept" domainObjectName="Department"/>
</context>
</generatorConfiguration>
在test/java目录下新建MBGTest.java,写入
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MBGTest {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//指定 逆向工程配置文件
File configFile = new File("src/main/resources/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
}
运行后生成对应的bean、dao和mapper文件。
增添查询员工信息时带上部门信息的业务
在dao/EmployeeMapper.java中添加:
// 因为逆向工程生成的查询只生成d_id,没有dept表的信息,所以自定义两个查询方法。
// 自定义,查询时带上dept表里信息
List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
然后在bean/Employee.java里添加:
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
最后往resources/mappers/EmployeeMapper.xml中添加:
<!-- 自定义返回集合-->
<resultMap id="WithDeptResultMap" type="com.angenin.crud.bean.Employee">
<id column="emp_id" jdbcType="INTEGER" property="empId" />
<result column="emp_name" jdbcType="VARCHAR" property="empName" />
<result column="gender" jdbcType="CHAR" property="gender" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="d_id" jdbcType="INTEGER" property="dId" />
<!-- 指定联合查询出的部门字段的封装-->
<association property="department" javaType="com.angenin.crud.bean.Department">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
<!-- 自定义查询集合-->
<sql id="WithDept_Column_List">
e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
</sql>
<!-- 自定义查询,查询员工同时带上部门信息-->
<select id="selectByExampleWithDept" parameterType="com.angenin.crud.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_id
where emp_id = #{empId,jdbcType=INTEGER}
</select>
测试CRUD功能
- 在pop.xml中导入spring的单元测试依赖。
<!-- spring单元测试-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
- 为bean下的Department.java和Employee.java添加有参和无参构造器。
//Department
public Department() {
}
public Department(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
//==========================
//Employee
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;
}
- 在resources/applicationContext.xml中加入一个可批量插入的sqlSession。
<!-- 配置一个可以执行批量插入的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
<constructor-arg name="executorType" value="BATCH"/>
</bean>
- 在test/java下新建一个MapperTest.java,并写入:
import com.angenin.crud.bean.Department;
import com.angenin.crud.bean.Employee;
import com.angenin.crud.dao.DepartmentMapper;
import com.angenin.crud.dao.EmployeeMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.UUID;
/*测试DepartmentMapper
* 推荐Spring的项目使用Spring的单元测试,可以自动注入我们需要的组件
* 1.导入SpringTest模块
* 2.@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) 指定spring配置文件的位置
*/
// - @RunWith(SpringJUnit4ClassRunner.class)指定Test用什么单元测试来运行
// - 如果出现`ExceptionInInitializerError`错误,
// 是因为`SpringJUnit4ClassRunner`要求`JUnit 4.12`或更高,
// 在pop.xml中把junit版本调高即可。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {
//3.直接autowired要使用的组件即可
@Autowired
DepartmentMapper departmentMapper;
@Autowired
EmployeeMapper employeeMapper;
@Autowired
SqlSession sqlSession;
@Test
public void testCRUD(){
// 1.插入几个部门
departmentMapper.insertSelective(new Department(null, "开发部"));
departmentMapper.insertSelective(new Department(null, "测试部"));
departmentMapper.insertSelective(new Department(null, "运维部"));
// 2.生成员工数据,测试员工表的插入
employeeMapper.insertSelective(new Employee(null, "张三", "M", "zhangsan@qq.com", 1));
// 3.批量插入多个员工;使用可以批量插入操作的sqlSession
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
for (int i = 0; i < 1000; i++) {
String uid = UUID.randomUUID().toString().substring(0, 5) + i;
employeeMapper.insertSelective(new Employee(null, uid, "M", uid + "@qq.com", 1));
}
}
}
CRUD-查询
步骤
1、访问 index.jsp页面
2、index.jsp页面发送出查询员工列表请求
3、EmployeeController来接受请求,查出员工数据
4、来到list.jsp页面进行展示
1. index.jsp只用于跳转到查询页面,所以只留以下内容。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/emps"/>
2. 在pop.xml中引入分页插件。
<!-- 引入PageHelper分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.8</version>
</dependency>
3. 在mybatis-config.xml中注册分页插件。
<!-- 注册PageInterceptor分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
4. 然后在controller下新建一个EmployeeController.java,用于处理员工CRUD请求。
package com.angenin.crud.controller;
import com.angenin.crud.bean.Employee;
import com.angenin.crud.service.EmployeeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* 处理员工CRUD请求
*/
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
/**
* 查询员工数据(分页显示)
* @param pn 页码
* @param model
* @return
*/
@RequestMapping("/emps")
public String getEmps(@RequestParam(value="pn", defaultValue = "1")Integer pn, Model model){
//引入PageHelper分页插件
//查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
//第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
PageHelper.startPage(pn, 5, "emp_id asc");
List<Employee> emps = employeeService.getAll();
//使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
PageInfo page = new PageInfo(emps, 5);
//把page传到下个页面
model.addAttribute("pageInfo", page);
// 页面跳转到WEB-INF/views下的list.jsp页面(springMVC的视图解析器)
return "list";
}
}
5. 在service下新建一个EmployeeService.java
package com.angenin.crud.service;
import com.angenin.crud.bean.Employee;
import com.angenin.crud.dao.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
* @return
*/
public List<Employee> getAll() {
return employeeMapper.selectByExampleWithDept(null);
}
}
6. 测试分页查询的数据
在test/java下新建一个MvcTest.java用于测试。
import com.angenin.crud.bean.Employee;
import com.github.pagehelper.PageInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.List;
/**
* 使用Spring测试模块提供的测试请求功能,测试crud请求的正确性
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration //获取springmvc的ioc容器
@ContextConfiguration(locations = {"classpath:applicationContext.xml", "classpath:springmvc.xml"})
public class MvcTest {
//传入SpringMVC的IOC
@Autowired
WebApplicationContext context;
//虚拟mvc请求,获取到处理结果
MockMvc mockMvc;
@Before //使用junit的Before
public void initMockMvc(){
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testPage() throws Exception {
//模拟发送get请求 param为请求传入的键值对
//andReturn为获取返回值
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "1")).andReturn();
//请求成功以后,请求域中会有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.print("在页面需要连续显示的页码:");
int[] nums = pi.getNavigatepageNums();
for (int num : nums) {
System.out.print(" " + num);
}
System.out.println();
//获取员工数据
List<Employee> list = pi.getList();
for (Employee employee : list) {
System.out.println("ID: " + employee.getEmpId() + ",name: " + employee.getEmpName());
}
}
}
测试效果:
把传入的键值对改为5,也没有问题。
7. 在webapp/WEB-INF/views里新建一个list.jsp页面,为员工列表页面。
编写list.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入标签核心库--%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>员工列表</title>
<%
//获取当前项目名(得到的是 /加项目名(例:/ssm_crud) ,所以使用的时候前面不用加/而后面需要)
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<%-- web的路径:
- 不以/开始的相对路径,找资源,以当前资源的路径为基准,经常出问题。
- 以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306)再需要加上项目名(项目名也不是写死的)
http://localhost:8080/ssm_crud
--%>
<script type="text/javascript" src="${ APP_PATH }/static/js/jquery-3.4.1.min.js"></script>
<link href="${ APP_PATH }/static/bootstrap-dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="${ APP_PATH }/static/bootstrap-dist/js/bootstrap.min.js"></script>
</head>
<body>
<%-- 搭建显示页面(官方的全局CSS样式的栅格系统) --%>
<div class="container">
<%-- 标题--%>
<div class="row">
<div class="col-md-12">
<h1>SSM_CRUD</h1>
</div>
</div>
<%-- 按钮--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新 增</button>
<button class="btn btn-danger">删 除</button>
</div>
</div>
<%-- 显示表格数据--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<tr>
<th>empId</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>操作</th>
</tr>
<c:forEach items="${ pageInfo.list }" var="emp">
<tr>
<td>${ emp.empId }</td>
<td>${ emp.empName }</td>
<td>${ emp.gender == "M" ? "男" : "女" }</td>
<td>${ emp.email }</td>
<td>${ emp.department.deptName }</td>
<td>
<button class="btn btn-info btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
编辑
</button>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
删除
</button>
</td>
</tr>
</c:forEach>
</table>
</div>
</div>
<%-- 显示分页信息--%>
<div class="row">
<%-- 分页文字信息--%>
<div class="col-md-6">
当前 ${ pageInfo.pageNum } 页,总 ${ pageInfo.pages } 页,总 ${ pageInfo.total } 条记录
</div>
<%-- 分页条信息--%>
<div class="col-md-6">
<nav aria-label="Page navigation">
<ul class="pagination">
<%--首页--%>
<li><a href="${ APP_PATH }/emps?pn=1">首页</a></li>
<%--如果有上一页--%>
<c:if test="${ pageInfo.hasPreviousPage }">
<%--上一页--%>
<li>
<a href="${ APP_PATH }/emps?pn=${ pageInfo.pageNum - 1 }" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<%--显示五页--%>
<c:forEach items="${ pageInfo.navigatepageNums }" var="page_Num">
<%--当前页--%>
<c:if test="${ page_Num == pageInfo.pageNum }">
<li class="active"><a href="/">${ page_Num }</a></li>
</c:if>
<%--不是当前页--%>
<c:if test="${ page_Num != pageInfo.pageNum }">
<li><a href="${ APP_PATH }/emps?pn=${ page_Num }">${ page_Num }</a></li>
</c:if>
</c:forEach>
<%--如果有下一页--%>
<c:if test="${ pageInfo.hasNextPage }">
<%--下一页--%>
<li>
<a href="${ APP_PATH }/emps?pn=${ pageInfo.pageNum + 1 }" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<%--尾页--%>
<li><a href="${ APP_PATH }/emps?pn=${ pageInfo.pages }">尾页</a></li>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
效果图
实现了数据的查询和分页以及分页的跳转功能。
但只能适用于PC浏览器和服务器的交互,实际上发送请求的可能是安卓或iOS,所以这里我们把数据用josn的格式用ajax发送给客户端。
查询-ajax
步骤
1、 index.jsp页面直接发送ajax请求进行员工分页数据的查询
2、服务器将查出的数据,以json字符串的形式返回给浏览器
3、浏览器收到js字符串,可以使用js对json进行解析,使用js通过dom增删改改变页面
4、返回json,实现客户端的无关性
1. 注释掉EmployeeController.java中的getEmps方法,新建一个getEmpsWithJson方法。
/**
* 查询员工数据(分页显示)
* json和ajax
* 导入jackson包
* @param pn 页码
* @return
*/
@RequestMapping("/emps")
@ResponseBody
public PageInfo getEmpsWithJson(@RequestParam(value="pn", defaultValue = "1")Integer pn){
//引入PageHelper分页插件
//查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
//第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
PageHelper.startPage(pn, 5, "emp_id asc");
List<Employee> emps = employeeService.getAll();
//使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
PageInfo page = new PageInfo(emps, 5);
return page;
}
2. 在pop.xml中引入json的依赖
<!-- 返回json字符串的支持-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
启动后页面显示json格式的数据。
因为PageInfo返回到页面不清楚是成功还是失败,所以我们还需要在bean中定义一个提示信息的类。
3. 在bean中定义一个Msg.java用于请求的结果进行处理和返回
package com.angenin.crud.bean;
import java.util.HashMap;
import java.util.Map;
public class Msg {
//状态码 100:成功;200:失败
private int 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;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Map<String, Object> getExtend() {
return extend;
}
public void setExtend(Map<String, Object> extend) {
this.extend = extend;
}
}
并修改getEmpsWithJson方法。
public Msg getEmpsWithJson(@RequestParam(value="pn", defaultValue = "1")Integer pn){
//引入PageHelper分页插件
//查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
//第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
PageHelper.startPage(pn, 5, "emp_id asc");
List<Employee> emps = employeeService.getAll();
//使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
PageInfo page = new PageInfo(emps, 5);
return Msg.success().add("pageInfo", page);
}
重新运行
4. 在mybatis-config.xml中给配置分页插件配置一个参数
!-- 注册PageInterceptor分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 新增属性:reasonable分页的合理化参数
pageNum<=0,而查询第一页,如果pageNum>pages,而查询最后一页-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
5. 舍弃list.jsp,重写index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入标签核心库--%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>员工列表</title>
<%
//获取当前项目名(得到的是 /加项目名(例:/ssm_crud) ,所以使用的时候前面不用加/而后面需要)
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<%-- web的路径:
- 不以/开始的相对路径,找资源,以当前资源的路径为基准,经常出问题。
- 以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306)再需要加上项目名(项目名也不是写死的)
http://localhost:8080/ssm_crud
--%>
<script type="text/javascript" src="${ APP_PATH }/static/js/jquery-3.4.1.min.js"></script>
<%-- 下载的bootstrap前端框架有问题,用第二种方式引入--%>
<%-- <link href="${ APP_PATH }/static/bootstrap-dist/css/bootstrap.min.css" rel="stylesheet"/>--%>
<%-- <script src="${ APP_PATH }/static/bootstrap-dist/js/bootstrap.min.js"></script>--%>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<%-- 搭建显示页面(官方的全局CSS样式的栅格系统) --%>
<div class="container">
<%-- 标题--%>
<div class="row">
<div class="col-md-12">
<h1>SSM_CRUD</h1>
</div>
</div>
<%-- 按钮--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新 增</button>
<button class="btn btn-danger">删 除</button>
</div>
</div>
<%-- 显示表格数据--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover" id="emps_table">
<thead>
<tr>
<th>empId</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" id="page_info_area"></div>
<%-- 分页条信息--%>
<div class="col-md-6" id="page_nav_area"></div>
</div>
</div>
<script type="text/javascript">
//1.页面加载完成后,发送一个ajax请求,要到分页数据
$(function () {
//请求首页收据
to_page(1);
});
//页面跳转方法
function to_page(pn) {
$.ajax({
url:"${APP_PATH}/emps",
data:"pn=" + pn,
type:"get",
success:function(result){
// console.log(result);
//1.解析并显示员工数据
build_emps_table(result);
//2.解析并显示分页信息
build_page_info(result);
//3.解析并显示分页条数据
build_page_nav(result);
}
});
}
//解析显示员工信息
function build_emps_table(result) {
//每次页面跳转都先清空原先的员工数据
$("#emps_table tbody").empty();
var emps = result.extend.pageInfo.list;
//jquery自带的遍历
$.each(emps, function (index, item) {
//员工信息单元格
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var genderTd = $("<td></td>").append(item.gender == 'M' ? "男" : "女");
var emailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
//修改删除按钮,在同一个单元格内
var editBtn = $("<button></button>").addClass("btn btn-info btn-sm edit_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-trash"))
.append("删除");
var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
//把相同员工的单元格添加到同一行
$("<tr></tr>").append(empIdTd)
.append(empNameTd)
.append(genderTd)
.append(emailTd)
.append(deptNameTd)
.append(btnTd)
.appendTo("#emps_table tbody"); //添加到id为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) {
//每次页面跳转都先清空table表格数据
$("#page_nav_area").empty();
var ul = $("<ul></ul>").addClass("pagination");
//首页
var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));
//上一页
var prePageLi = $("<li></li>").append($("<a></a>").append("«").attr("href", "#"));
//如果没有上一页,给首页和前一页按钮增加不能点击的效果
if(!result.extend.pageInfo.hasPreviousPage){
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 = $("<li></li>").append($("<a></a>").append("»").attr("href", "#"));
//尾页
var lastPageLi = $("<li></li>").append($("<a></a>").append("尾页").attr("href", "#"));
//如果没有下一页,给后一页和尾页按钮增加不能点击的效果
if(!result.extend.pageInfo.hasNextPage){
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);
//5个连续显示的页码
$.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
var numLi = $("<li></li>").append($("<a></a>").append(item).attr("href", "#"));
//如果循环到的页码是当前页码
if(item == result.extend.pageInfo.pageNum){
numLi.addClass("active");
}
//为页码按钮添加点击事件
numLi.click(function () {
//页面跳转到对应的页数
to_page(item);
});
//添加页码
ul.append(numLi);
})
//添加下一页和尾页
ul.append(nextPageLi).append(lastPageLi);
//把ul添加到nav中
var navEle = $("<nav></nav>").append(ul).appendTo("#page_nav_area");
}
</script>
</body>
</html>
效果图
实现效果与第一种做法一致。
CRUD-新增
步骤
1、在 index.jsp页面点击”新增”按钮
2、弹出增对话框(bootstrap框架js插件的模态框里的动态实例)
3、到数据库查询部门列表,显示在对话框中
4、用户输入数据后进行校验(jquery前端校验,ajax用户名重复校验,重要数据(后端校验JSR303),唯一约束)
5、完成保存
1. 为index.jsp的新增按钮增加弹窗效果
使用bootstrap官网js插件的模态框。
- 为新增按钮添加一个id,顺便为删除按钮也添加一个id。
...
<%-- 按钮--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary" id="emp_add_modal_btn">新 增</button>
<button class="btn btn-danger" id="emp_delete_modal_btn">删 除</button>
</div>
</div>
<%-- 显示表格数据--%>
...
- 在index.jsp的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">
<%-- 表单 --%>
<%-- empName --%>
<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>
<%-- email --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="email" id="email_add_input" placeholder="email@qq.com">
</div>
</div>
<%-- gender --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="gender" id="gender1_add_input" value="M" checked> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2_add_input" value="F"> 女
</label>
</div>
</div>
<%-- deptName --%>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<%-- 提交部门id即可 --%>
<select class="form-control" name="dId"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<%-- 弹窗关闭按钮 --%>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<%-- 弹窗保存按钮 --%>
<button type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
- 在Service包中创建一个名为DepartmentService.java的类,用于处理DepartmentController.java发送过来的业务。
package com.angenin.crud.service;
import com.angenin.crud.bean.Department;
import com.angenin.crud.dao.DepartmentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
public List<Department> getDepts() {
// 查出所有部门信息并返回给对应的controller
return departmentMapper.selectByExample(null);
}
}
- 在Controller包中新建一个名为DepartmentController.java的控制器,用于处理和部门有关的请求,在里面新建一个名为的方法,用于返回查询到的所有部门信息。
package com.angenin.crud.controller;
import com.angenin.crud.bean.Department;
import com.angenin.crud.bean.Msg;
import com.angenin.crud.service.DepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* 处理和部门有关的请求
*/
@Controller
public class DepartmentController {
@Autowired
private DepartmentService departmentService;
/**
* 返回所有部门的信息
*/
@RequestMapping("/depts")
@ResponseBody
public Msg getDepts(){
//查出所有的部门信息
List<Department> list = departmentService.getDepts();
return Msg.success().add("depts", list);
}
}
- 在index.jsp页面底部的script中为新增按钮添加点击弹窗事件。
//新增按钮的点击弹窗事件
$("#emp_add_modal_btn").click(function () {
//发送ajax请求,查出部门信息,显示在下拉列表中
getDepts("#empAddModal select");
//调用模态框
$("#empAddModal").modal({
backdrop: "static"
});
});
//查出所有部门信息并显示在下拉列表中
function getDepts(ele){
//清空下拉列表
$(ele).empty();
$.ajax({
url: "${APP_PATH}/depts",
type: "get",
success: function (result) {
//显示部门信息到下拉列表中
$.each(result.extend.depts, function () { //不传参使用this代表当前被遍历的对象
var optionEle = $("<option></option>").append(this.deptName)
.attr("value", this.deptId).appendTo("ele");
});
}
});
}
效果图
2. 编写新建按钮的弹窗的保存按钮的保存效果
- 在EmployeeService.java中添加一个名为saveEmp的方法,用于保存新增的员工信息。
/**
* 员工保存方法
* @param employee
*/
public void saveEmp(Employee employee) {
//因为我们的员工id是自增的,所有使用insertSelective有选择的插入,而不是insert。
employeeMapper.insertSelective(employee);
}
- 在EmployeeController.java中新增一个名为saveEmp的方法,用于保存新增的员工信息。
/**
* 保存新增的员工信息
* Rest风格的URI,我们规定post的请求为保存请求
*/
@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(Employee employee){ //接收页面表单传递过来的employee对象信息
employeeService.saveEmp(employee);
return Msg.success();
}
-
在index.jsp页面中为弹窗的保存按钮添加一个id=“emp_save_btn”。
-
在index.jsp页面底部的script中添加一个全局变量
var totalRecord;
,为保存后的页面跳转做准备,此全局变量在分页信息那赋值。
//定义一个全局变量:总记录数和当前页(在分页信息那赋值)
var totalRecord, currentNum;
//----------------------------
function build_page_info(result) {
...
//为全局变量赋值
totalRecord = result.extend.pageInfo.total;
currentNum = result.extend.pageInfo.pageNum;
}
- 在index.jsp页面底部的script中为保存按钮添加点击保存事件。
//弹窗的保存按钮的点击保存事件
$("#emp_save_btn").click(function () {
//调用JQuery的serialize,系列化表单里的员工信息
//系列化后的字符串:empName=cat&email=cat%40qq.com&gender=F&dId=3
// alert($("#empAddModal form").serialize());
//发送ajax请求把保存表单内新增的员工信息提交给服务器
$.ajax({
url: "${APP_PATH}/emp",
type: "post",
data: $("#empAddModal form").serialize(),
success: function(result){
// alert(result.msg);
//当保存成功:
//1.关闭弹窗
$("#empAddModal").modal('hide');
//2.跳转到最后一页
// (因为我们已经添加了bootstrap的合理化参数,所以当超过总页数将会跳转到最后一页)
to_page(totalRecord);
}
});
});
效果图
3. 问弹窗表单增加校验功能
提交的数据需要满足才可保存:
- 用户名合法
- 邮箱合法
- 员工姓名不重复(只是示例,练习,可把员工姓名看成用户名就不会觉得逻辑有问题了)
校验员工姓名和邮箱
- 在弹窗的保存按钮的点击保存事件的中最上面添加,先进行数据的校验。
//对提交的数据进行校验
if(!validate_add_form()){
return false;
}
- 在script标签中新建一个validate_add_form的方法,用于数据的校验。
//校验表单数据
function validate_add_form(){
//拿到数据,用jQuery的正则表达式进行校验
//校验员工姓名
var empName = $("#empName_add_input").val();
//正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文)
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if(!regName.test(empName)){
alert("用户名可以是2-5位中文或6-16个英文和数字的组合!");
return false;
}
//校验邮箱
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if(!regEmail.test(email)){
alert("邮箱格式不正确!");
return false;
}
//校验通过
return true;
}
效果:
-
使用bootstrap官网全局css样式美化错误提醒。
- 在body标签中,弹窗代码内的表单的empName和email位置的
<input type="text" .../>
下添加<span class="help-block"></span>
,用于错误时显示的提示信息。 - 新建一个show_validate_msg方法,用于校验的提示信息。
//校验的提示信息 //ele校验的元素,status校验状态,msg提示信息 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); } }
- 修改js中校验表单数据方法
//校验表单数据 function validate_add_form(){ //拿到数据,用jQuery的正则表达式进行校验 //校验员工姓名 var empName = $("#empName_add_input").val(); //正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文) 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", ""); } //校验邮箱 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; }
- 在body标签中,弹窗代码内的表单的empName和email位置的
-
为了给用户更好的体验效果,我们再给输入文本框增加一个失去焦点事件,让用户输入完文本后,就发起校验,而不用等到去点击保存才提示,顺便解决了用户名和邮箱都不合法,只有用户名提示错误信息。(当然保存的校验也要保留)
- 把validate_add_form方法拆为validate_add_form_empName和validate_add_form_email两个方法。
//校验表单员工名 function validate_add_form_empName(ele){ //拿到数据,用jQuery的正则表达式进行校验 //校验员工姓名 var empName = $(ele).val(); //正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文) var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/; if(!regName.test(empName)){ // alert("用户名可以是2-5位中文或6-16个英文和数字的组合!"); //显示校验的信息 show_validate_msg(ele, "error", "用户名可以是2-5位中文或6-16个英文和数字的组合!"); return false; }else{ show_validate_msg(ele, "success", ""); } //校验通过 return true; } //校验表单邮箱 function validate_add_form_email(ele) { //校验邮箱 var email = $(ele).val(); var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/; if(!regEmail.test(email)){ // alert("邮箱格式不正确!"); //显示校验的信息 show_validate_msg(ele, "error", "邮箱格式不正确!"); return false; }else{ show_validate_msg(ele, "success", ""); } //校验通过 return true; }
- 把弹窗的保存按钮的点击保存事件中的判断稍做修改。
//弹窗的保存按钮的点击保存事件 $("#emp_save_btn").click(function () { //对提交的数据进行校验 if(!validate_add_form_empName("#empName_add_input") || !validate_add_form_email("#email_add_input")){ alert("请正确输入信息!"); return false; }
- 在js中新建两个文本框的失去焦点事件。
//员工名输入框失去焦点校验事件(弹窗) $("#empName_add_input").blur(function () { validate_add_form_empName("#empName_add_input"); }); //邮箱输入框失去焦点校验事件(弹窗) $("#email_add_input").blur(function () { validate_add_form_email("#email_add_input"); });
- 在新增按钮的点击弹窗事件中增加表单重置功能,每次打开都是初始状态。
//清除表单数据(表单重置) //清空文本框内容 $("#empAddModal form")[0].reset(); //去除表单样式 $("#empAddModal form").find("*").removeClass("has-success has-error"); //清空有带有help-block类的内容(即错误信息) $("#empAddModal form").find(".help-block").text("");
校验员工姓名是否重复
- 在DepartmentExample.java中新建一个查询用户名是否可用的方法。
/**
* 查询用户名是否已存在
* @param empName
* @return true为可用(输入的用户名不存在)
*/
public boolean checkUser(String empName) {
//查询条件
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
//查询数据库中emp_name和传参empName相同的记录数
criteria.andEmpNameEqualTo(empName);
//countByExample方法返回符合条件的记录数
long count = employeeMapper.countByExample(example);
return count == 0;
}
- 在EmployeeController.java中新建方法。
/**
* 校验用户名是否已存在
*/
@RequestMapping("/checkuser")
@ResponseBody
public Msg checkuser(@RequestParam("empName")String empName){
boolean b = employeeService.checkUser(empName);
if(b){
//用户名可用
return Msg.success();
}else{
//用户名不可用
return Msg.fail();
}
}
- 在index.jsp的js中新建一个方法。
//检验用户名是否可用
function validate_usable_empName(ele) {
//获取输入框的内容
var empName = $(ele).val();
//发送ajax请求校验用户名是否存在
$.ajax({
url: "${APP_PATH}/checkuser",
data: "empName=" + empName,
type: "get",
success: function (result) {
//判断是否成功(100为成功,200为失败)
if(100 == result.code){
show_validate_msg(ele, "success", "用户名可用");
//并给保存按钮添加一个自定义属性,success代表用户名可用
$("#emp_save_btn").attr("ajax-va", "success");
}else{
show_validate_msg(ele, "error", "用户名已存在!");
//并给保存按钮添加一个自定义属性,fail代表用户名不可用
$("#emp_save_btn").attr("ajax-va", "error");
}
}
});
}
-
在js的validate_add_form_empName方法中的else里中调用validate_usable_empName方法,实现用户名输入框失去焦点后先校验格式,格式符合再校验用户名是否可用。
-
因为用户名通过格式校验后,用户名是否可用保存按钮不知道,所以需要在保存按钮的点击事件里数据校验判断之下再加一个判断。
//判断用户名是否通过可用性校验
if($(this).attr("ajax-va") == "error"){
//没通过,不保存
alert("请正确输入信息!");
return false;
}
后端校验数据
-
对用户名进行校验
- 在EmployeeController.java的checkuser中也进行用户名的校验。
/** * 校验用户名是否已存在 */ @RequestMapping("/checkuser") @ResponseBody public Msg checkuser(@RequestParam("empName")String empName){ //后端判断用户名的合法性 String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})"; //如果匹配失败,直接返回 if(!empName.matches(regx)){ return Msg.fail().add("va_msg", "用户名必须是6-16个英文和数字或2-5位中文的组合!"); } //数据库用户名重复校验 boolean b = employeeService.checkUser(empName); if(b){ //用户名可用 return Msg.success(); }else{ //用户名不可用 return Msg.fail().add("va_msg", "用户名已存在!"); } }
- index.jsp里的validate_usable_empName方法中,ajax请求的success的else中show_validate_msg的错误信息就改为result.extend.va_msg,从后端拿到的错误信息。
function validate_usable_empName(ele) { ... }else{ //错误信息从后端返回的数据中获取 show_validate_msg(ele, "error", result.extend.va_msg); ... }
-
JSR303校验
- 导入依赖
<!-- JSR303校验 --> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.2.Final</version> </dependency>
- 在Employee.java类的empName和email属性上加上校验注解。
//@Pattern(regexp = "", message 错误信息) 自定义校验注解 @Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})", message = "用户名必须是6-16个英文和数字或2-5位中文的组合!") private String empName; //@Email //邮箱校验注解 @Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$", message = "邮箱格式不正确!") private String email;
- 修改EmployeeController.java中的saveEmp方法。
/** * 保存新增的员工信息 * Rest风格的URI,我们规定post的请求为保存请求 * @param employee 页面表单传递过来的employee对象信息 * @param result 封装校验的结果 * @return */ @RequestMapping(value = "/emp", method = RequestMethod.POST) @ResponseBody //加上@Valid注解的参数需要校验 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) { //获取错误的字段名 System.out.println("错误的字段名:" + fieldError.getField()); //获取错误的信息 System.out.println("错误信息:" + fieldError.getDefaultMessage()); //把错误信息保存到map中 map.put(fieldError.getField(), fieldError.getDefaultMessage()); } return Msg.fail().add("errorFields", map); }else{ //校验成功 employeeService.saveEmp(employee); System.out.println(employee); return Msg.success(); } }
- 修改index.jsp中弹窗的保存按钮点击事件中ajax请求的success方法。
success: function(result){ if(100 == result.code){ //当保存成功: //1.关闭弹窗 $("#empAddModal").modal('hide'); //2.跳转到最后一页 // (因为我们已经添加了bootstrap的合理化参数,所以当超过总页数将会跳转到最后一页) to_page(totalRecord); }else{ //显示失败信息,哪个错误就显示哪个 if(undefined != result.extend.errorFields.empName){ //显示员工名字的错误信息 show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName); alert(result.extend.errorFields.empName); } if(undefined != result.extend.errorFields.email){ //显示邮箱的错误信息 show_validate_msg("#email_add_input", "error", result.extend.errorFields.email); alert(result.extend.errorFields.email); } } }
CRUD-修改
步骤
1、点击编辑
2、弹出用户修改的模态框(显示用户信息)
3、点击更新,完成用户修改
1. 实现点击编辑弹出员工信息模态框
- 在index.jsp中再添加一个模态框。
<%-- 员工修改的模态框 --%>
<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">
<%-- 表单 --%>
<%-- empName --%>
<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" class="form-control" name="empName" id="empName_update_input" placeholder="empName">
<span class="help-block"></span>
</div>
</div>
<%-- email --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="email" id="email_update_input" placeholder="email@qq.com">
<span class="help-block"></span>
</div>
</div>
<%-- gender --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="gender" id="gender1_update_input" value="M" checked> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2_update_input" value="F"> 女
</label>
</div>
</div>
<%-- deptName --%>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<%-- 提交部门id即可 --%>
<select class="form-control" name="dId"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<%-- 弹窗关闭按钮 --%>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<%-- 弹窗保存按钮 --%>
<button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
</div>
</div>
</div>
</div>
-
把getDepts修改为有参函数。
-
在EmployeeService.java中新建一个名为getEmp的方法,用于根据id查询员工信息。
/**
* 根据id查询员工信息
* @param id
* @return
*/
public Employee getEmp(Integer id) {
Employee employee = employeeMapper.selectByPrimaryKey(id);
return employee;
}
- 在EmployeeController.java新建一个名为getEmp的方法,用于查询员工信息。
/**
* 查询员工信息
* 查询指定是get请求
* @param id
* @return
*/
@RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
@ResponseBody
public Msg getEmp(@PathVariable("id")Integer id){
//查询指定的员工信息
Employee employeee = employeeService.getEmp(id);
return Msg.success().add("emp", employeee);
}
- 解析显示员工信息的方法build_emps_table中的循环里,为修改增加一个自定义属性,就能让每个按钮和对应的员工绑定起来,同理,在这里先把删除按钮也一起设置。
function build_emps_table(result) {
...
$.each(){
...
//修改删除按钮,在同一个单元格内
var editBtn = $("<butt..
//为编辑按钮添加一个自定义属性,表示当前员工id
editBtn.attr("edit-id", item.empId);
var delBtn...
//同理,也为删除按钮添加一个自定义属性
delBtn.attr("del-id", item.empId);
...
}
...
}
- 为修改按钮添加点击事件。
//因为在按钮创建之前就绑定click,所以绑定不了
//解决:在创建按钮后在绑定 或 绑定点击.live()
//jquery新版用on代替了live
//为修改按钮添加点击事件
$(document).on("click", ".edit_btn", function () {
//查出并显示部门信息
getDepts("#empUpdateModal select");
//查出并显示员工信息,$(this)当前被点击的编辑按钮
getEmp($(this).attr("edit-id"));
//把员工的id传递给模态框的更新按钮
$("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
//调用模态框
$("#empUpdateModal").modal({
backdrop: "static"
});
});
- js中新建一个查询员工信息的方法。
//查询员工信息
function getEmp(id){
$.ajax({
url: "${APP_PATH}/emp/" + id,
type: "get",
success: function (result) {
//获取员工信息
var empData = result.extend.emp;
//员工姓名
$("#empName_update_static").text(empData.empName);
//邮箱
$("#email_update_input").val(empData.email);
//性别
$("#empUpdateModal input[name=gender]").val([empData.gender]);
//下拉列表
$("#empUpdateModal select").val([empData.dId]);
}
});
完成员工对应信息在模态框显示。
2. 实现点击弹窗内更新按钮修改员工信息
- js中为修改模态框邮箱输入框新建失去焦点校验事件,用于在用户修改邮箱后校验邮箱的合法性。
//修改模态框邮箱输入框失去焦点校验事件(弹窗)
$("#email_add_input").blur(function () {
validate_add_form_email("#email_update_input");
});
- 并在修改按钮事件里添加清空前一次校验样式。
$(document).on("click", ".edit_btn", function () {
//清除当前元素的校验状态
$("#email_update_input").parent().removeClass("has-success has-error");
$("#email_update_input").next("span").text("");
...
}
- 在EmployeeService.java中新建一个updateEmp方法,用于根据主键有选择的更新员工信息。
/**
* 根据主键有选择的更新员工信息
* @param employee
*/
public void updateEmp(Employee employee) {
employeeMapper.updateByPrimaryKeySelective(employee);
}
- 在EmployeeController.java中新建一个saveEmp方法,用于员工的更新。
/**
* 员工更新
* 更新指定put请求
* @param employee
* @return
*/
@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
@ResponseBody
public Msg saveEmp(Employee employee){
//更新员工信息
employeeService.updateEmp(employee);
return Msg.success();
}
- 然后为模态框的更新按钮添加点击事件。
//更新按钮的点击事件
$("#emp_update_btn").click(function () {
//校验邮箱信息
if (!validate_add_form_email("#email_update_input")){
alert("邮箱格式不正确,请输入正确的邮箱");
return false;
}
//发送ajax请求更新员工信息
$.ajax({
url: "${APP_PATH}/emp/" + $(this).attr("edit-id"),
//第一种方法:
// 如果ajax直接发put请求,请求体中的数据,request.getgetParameter("empName")拿不到
// tomcat发现是put请求,就不会封装数据为map,只有post形式的请求才会封装请求体为map
// 所以要在web.xml中注册FormContentFilter过滤器,支持put和delete请求
//第二种方法:
// ajax发送post请求,并在发送的data加上 "_method=put"
// HiddenHttpMethodFilter把post转为put
type: "put",
data: $("#empUpdateModal form").serialize(),
success: function (result) {
//关闭对话框
$("#empUpdateModal").modal("hide");
//回到本页面(刷新)
to_page(currentPage);
}
});
});
CRUD-删除
步骤
1、单个删除
2、多个删除
1. 实现单个删除
- 在EmployeeService.java中新建deleteEmp方法,用于根据id删除指定员工信息。
/**
* 根据id删除指定员工信息
* @param id
*/
public void deleteEmp(Integer id) {
employeeMapper.deleteByPrimaryKey(id);
}
- 在EmployeeController.java中新建deleteEmp方法,用于删除单个员工信息。
/**
* 删除单个员工信息
* 删除指定delete请求
* @param id
* @return
*/
@RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE)
public Msg deleteEmpById(@PathVariable("id")Integer id){
//按照id删除指定员工信息
employeeService.deleteEmp(id);
return Msg.success();
}
- 在js中为员工对应的删除按钮添加点击事件(单个删除)。
//为员工对应的删除按钮添加点击事件(单个删除)
$(document).on("click", ".delete_btn", function () {
//获取删除的员工姓名
var empName = $(this).parents("tr").find("td:eq(1)").text();
//获取删除的员工id
var empId = $(this).attr("del-id");
//弹出是否确认删除提示
if(confirm("确定要删除【" + empName + "】吗?")){
//确认,发送ajax请求删除员工
$.ajax({
url: "${APP_PATH}/emp/" + empId,
type: "delete",
success: function (result) {
//回到本页(刷新页面)
to_page(currentPage);
}
});
}else {
//取消
return false;
}
});
2. 多选删除
- 为行首添加checkbox全选选项。
...
<thead>
<tr>
<th>
<input type="checkbox" id="check_all">
</th>
<th>empId</th>
<th>empName</th>
<th>gender</th>
...
- 在build_emps_table函数中为员工行也添加上checkbox选项。
...
$.each(emps, function (index, item) {
var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
//员工信息单元格
...
//把相同员工的单元格添加到同一行
$("<tr></tr>")
.append(checkBoxTd)
.append(empIdTd)
.append(empNameTd)
.append(genderTd)
.append(emailTd)
...
- 为th行首的全选按钮添加点击全选/全不选事件。
$("#check_all").click(function () {
//attr获取checked是undefined;
//attr获取自定义属性的值;
//prop修改和读取dom原生属性的值
//check_item应跟随全选按钮,一同选中或不选中
$(".check_item").prop("checked", $(this).prop("checked"));
});
-
因为我们多加了一列,所以之前单个员工删除按钮事件中获取员工姓名需要改为2。
-
为td行首的按钮添加点击事件。
//check_item的点击事件
$(document).on("click", ".check_item", function () {
//是否满足选中的个数和当前页员工的个数相同
var flag = $(".check_item:checked").length == $(".check_item").length;
//check_all全选按钮要和判断的结果相同,如果相同就选中,不同不选中
$("#check_all").prop("checked", flag);
});
- 在EmployeeService.java中新建一个deleteBatch方法,用于批量删除。
/**
* 批量删除员工信息
* @param ids
*/
public void deleteBatch(List<Integer> ids) {
//自定义条件
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
//删除语句将变成:delete from xxx where emd_id in (1, 2, 4 ...)
criteria.andEmpIdIn(ids);
employeeMapper.deleteByExample(example);
}
- 修改EmployeeController.java中的deleteEmpById改为deleteEmp,并修改内容实现单个多选二合一删除。
/**
* 单个多选二合一删除员工信息
* 多个删除:id中间用-分隔,如 1-2-4
* 单个删除:如3
* 删除指定delete请求
* @param ids
* @return
*/
@RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
@ResponseBody
public Msg deleteEmp(@PathVariable("ids")String ids){
//判断是否是多个删除
if(ids.contains("-")){
//多个删除
//分隔成数组
String[] str_ids = ids.split("-");
List<Integer> del_ids = new ArrayList<>();
for (String id : str_ids) {
del_ids.add(Integer.parseInt(id));
}
//批量删除
employeeService.deleteBatch(del_ids);
}else{
//单个删除
//按照id删除指定员工信息
Integer id = Integer.parseInt(ids);
employeeService.deleteEmp(id);
}
return Msg.success();
}
- 为上方删除按钮添加点击删除选中员工信息事件。
//为上方删除按钮添加点击删除选中员工信息事件
$("#emp_delete_modal_btn").click(function () {
var empName = "";
var del_idstr = "";
//遍历当前页被选中的员工
$.each($(".check_item:checked"), function () {
//获取被选中的员工姓名
empName += $(this).parents("tr").find("td:eq(2)").text() + ",";
//组装员工id字符串
del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";;
});
//去除多余 ,
empName = empName.substring(0, empName.length - 1);
//去除多余 -
del_idstr = del_idstr.substring(0, del_idstr.length - 1);
if(confirm("确定要删除【" + empName + "】吗?")){
//确认,发送ajax请求删除指定员工
$.ajax({
url: "${APP_PATH}/emp/" + del_idstr,
type: "delete",
success: function (result) {
//提示删除成功
alert(result.msg);
//回到当前页
to_page(currentPage);
}
});
}else{
//取消
return false;
}
});
磕磕碰碰的跟着老师做完了这个项目,第一次用ssm做项目,还是有很多知识点不够扎实,也学到了很多东西,学后端,前端的知识也需要了解,接下来继续练习,然后学习springboot。