一、基础环境搭建
1. 创建一个maven工程
导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.ssm</groupId>
<artifactId>ssm_crud</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--spring mvcweb-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.6</version>
</dependency>
<!--spring jdbc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.6</version>
</dependency>
<!--spring aspects-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.6</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--mybatis与spring整合适配包-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL驱动 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!--c3p0数据库连接池-->
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--jstl-->
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--servletapi-->
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
2. 引入bootstrap前端框架
- 下载bootstrap文档解压放在static文件目录下
- 引入
<%--
Created by IntelliJ IDEA.
User: long
Date: 2022/9/21
Time: 8:27
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<%--jquery--%>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<%--bootstrap--%>
<link rel="stylesheet" href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css">
<script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
</body>
</html>
3. 编写配置文件
1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--启动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>
<!--配置编码过滤器,一定要放在所有过滤器之前-->
<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>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置隐藏请求过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--springmvc的前端拦截器,拦截除jsp外的所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2. springMVC
文件名:dispatcherServlet-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--开启组件扫描-->
<context:component-scan base-package="com.atguigu.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>
<property name="suffix" value=".jsp"></property>
</bean>
<!--两个标准配置-->
<!--springmvc不能处理的东西交给tomcat-->
<mvc:default-servlet-handler />
<!--能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax,映射动态请求-->
<mvc:annotation-driven/>
</beans>
3. spring
文件名: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配置文件,这里主要配置和业务逻辑有关的
核心关注点:数据源、与mybatis的整合、事务控制
-->
<!--开启组件扫描。除了Controller其他都扫描-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--引入资源文件-->
<context:property-placeholder location="classpath:daconfig.properties"></context:property-placeholder>
<!--===============================数据源===============================-->
<bean id="poolDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--===============================配置和Mybatis的整合===============================-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定mybatis全局配置文件的位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!--配置数据源-->
<property name="dataSource" ref="poolDataSource"></property>
<!--指定mybatis中mapper文件的位置-->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!--配置一个可以执行批量的sqlSession-->
<bean class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
<constructor-arg name="executorType" value="BATCH"/>
</bean>
<!--配置扫描器,将mybatis接口的实现加入到ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描所有的dao接口-->
<property name="basePackage" value="com.atguigu.crud.dao"></property>
</bean>
<!--===============================事务控制的配置===============================-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--控制数据源-->
<property name="dataSource" ref="poolDataSource"></property>
</bean>
<!--开启基于注解的事务,使用xml配置文件形式的事务(重要的事务用品味至文件)-->
<aop:config>
<!--切入点表达式
*(任意权限修饰符) com.atguigu.crud.service..(service下以及子包内的所有类)*(..)(任意方法的任意参数))
-->
<aop:pointcut id="txPoint" expression="execution(* com.atguigu.crud.service..*(..))"/>
<!--配置事务增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
</aop:config>
<!--配置事务增强,事务如何切入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--切入的所有方法都是事务方法-->
<tx:method name="*"/>
<!--以get开头的所有方法设置只读-->
<tx:method name="get*" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
</beans>
4. mybatis
文件名:mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--转驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<!--取别名-->
<package name="com.atguigu.crud.bean"/>
</typeAliases>
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--指定页面在1-最后一页之间,如果出现超过的情况会当最后一页处理,如果出现0和负数当做第一页处理-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
</configuration>
5. mybatis逆向工程
导入依赖:
<!--mybaits逆向工程-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
创建generatorConfig.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版) -->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=UTC"
userId="root" password="root"></jdbcConnection>
<!-- javaBean的生成位置-->
<javaModelGenerator targetPackage="com.atguigu.crud.bean" targetProject=".\src\main\java">
<!--是否使用子包,开启时com.atguigu.mybatis.pojo会变成一层一层的目录
不开启则默认com.atguigu.mybatis.pojo就是目录名字,不会创建多层目录-->
<property name="enableSubPackages" value="true"/>
<!--去除字段名两边的空格-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.crud.dao"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 逆向分析每个表的生成策略 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="tbl_emp" domainObjectName="Emp"/>
<table tableName="tbl_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration>
通过java运行逆向工程:
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MBGTest {
public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
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);
}
}
二、测试功能
package com.atguigu.crud.testMapper;
import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import com.atguigu.crud.dao.DeptMapper;
import com.atguigu.crud.dao.EmpMapper;
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.List;
import java.util.UUID;
/**
* 1、导入springtest单元测试,可以注入我们需要的组件
* 2、@ContextConfiguration指定Spring配置文件所在的位置
* 3、直接Autowired要使用的组件即可
*/
@RunWith(SpringJUnit4ClassRunner.class)//使用Spring提供的单元测试模块
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestDeptMapper {
@Autowired
DeptMapper deptMapper;
@Autowired
EmpMapper empMapper;
@Autowired
SqlSession sqlSession;
/**
* 测试插入
*/
@Test
public void testSelectByExampleWithDept() {
// Emp emp = new Emp();
// emp.setDid(1);
// emp.setEmail("123@qq.com");
// emp.setEmpName("李四");
// emp.setGender("男");
// empMapper.insertSelective(emp);
//实现批量插入
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
for (int i = 0; i < 1000; i++) {
String uuid = UUID.randomUUID().toString().substring(0, 5) + String.valueOf(i);
Emp emp1 = new Emp();
emp1.setGender("男");
emp1.setEmpName(uuid);
emp1.setEmail(uuid+"@qq.com");
emp1.setDid(2);
mapper.insertSelective(emp1);
}
}
/**
* 测试插入
*/
@Test
public void testInsertDept(){
Dept dept = new Dept();
dept.setDeptName("开发部");
deptMapper.insertSelective(dept);
}
/**
* 测试查询
*/
@Test
public void testSelectEmp(){
EmpExample empExample = new EmpExample();
empExample.createCriteria().andEmpNameEqualTo("张三");
// Emp emp = empMapper.selectByPrimaryKey(2);
// System.out.println(emp);
List<Emp> emps = empMapper.selectByExampleWithDept(empExample);
emps.forEach(System.out::println);
}
}
三、实现功能
- 访问index.jsp页面
- index.jsp页面发送出查询员工列表请求
- EmployeeController来接受请求,查出员工数据来
- 到list.jsp页面进行展示
1. 接口功能实现
1.1 EmpController
package com.atguigu.crud.controller;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
public class EmpController {
@Autowired
EmpService empService;
/**
* 查询所有员工信息
*
* @return
*/
@RequestMapping("/emps")
public ModelAndView getEmps(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
ModelAndView modelAndView = new ModelAndView();
//开启分页查询
PageHelper.startPage(pageNumber, 4);
List<Emp> emps = empService.getAll();
//navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
//封装了分页信息与查询结果
PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
modelAndView.addObject("pageInfo", empPageInfo);
modelAndView.setViewName("list");
return modelAndView;
}
}
1.2 EmpService
package com.atguigu.crud.service;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.dao.EmpMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmpService {
@Autowired
EmpMapper empMapper;
/**
* 查询所有员工信息
* @return
*/
public List<Emp> getAll() {
return empMapper.selectByExampleWithDept(null);
}
}
1.3 EmpMapper
package com.atguigu.crud.dao;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface EmpMapper {
/**
* 带上部门的员工信息
* @param empId
* @return
*/
Emp selectByPrimaryKeyWithDept(Integer empId);
/**
* 带上部门信息的员工信息
* @param example
* @return
*/
List<Emp> selectByExampleWithDept(EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
long countByExample(EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int deleteByExample(EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int deleteByPrimaryKey(Integer empId);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int insert(Emp record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int insertSelective(Emp record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
List<Emp> selectByExample(EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
Emp selectByPrimaryKey(Integer empId);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int updateByExampleSelective(@Param("record") Emp record, @Param("example") EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int updateByExample(@Param("record") Emp record, @Param("example") EmpExample example);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int updateByPrimaryKeySelective(Emp record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table tbl_emp
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
int updateByPrimaryKey(Emp record);
}
2. 前端功能实现(抛弃)
因为这样做每次需要返回大量数据,导致访问速度变慢,实现基本展示后使用ajax请求访问后台,实现异步显示。
2.1 index.jsp跳转list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/emps"></jsp:forward>
2.2 list实现数据展示
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
http://localhost:3306/crud
-->
<script src="${APP_PATH}/static/js/jquery-3.6.0.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/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<div class="container">
<!-- 标题 -->
<div class="row">
<div class="col-md-12">
<h1>SSM-CRUD BY PL</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>#</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=="男"?"male":"female"}</td>
<td>${emp.email}</td>
<td>${emp.dept.deptName}</td>
<td>
<button class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
编辑
</button>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-remove" 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?pageNumber=1">首页</a></li>
<%--如果有上一页才显示上一页--%>
<c:if test="${pageInfo.hasPreviousPage}">
<li class="disabled">
<a href="${APP_PATH}/emps?pageNumber=${pageInfo.prePage}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<c:forEach items="${pageInfo.navigatepageNums}" var="page_Num">
<%--判断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?pageNumber=${page_Num}">${page_Num}</a></li>
</c:if>
</c:forEach>
<%--如果有上一页才显示上一页--%>
<c:if test="${pageInfo.hasNextPage}">
<li>
<a href="${APP_PATH}/emps?pageNumber=${pageInfo.nextPage}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<li><a href="${APP_PATH}/emps?pageNumber=${pageInfo.pages}">末页</a></li>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
3. 用ajax进行交互(推荐)
- index.jsp页面直接发送ajax请求进行员工分页数据的查询
- 服务器将查出的数据,以json字符串的形式返回给浏览器
- 浏览器收到js字符串。可以使用js对json进行解析,使用js通过dom增删改改变页面
- 返回json,实现客户端的无关性
3.1 index.jsp用ajax请求展示数据
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
http://localhost:3306/crud
-->
<script src="${APP_PATH}/static/js/jquery-3.6.0.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/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<div class="container">
<!-- 标题 -->
<div class="row">
<div class="col-md-12">
<h1>SSM-CRUD</h1>
</div>
</div>
<!-- 按钮 -->
<div class="row">
<div class="col-md-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_tables">
<thead>
<tr>
<th>#</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<%--显示分页信息--%>
<div class="row">
<%--分页信息--%>
<div class="col-md-6" id="page_info_area">
</div>
<%--分页条信息--%>
<div class="col-md-6" id="page_nav_area">
</div>
</div>
</div>
<script type="text/javascript">
//页面加载完以后,直接发送一个ajax请求,要到分页数据
$(function () {
//去第一页
to_page(4);
});
function build_emps_table(result) {
//清空div中的数据
$("#emps_tables tbody").empty();
//拿到所有的员工数据
var emps = result.extend.pageInfo.list;
$.each(emps, function (index, item) {
// alert(item.empName);
var empId = $("<td></td>").append(item.empId);//员工id的td
var empName = $("<td></td>").append(item.empName);//员工姓名的td
var gender = $("<td></td>").append(item.gender);//员工性别的td
var email = $("<td></td>").append(item.email);//员工邮箱的td
var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
//编辑按钮
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil").append("编辑");
//删除按钮
var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove").append("删除");
//将两个按钮放到一个单元格中
var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
//将单元格加入到tr中,且将tr加入到表格体中
$("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
});
}
/*
{"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
"nextPage":2,"isFirstPage":true,"isLastPage":false,
"hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
"navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
"navigateLastPage":5}}}
*/
//解析并显示分页信息
function build_page_info(result) {
//清空分页信息数据
$("#page_info_area").empty();
//拿到分页数据
var page_number = result.extend.pageInfo.pageNum;//当前页
var pages = result.extend.pageInfo.pages;//总页数
var total = result.extend.pageInfo.total;//总数据条数
$("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
}
//解析并显示分页条信息
function build_page_nav(result) {
//page_nav_area
$("#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("«"));
//如果有是第一页则添加禁用样式
if (result.extend.pageInfo.isFirstPage == true) {
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
}else {
//点击时跳转到上一页或前一页
firstPageLi.click(function (){
to_page(1);
});
prePageLi.click(function (){
to_page(result.extend.pageInfo.prePage);
});
}
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
//如果有是第最后一页则添加禁用样式
if (result.extend.pageInfo.isLastPage == true) {
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
}else {
//点击时跳转到下一页或最后一页
nextPageLi.click(function (){
to_page(result.extend.pageInfo.nextPage);
});
lastPageLi.click(function (){
to_page(result.extend.pageInfo.pages);
});
}
//添加首页和前一页 的提示
ul.append(firstPageLi).append(prePageLi);
//1,2,3遍历给ul中添加页码提示
$.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
var numLi = $("<li></li>").append($("<a></a>").append(item));
if (result.extend.pageInfo.pageNum == item) {
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);
navEle.appendTo("#page_nav_area");
}
function to_page(pageNumber) {
$.ajax({
url: "${APP_PATH}/emps",
data: "pageNumber=" + pageNumber,
type: "GET",
success: function (result) {
// console.log(result);
//1、解析并显示员工数据
build_emps_table(result);
//2、解析并显示分页信息
build_page_info(result);
//3、解析并显示分页条数据
build_page_nav(result);
}
});
}
</script>
</body>
</html>
3.2 后台发送返回json数据
3.2.1 新增Msg类专门用于存储数据用于返回
package com.atguigu.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<String, Object>();
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;
}
}
3.2.2 导入jackson包
<!--返回json字符串的支持-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
3.2.3 返回json数据的方法
返回json数据的前提条件:
- 导入了jackson
- 开启了mvc注解驱动<mvc:annotation-driven />
- 加入了@ResponseBody注解
- 直接返回对象即可,将自动转换成json字符串
@RequestMapping("/emps")
@ResponseBody//直接返回json字符串
public Msg getEmpsWithJson(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
//开启分页查询
PageHelper.startPage(pageNumber, 4);
List<Emp> emps = empService.getAll();
//navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
//封装了分页信息与查询结果
PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
return Msg.success().add("pageInfo",empPageInfo);
}
4. 实现新增功能
-
在index.jsp页面点击"新增”
-
弹出新增对话框
-
去数据库查询部门列表,显示在对话框中
-
用户输入数据进行校验
-
完成保存
URI:
- /emp/{id} GET请求:查询员工
- /emp POST请求:保存员工
- /emp/{id} PUT请求: 修改员工
- /emp/{id} DELETE 请求:删除员工
前端:
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
http://localhost:3306/crud
-->
<script src="${APP_PATH}/static/js/jquery-3.6.0.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/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<%--员工添加的模态框--%>
<!-- Modal -->
<div class="modal fade" id="empAndModal" 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">员工姓名</label>
<div class="col-sm-10">
<input type="text" name="empName" class="form-control" id="empName_add_input"
placeholder="empName">
<span id="empName_span" class="help-block"></span>
</div>
</div>
<div class="form-group">
<label for="email_add_input" class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="email" name="email" class="form-control" id="email_add_input"
placeholder="123456@qq.com">
<span id="email_span" class="help-block"></span>
</div>
</div>
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">性别</label>
<label class="radio-inline">
<input type="radio" name="gender" id="male" value="男" checked="checked"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="remale" value="女"> 女
</label>
</div>
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">所属部门</label>
<div class="col-sm-4">
<%--部门下拉框--%>
<select class="form-control" id="dept_add_select" 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_sava_btn">保存</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-4 col-md-offset-8">
<button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<!-- 显示表格数据 -->
<div class="row">
<div class="col-md-12">
<table class="table table-hover" id="emps_tables">
<thead>
<tr>
<th>#</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<%--显示分页信息--%>
<div class="row">
<%--分页信息--%>
<div class="col-md-6" id="page_info_area">
</div>
<%--分页条信息--%>
<div class="col-md-6" id="page_nav_area">
</div>
</div>
</div>
<script type="text/javascript">
var totalPage;//总记录数
//页面加载完以后,直接发送一个ajax请求,要到分页数据
$(function () {
//去第一页
to_page(1);
});
function build_emps_table(result) {
//清空div中的数据
$("#emps_tables tbody").empty();
//拿到所有的员工数据
var emps = result.extend.pageInfo.list;
$.each(emps, function (index, item) {
// alert(item.empName);
var empId = $("<td></td>").append(item.empId);//员工id的td
var empName = $("<td></td>").append(item.empName);//员工姓名的td
var gender = $("<td></td>").append(item.gender);//员工性别的td
var email = $("<td></td>").append(item.email);//员工邮箱的td
var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
//编辑按钮
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil").append("编辑");
//删除按钮
var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove").append("删除");
//将两个按钮放到一个单元格中
var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
//将单元格加入到tr中,且将tr加入到表格体中
$("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
});
}
/*
{"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
"nextPage":2,"isFirstPage":true,"isLastPage":false,
"hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
"navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
"navigateLastPage":5}}}
*/
//解析并显示分页信息
function build_page_info(result) {
//清空分页信息数据
$("#page_info_area").empty();
//拿到分页数据
var page_number = result.extend.pageInfo.pageNum;//当前页
var pages = result.extend.pageInfo.pages;//总页数
var total = result.extend.pageInfo.total;//总数据条数
totalPage = result.extend.pageInfo.total;
$("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
}
//解析并显示分页条信息
function build_page_nav(result) {
//page_nav_area
$("#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("«"));
//如果有是第一页则添加禁用样式
if (result.extend.pageInfo.isFirstPage == true) {
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
} else {
//点击时跳转到上一页或前一页
firstPageLi.click(function () {
to_page(1);
});
prePageLi.click(function () {
to_page(result.extend.pageInfo.prePage);
});
}
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
//如果有是第最后一页则添加禁用样式
if (result.extend.pageInfo.isLastPage == true) {
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
} else {
//点击时跳转到下一页或最后一页
nextPageLi.click(function () {
to_page(result.extend.pageInfo.nextPage);
});
lastPageLi.click(function () {
to_page(result.extend.pageInfo.pages);
});
}
//添加首页和前一页 的提示
ul.append(firstPageLi).append(prePageLi);
//1,2,3遍历给ul中添加页码提示
$.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
var numLi = $("<li></li>").append($("<a></a>").append(item));
if (result.extend.pageInfo.pageNum == item) {
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);
navEle.appendTo("#page_nav_area");
}
function to_page(pageNumber) {
$.ajax({
url: "${APP_PATH}/emps",
data: "pageNumber=" + pageNumber,
type: "GET",
success: function (result) {
// console.log(result);
//1、解析并显示员工数据
build_emps_table(result);
//2、解析并显示分页信息
build_page_info(result);
//3、解析并显示分页条数据
build_page_nav(result);
}
});
}
//表单重置
function reset_form(ele){
//清空表单内容
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
//清空提示内容
$(ele).find(".help-block").text("");
}
//点击新增按钮弹出模态框
$("#emp_add_modal_btn").click(function () {
//清除表单数据(表单重置以及表单样式重置)
reset_form("#empAndModal form");
//查出部门信息,显示在下拉框中
getDepts();
//弹出模态框
$("#empAndModal").modal({
backdrop: "static"
});
});
//查出所有部门信息,并显示在下拉框中
function getDepts() {
$.ajax({
url: "${APP_PATH}/depts",
type: "GET",
success: function (result) {
//清除本来的数据
$("#dept_add_select").empty();
//拿到dept的信息并显示在下拉框中
$.each(result.extend.depts, function (index, item) {
$("<option></option>").append(item.deptName).attr("value", item.deptId).appendTo("#dept_add_select");
});
}
});
}
//对表单的数据进行校验
function validate_add_from() {
//拿到要校验的数据,使用正则表达式
//校验姓名
var empName = $("#empName_add_input").val();
var regName = /([a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if (!regName.test(empName)) {
show_validate_msg("#empName_add_input", "error", "用户名必须是6-16位数字和字母的组合或者2-5位中文");
return false;
} else {
show_validate_msg("#empName_add_input", "success", "");
}
//校验邮箱
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
show_validate_msg("#email_add_input", "error", "邮箱格式不正确")
return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
return true;
}
function show_validate_msg(ele, status, msg) {
//清除当前元素校验状态
$(ele).parent().removeClass("has-error").removeClass("has-success");
if ("error" == status) {
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg);
} else if ("success" == status) {
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg);
}
}
//发送ajax请求校验用户是否可用
$("#empName_add_input").change(function () {
//拿到用户名中的值
var empName = $("#empName_add_input").val();
$.ajax({
url: "${APP_PATH}/checkNmpName",
type: "GET",
data: "empName=" + empName,
success: function (result) {
//数据库中没有这个人时提示可以使用
if ("100" == result.code) {
show_validate_msg("#empName_add_input", "success", "该用户名可用");
$("#emp_sava_btn").attr("ajax-va", "success");
} else if ("200" == result.code) {//数据库中有这个人时提示不可以使用
show_validate_msg("#empName_add_input", "error",
result.extend.va_msg);
$("#emp_sava_btn").attr("ajax-va", "error");
}
}
});
});
//点击保存时保存员工信息
$("#emp_sava_btn").click(function () {
//1、模态框中填写的表单数据提交给服务器进行保存
//校验数据合法性
if (!validate_add_from()) {
return false;
}
//发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
if ("error" == $(this).attr("ajax-va")) {
return false;
}
var data = $("#empAndModal form").serialize();//获取到表单中的数据
//2、发送ajax请求保存员工
$.ajax({
url: "${APP_PATH}/emp",
type: "POST",
data: data,
success: function (result) {
//打印处理成功信息
alert(result.msg);
//1、关闭模态框
$("#empAndModal").modal('hide');
//2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
// 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
to_page(totalPage);
}
});
});
</script>
</body>
</html>
EmpController:
package com.atguigu.crud.controller;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
public class EmpController {
@Autowired
private EmpService empService;
/**
* 分页查询员工信息,正常使用ResponseBody需要导入jackson包才可以转为json字符串的支持
*
* @param pageNumber
* @return
*/
@RequestMapping("/emps")
@ResponseBody//直接返回json字符串
public Msg getEmpsWithJson(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
//开启分页查询
PageHelper.startPage(pageNumber, 4);
List<Emp> emps = empService.getAll();
//navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
//封装了分页信息与查询结果
PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
return Msg.success().add("pageInfo", empPageInfo);
}
/**
* 插入员工信息
*
* @return
*/
@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(Emp emp) {
System.out.println(emp);
empService.savaEmp(emp);
return Msg.success();
}
/**
* 检查用户名是否可用,可用返回ture,不可用返回false
*
* @param empName
* @return
*/
@RequestMapping(value = "/checkNmpName")
@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位中文");
}
//数据库用户名重复校验
//可用则返回状态码100
if (empService.checkNotHasNmpName(empName)) {
return Msg.success();
} else {//不可用则返回状态码200
return Msg.fail().add("va_msg","用户名被占用");
}
}
/**
* 分页查询所有员工信息
*
* @return
*/
// @RequestMapping("/emps")
public ModelAndView getEmps(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
ModelAndView modelAndView = new ModelAndView();
//开启分页查询
PageHelper.startPage(pageNumber, 4);
List<Emp> emps = empService.getAll();
//navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
//封装了分页信息与查询结果
PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
modelAndView.addObject("pageInfo", empPageInfo);
modelAndView.setViewName("list");
return modelAndView;
}
}
EmpService:
package com.atguigu.crud.service;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import com.atguigu.crud.dao.EmpMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmpService {
@Autowired
private EmpMapper empMapper;
/**
* 查询所有员工信息
* @return
*/
public List<Emp> getAll() {
return empMapper.selectByExampleWithDept(null);
}
/**
* 保存员工
*/
public void savaEmp(Emp emp) {
empMapper.insertSelective(emp);
}
/**
* 检查数据库中是否已经有了empName,如果有则返回false,没有则返回true
* @param empName
*/
public boolean checkNotHasNmpName(String empName) {
EmpExample example = new EmpExample();
example.createCriteria().andEmpNameEqualTo(empName);
long count = empMapper.countByExample(example);
return count == 0;
}
}
DeptController:
package com.atguigu.crud.controller;
import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.DeptService;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class DeptController {
@Autowired
private DeptService deptService;
/**
* 查询所有员工数据
* @param pageNumber
* @return
*/
@RequestMapping("/depts")
@ResponseBody
public Msg getDepts(@RequestParam(value="pageNumber",defaultValue = "1") Integer pageNumber){
List<Dept> depts = deptService.getDepts();
Msg msg = Msg.success().add("depts", depts);
return msg;
}
}
DeptService:
package com.atguigu.crud.service;
import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.dao.DeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptService {
@Autowired
private DeptMapper deptMapper;
public List<Dept> getDepts() {
return deptMapper.selectByExample(null);
}
}
4.1 加入后端校验(JSR303)
虽然前端做了数据校验,但是前端的数据可以更改,所以需要加上后端重要数据校验,(后端校验(SR303),唯一约束)。
-
导入Hibernate-Validator的jar包
-
给javabean的要校验的属性加上@Pattern注解
package com.atguigu.crud.bean;
import javax.validation.constraints.Pattern;
public class Emp {
/**
* This field was generated by MyBatis Generator.
* This field corresponds to the database column tbl_emp.emp_id
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
private Integer empId;
/**
* This field was generated by MyBatis Generator.
* This field corresponds to the database column tbl_emp.emp_name
*
* @mbg.generated Wed Sep 21 17:24:14 CST 2022
*/
@Pattern(regexp = "([a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})", message = "用户名必须是6-16位数字和字母的组合或者2-5位中文")
private String empName;
}
- 在方法中添加注解@Valid进行校验,用BindingResult来接收校验后的结果
/**
* 插入员工信息
*
* @return
*/
@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(@Valid Emp emp, BindingResult result) {
if (result.hasErrors()) {
//校验失败,应该返回失败,在模态框中显示校验失败的错误信息
List<FieldError> fieldErrors = result.getFieldErrors();
HashMap<String, Object> map = new HashMap<>();
for (FieldError fieldError : fieldErrors) {
System.out.println("错误的字段名:" + fieldError.getField());
System.out.println("错误信息:" + fieldError.getDefaultMessage());
//将错误字段和信息存储在map中
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return Msg.fail().add("errorFields", map);
} else {
empService.savaEmp(emp);
return Msg.success();
}
}
- 前端对后端返回的错误信息进行展示,或将成功信息展示
//点击保存时保存员工信息
$("#emp_sava_btn").click(function () {
//1、模态框中填写的表单数据提交给服务器进行保存
//校验数据合法性
if (!validate_add_from()) {
return false;
}
//发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
if ("error" == $(this).attr("ajax-va")) {
return false;
}
var data = $("#empAndModal form").serialize();//获取到表单中的数据
//2、发送ajax请求保存员工
$.ajax({
url: "${APP_PATH}/emp",
type: "POST",
data: data,
success: function (result) {
//code=100说明后台校验没问题
if (result.code == 100) {
//打印处理成功信息
// alert(result.msg);
//1、关闭模态框
$("#empAndModal").modal('hide');
//2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
// 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
to_page(totalPage);
} else {
//当后台校验出现问题的时候,显示失败信息
//有哪个字段的错误信息就显示哪个
if (undefined != result.extend.errorFields.email) {//邮箱不是未定义,则说明有错误返回
show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
} else if (undefined != result.extend.errorFields.empName) {
show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
}
}
}
});
});
5. 实现编辑功能
- 点击编辑
- 弹出用户修改的模态框(显示用户信息)
- 点击更新
前端:
<%@ page isELIgnored="false" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
http://localhost:3306/crud
-->
<script src="${APP_PATH}/static/js/jquery-3.6.0.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/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<%--员工添加的模态框--%>
<!-- Modal -->
<div class="modal fade" id="empAndModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">员工添加</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">员工姓名</label>
<div class="col-sm-10">
<input type="text" name="empName" class="form-control" id="empName_add_input"
placeholder="empName">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label for="email_add_input" class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="email" name="email" class="form-control" id="email_add_input"
placeholder="123456@qq.com">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<label class="radio-inline">
<input type="radio" name="gender" id="male" value="男" checked="checked"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="remale" value="女"> 女
</label>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-4">
<%--部门下拉框--%>
<select class="form-control" id="dept_add_select" 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_sava_btn">保存</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">员工编辑</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="empName_update_static" class="col-sm-2 control-label">员工姓名</label>
<div class="col-sm-10">
<p class="form-control-static" id="empName_update_static"></p>
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label for="email_update_input" class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="email" name="email" class="form-control" id="email_update_input"
placeholder="123456@qq.com">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<label class="radio-inline">
<input type="radio" name="gender" value="男" checked="checked"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" value="女"> 女
</label>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-4">
<%--部门下拉框--%>
<select class="form-control" id="dept_update_select" 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>
<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" id="emp_add_modal_btn">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<!-- 显示表格数据 -->
<div class="row">
<div class="col-md-12">
<table class="table table-hover" id="emps_tables">
<thead>
<tr>
<th>id</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">
var totalRecord;//总记录数
var currentNum;//当前页码
//页面加载完以后,直接发送一个ajax请求,要到分页数据
$(function () {
//去第一页
to_page(1);
});
function build_emps_table(result) {
//清空div中的数据
$("#emps_tables tbody").empty();
//拿到所有的员工数据
var emps = result.extend.pageInfo.list;
$.each(emps, function (index, item) {
// alert(item.empName);
var empId = $("<td></td>").append(item.empId);//员工id的td
var empName = $("<td></td>").append(item.empName);//员工姓名的td
var gender = $("<td></td>").append(item.gender);//员工性别的td
var email = $("<td></td>").append(item.email);//员工邮箱的td
var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
//编辑按钮
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil edit_btn").append("编辑");
//为编辑按钮添加一个自定义的属性,来表示当前员工id
editBtn.attr("edit-id", item.empId);
//删除按钮
var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove delete_btn").append("删除");
//为删除按钮添加一个自定义的属性,来表示当前员工id
deleteBtn.attr("delete-id", item.empId);
//将两个按钮放到一个单元格中
var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
//将单元格加入到tr中,且将tr加入到表格体中
$("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
});
}
/*
{"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
"nextPage":2,"isFirstPage":true,"isLastPage":false,
"hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
"navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
"navigateLastPage":5}}}
*/
//解析并显示分页信息
function build_page_info(result) {
//清空分页信息数据
$("#page_info_area").empty();
//拿到分页数据
var page_number = result.extend.pageInfo.pageNum;//当前页
currentNum = page_number;
var pages = result.extend.pageInfo.pages;//总页数
var total = result.extend.pageInfo.total;//总数据条数
totalRecord = total;
$("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
}
//解析并显示分页条信息
function build_page_nav(result) {
//page_nav_area
$("#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("«"));
//如果有是第一页则添加禁用样式
if (result.extend.pageInfo.isFirstPage == true) {
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
} else {
//点击时跳转到上一页或前一页
firstPageLi.click(function () {
to_page(1);
});
prePageLi.click(function () {
to_page(result.extend.pageInfo.prePage);
});
}
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
//如果有是第最后一页则添加禁用样式
if (result.extend.pageInfo.isLastPage == true) {
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
} else {
//点击时跳转到下一页或最后一页
nextPageLi.click(function () {
to_page(result.extend.pageInfo.nextPage);
});
lastPageLi.click(function () {
to_page(result.extend.pageInfo.pages);
});
}
//添加首页和前一页 的提示
ul.append(firstPageLi).append(prePageLi);
//1,2,3遍历给ul中添加页码提示
$.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
var numLi = $("<li></li>").append($("<a></a>").append(item));
if (result.extend.pageInfo.pageNum == item) {
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);
navEle.appendTo("#page_nav_area");
}
function to_page(pageNumber) {
$.ajax({
url: "${APP_PATH}/emps",
data: "pageNumber=" + pageNumber,
type: "GET",
success: function (result) {
// console.log(result);
//1、解析并显示员工数据
build_emps_table(result);
//2、解析并显示分页信息
build_page_info(result);
//3、解析并显示分页条数据
build_page_nav(result);
}
});
}
//表单重置
function reset_form(ele) {
//清空表单内容
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
//清空提示内容
$(ele).find(".help-block").text("");
}
//点击新增按钮弹出模态框
$("#emp_add_modal_btn").click(function () {
//清除表单数据(表单重置以及表单样式重置)
reset_form("#empAndModal form");
//查出部门信息,显示在下拉框中
getDepts("#dept_add_select");
//弹出模态框
$("#empAndModal").modal({
backdrop: "static"
});
});
//点击更新按钮,更新员工信息
$("#emp_update_btn").click(function () {
//验证邮箱是否合法
//验证邮箱信息
var email = $("#email_update_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
show_validate_msg("#email_update_input", "error", "邮箱格式不正确")
return false;
} else {
show_validate_msg("#email_update_input", "success", "");
}
//发送ajax请求保存更新的员工数据
$.ajax({
url: "${APP_PATH}/emp/" + $(this).attr("edit-id"),
type: "PUT",
data: $("#empUpdateModal form").serialize(),
success: function (result) {
//关闭对话框
$("#empUpdateModal").modal('hide');
//回到编辑的那一个页面
to_page(currentNum);
}
});
});
//我们是按钮创建之前就绑定了click,所以绑定不上
//方式一:可以在创建按钮的时候绑定事件
//方式二:live()可以为后来的元素绑定事件,但是新版本已经删除了,现在用on()
//点击编辑按钮弹出模态框
$(document).on("click", ".edit_btn", function () {
//清除表单数据(表单重置以及表单样式重置)
reset_form("#empUpdateModal form");
//1、查出部门列表
getDepts("#dept_update_select");
//2、查出员工信息
getEmp($(this).attr("edit-id"));
//3、将员工的id传递给模态框的更新按钮
$("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
//弹出模态框
$("#empUpdateModal").modal({
backdrop: "static"
});
});
function getEmp(id) {
$.ajax({
url: "${APP_PATH}/emp/" + id,
type: "GET",
success: function (result) {
//将信息填充到编辑窗口
var empData = result.extend.emp;//获取到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]);
}
});
}
//查出所有部门信息,并显示在下拉框中
function getDepts(ele) {
$.ajax({
url: "${APP_PATH}/depts",
type: "GET",
success: function (result) {
//清除本来的数据
$(ele).empty();
//拿到dept的信息并显示在下拉框中
$.each(result.extend.depts, function (index, item) {
$("<option></option>").append(item.deptName).attr("value", item.deptId).appendTo(ele);
});
}
});
}
//对表单的数据进行校验
function validate_add_from() {
//拿到要校验的数据,使用正则表达式
//校验姓名
var empName = $("#empName_add_input").val();
var regName = /([a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if (!regName.test(empName)) {
show_validate_msg("#empName_add_input", "error", "用户名必须是6-16位数字和字母的组合或者2-5位中文");
return false;
} else {
show_validate_msg("#empName_add_input", "success", "");
}
//校验邮箱
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
show_validate_msg("#email_add_input", "error", "邮箱格式不正确")
return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
return true;
}
function show_validate_msg(ele, status, msg) {
//清除当前元素校验状态
$(ele).parent().removeClass("has-error").removeClass("has-success");
if ("error" == status) {
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg);
} else if ("success" == status) {
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg);
}
}
//发送ajax请求校验用户是否可用
$("#empName_add_input").change(function () {
//拿到用户名中的值
var empName = $("#empName_add_input").val();
$.ajax({
url: "${APP_PATH}/checkNmpName",
type: "GET",
data: "empName=" + empName,
success: function (result) {
//数据库中没有这个人时提示可以使用
if ("100" == result.code) {
show_validate_msg("#empName_add_input", "success", "该用户名可用");
$("#emp_sava_btn").attr("ajax-va", "success");
} else if ("200" == result.code) {//数据库中有这个人时提示不可以使用
show_validate_msg("#empName_add_input", "error",
result.extend.va_msg);
$("#emp_sava_btn").attr("ajax-va", "error");
}
}
});
});
//点击保存时保存员工信息
$("#emp_sava_btn").click(function () {
//1、模态框中填写的表单数据提交给服务器进行保存
//校验数据合法性
if (!validate_add_from()) {
return false;
}
//发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
if ("error" == $(this).attr("ajax-va")) {
return false;
}
var data = $("#empAndModal form").serialize();//获取到表单中的数据
//2、发送ajax请求保存员工
$.ajax({
url: "${APP_PATH}/emp",
type: "POST",
data: data,
success: function (result) {
//code=100说明后台校验没问题
if (result.code == 100) {
//打印处理成功信息
// alert(result.msg);
//1、关闭模态框
$("#empAndModal").modal('hide');
//2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
// 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
to_page(totalRecord);
} else {
//当后台校验出现问题的时候,显示失败信息
//有哪个字段的错误信息就显示哪个
if (undefined != result.extend.errorFields.email) {//邮箱不是未定义,则说明有错误返回
show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
} else if (undefined != result.extend.errorFields.empName) {
show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
}
}
}
});
});
</script>
</body>
</html>
后端:
EmpController:
/**
* 如果直接用ajax发送put请求,会遇到一个问题:请求体中有数据,但是Emp对象封装不上
* 原因:这是tomcat的问题
* 1、请求体中的数据,会封装成一个map
* 2、reqeust.getParameter("empName")就会从这个map中取值
* 3、SpringMVC封装POJO对象的时候,会把POJO中的每个属性的值都用request.getParameter("属性名取出")
* 4、但是request.getParameter()拿不到数据,因为tomcat看到是put请求,就不会去封装数据为map,只有post请求才封装请求体。
* 5、解决方法:需要在web.xml中添加一个过滤器:HttpPutFormContentFilter,它的作用是将请求体中的数据解析包装成一个map,
* request被重新包装,request.getParameter()被重写,就会从自己封装的map中获取数据
*
* @param emp
* @return
*/
@PutMapping("/emp/{empId}")//这个{}中的名字需要跟Emp类中的属性名一致,否则注入不进去
@ResponseBody
public Msg updateEmp(Emp emp){
empService.updateEmp(emp);
return Msg.success();
}
EmpService:
/**
* 员工更新
* @param emp
*/
public void updateEmp(Emp emp) {
empMapper.updateByPrimaryKeySelective(emp);
}
6. 实现删除功能
前端新增逻辑:
//点击删除按钮,单个删除
$(document).on("click", ".delete_btn", function () {
//弹出确认删除对话框
var empName = $(this).parents("tr").find("td:eq(2)").text();
var deleteId = $(this).attr("delete-id");//获取要删除的员工id
if (confirm("确认删除【" + empName + "】吗?")) {
//确认,发送ajax请求删除
$.ajax({
url: "${APP_PATH}/emp/" + deleteId,
type: "delete",
success: function (result) {
alert(result.msg);
to_page(currentNum);//跳转到当前页
}
});
}
});
//完成全选、全不选功能
$("#checkall").click(function () {
//dom原生的属性用prop,attr可以用来获取自定义属性的值
var checked = $("#checkall").prop("checked");//选中返回true,没有选中返回false
$(".check_item").prop("checked", checked);//将下面的单选框状态变得跟checkall一样
});
//勾选全部单选框时自动选中全选框
$(document).on("click", ".check_item", function () {
//判断当前选中的元素是不是选满了
var flag = $(".check_item:checked").length == $(".check_item").length;//判断选中的个数是否是总个数
$("#checkall").prop("checked", flag);//如果flag为true则赋值,否则不复赋值
});
//完成全部删除
$("#delete_all").click(function () {
//找到被选中的单选框
var delete_emp_name = "";
var deleteIds = "";
$.each($(".check_item:checked"), function () {
delete_emp_name += $(this).parents("tr").find("td:eq(2)").text() + ",";//组装员工名字的字符串
deleteIds += $(this).parents("tr").find("td:eq(1)").text()+"-";//组装员工id字符串 1-2-3
});
//去除最后多余的符号
delete_emp_name = delete_emp_name.substring(0,delete_emp_name.length-1);
deleteIds = deleteIds.substring(0,deleteIds.length-1);
if (confirm("确认删除" + delete_emp_name + "吗?")) {
//确认,发送ajax请求删除
$.ajax({
url: "${APP_PATH}/emp/" + deleteIds,
type: "DELETE",
success: function (result) {
alert(result.msg);
to_page(currentNum);//跳转到当前页
}
});
}
});
后端删除方法:
EmpControlelr:
/**
* 单个或批量删除
* 批量删除:1-2-3
* 单个删除:1
*
* @param ids
* @return
*/
@RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
@ResponseBody
public Msg deleteEmp(@PathVariable("ids") String ids) {
if (ids.contains("-")) {
String[] split = ids.split("-");//分割id
//转换成list
ArrayList<Integer> ints = new ArrayList<>();
for (String s : split) {
ints.add(Integer.parseInt(s));
}
empService.deleteBatchEmp(ints);//批量删除
return Msg.success();
} else {
empService.deleteEmp(Integer.parseInt(ids));
return Msg.success();
}
}
EmpService:
/**
* 根据id删除员工
* @param id
*/
public void deleteEmp(Integer id) {
empMapper.deleteByPrimaryKey(id);
}
/**
* 批量删除
* @param ids
*/
public void deleteBatchEmp(List<Integer> ids) {
EmpExample empExample = new EmpExample();
//delete from table_name where id = {1,2,3}
empExample.createCriteria().andEmpIdIn(ids);
empMapper.deleteByExample(empExample);
}
四、遇到的问题
记录错误无法自动装配。未找到 ‘xxxService‘ 类型的 Bean
记录错误 Method com/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z is abstract
put请求无法自动注入的问题:
/**
* 如果直接用ajax发送put请求,会遇到一个问题:请求体中有数据,但是Emp对象封装不上
* 原因:这是tomcat的问题
* 1、请求体中的数据,会封装成一个map
* 2、reqeust.getParameter("empName")就会从这个map中取值
* 3、SpringMVC封装POJO对象的时候,会把POJO中的每个属性的值都用request.getParameter("属性名取出")
* 4、但是request.getParameter()拿不到数据,因为tomcat看到是put请求,就不会去封装数据为map,只有post请求才封装请求体。
* 5、解决方法:需要在web.xml中添加一个过滤器:HttpPutFormContentFilter,它的作用是将请求体中的数据解析包装成一个map,
* request被重新包装,request.getParameter()被重写,就会从自己封装的map中获取数据
*
* @param emp
* @return
*/
@PutMapping("/emp/{empId}")//这个{}中的名字需要跟Emp类中的属性名一致,否则注入不进去
@ResponseBody
public Msg updateEmp(Emp emp){
empService.updateEmp(emp);
return Msg.success();
}