一、搭建maven工程
1.1、补齐目录
先项目上右键,选择属性
先去掉,然后再勾上下图选项
1.2、配置生成的web.xml的位置
二、 通过pom.xml引进相关jar依赖
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>ssm-crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- spring-mvc、spring -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.13</version>
</dependency>
<!-- spring-jdbc事务处理 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.13</version>
</dependency>
<!-- spring面向切面编程 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.13</version>
</dependency>
<!-- mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mybatis和spring整合 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 数据库连接池 -->
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mysql驱动 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- jstl -->
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- servlet-api -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- junit -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
三、 引进bootstrap和jQuery
https://v3.bootcss.com/
3.1、使用bootstrap
引入基本样式css和JavaScript和jQuery
使用
四、配置相关xml文件
4.1、配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://JAVA.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- ====================Spring 的配置,启动spring容器========================= -->
<!-- 配置使web项目启动就去找applicationContext.xml配置文件,进行解析 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 监听器,tomcat服务启动的时候,自动加载spring的核心容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- ====================Spring MVC前端控制器的配置,拦截所有请求====================== -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param><!--init-param 指定spring-mvc的配置文件的路径 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling
将所有请求映射到DispatcherServlet进行处理 -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- ====================字符编码过滤器的配置====================== -->
<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>
<!-- ====================配置restful风格过滤器====================== -->
<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>
附:
servlet-name标签出错的解决方案
4.2、配置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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- spring主要配置和业务逻辑有关的 -->
<!-- ================================组件扫描================================ -->
<context:component-scan base-package="com.atguigu" >
<!-- 扫描除了@Controller注解的组件 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- ================================配置数据源================================ -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 读取数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- ========================spring整合Mybatis================================ -->
<!-- 1、Mybatis的sqlsession的创建 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
<!-- Mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- Mybatis的SQL映射文件,这样就不用同名同位置了 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!--配置扫描器,将mybatis接口的实现加入到ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描所有dao接口的实现,加入到ioc容器中-->
<property name="basePackage" value="com.atguigu.crud.dao"></property>
</bean>
<!-- ================================配置事务管理器================================ -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务控制 -->
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut expression="execution(* com.atguigu.crud.service..*(..))" id="txPoint"/>
<!-- 配置事务增强 -->
<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>
4.3、配置springmvc的配置文件springmvc.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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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-4.3.xsd">
<!-- SpringMVC的配置文件,包含网站跳转逻辑的控制,配置 -->
<!-- ===================组件扫描=================== -->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!-- 结合use-default-filters="false",只扫描Controller,标有@Controller注解的组件 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- ==========使用视图解析器,代替controller中的ModelAndView ,方便页面放回===========-->
<bean id="internalResourceViewResolver" 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></mvc:annotation-driven>
</beans>
4.4、配置数据库连接文件db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=Hongkong
jdbc.username=root
jdbc.password=75688
4.5、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>
<!-- 将数据库中的字段转换成小驼峰命名方式,例如member_id,转换成memberId -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 取别名 -->
<typeAliases>
<package name="com.atguigu.crud.bean"></package>
</typeAliases>
</configuration>
五、创建数据库表
六、mybatis逆向工程
6.1、引入mabatis逆向工程所需依赖
6.2、mbg.xml
参考http://mybatis.org/generator/
<?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>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 不生成注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- 配置数据库连接 -->
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=Hongkong"
userId="root"
password="75688">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 指定javaBean生成的位置 -->
<javaModelGenerator
targetProject=".\src\main\java"
targetPackage="com.atguigu.crud.bean" >
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--指定sql映射文件生成的位置-->
<sqlMapGenerator
targetProject=".\src\main\resources"
targetPackage="mapper">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--指定dao接口生成的位置,mapper接口-->
<javaClientGenerator type="XMLMAPPER"
targetProject=".\src\main\java"
targetPackage="com.atguigu.crud.dao">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- table指定每个表的生成策略 -->
<table tableName="tbl_emp" domainObjectName="Employee"></table>
<table tableName="tbl_dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
6.3、使用逆向工程生成代码
参考官方文档
6.3.1、MBGTest.java
package com.atguigu.crud.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
public class MBGTest {
public static void main(String[] args) throws Exception, XMLParserException {
System.out.println("============开始执行逆向工程============");
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("============执行逆向工程结束============");
}
}
运行上面代码将自动生成逆向工程
七、自定义SQL查询
7.1、新增查询1
查询结果封装
7.2、新增查询2
八、使用spring单元测试
8.1、简单插入
@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测试框架
@ContextConfiguration(locations= {"classpath:applicationContext.xml"})
public class MapperTest {
@Autowired
DepartmentMapper departmentMapper ;
@Autowired
EmployeeMapper employeeMapper;
@Test
public void testCRUD() {
//1、部门插入测试
//departmentMapper.insertSelective(new Department(null,"销售部"));
//2、员工插入测试
employeeMapper.insertSelective(new Employee(null,"苗丹","M","0103123@qq.com",1));
}
}
8.2、批量插入
@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测试框架
@ContextConfiguration(locations= {"classpath:applicationContext.xml"})
public class MapperTest {
@Autowired
EmployeeMapper employeeMapper;
@Autowired
SqlSession sqlSession;
@Test
public void testCRUD() {
//批量插入员工数据
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
for(int i=0;i<968;i++){
String uid= UUID.randomUUID().toString().toString().substring(0,5)+i;
mapper.insertSelective(new Employee(null, uid, "M", uid+"@qq.com", 1));
}
System.out.println("============批量插入员工数据完成============");
}
}
九、PageHelper分页插件的使用
9.1、引进PageHelper maven依赖
9.2、在mybatis-config.xml注册PageHelper分页插件
十、查询功能
controller处理请求
Service执行业务逻辑
分页查询的单元测试
//使用Spring测试模块提供的测试请求功能,测试curd请求的正确性
@RunWith(SpringJUnit4ClassRunner.class)//使用Springtest测i试框架
@ContextConfiguration(locations = {"classpath:applicationContext.xml","classpath:springmvc.xml"})
@WebAppConfiguration
public class MvcTest {
//传入Springmvc的ioc
@Autowired
WebApplicationContext context;
//虚拟mvc请求,获取到处理结果。
MockMvc mockMvc ;
@Before
public void initMokcMvc(){
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testPage() throws Exception {
//模拟发送请求,获取第5页数据,得到返回值
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn","5"))
.andReturn();
//请求成功以后 请求域中有pageINfo;我们可以取出来pageInfo进行验证
MockHttpServletRequest request = mvcResult.getRequest();
PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
//进行输出
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("总页码:"+pageInfo.getPages());
System.out.println("总记录数:"+pageInfo.getTotal());
int[] nums = pageInfo.getNavigatepageNums();
System.out.println("在页面需要连续显示的页码:");
for (int i:nums ) {
System. out.print(" "+i);
}
System. out.println("");
//也获取员工数据
List<Employee> list = pageInfo.getList();
for (Employee employee : list) {
System.out.println("ID: "+employee.getEmpId( )+"== >Name:"+employee.getEmpName());
}
}
}
10.1、前端页面设计
<%@ 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>
<html>
<head>
<meta charset="UTF-8">
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以“/”开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
以“/”开始的开始的相对路径,找资源,以服务器为标准(http//localhost/端口号)需要加项目名;
就是http//localhost/端口号/ssm-crud/...
${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
-->
<!-- Bootstrap -->
<link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<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">
<!-- 表头 -->
<tr>
<th>#</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>operator</th>
</tr>
<!-- 表体 -->
<c:forEach items="${pageInfo.list}" var="emp">
<tr>
<td >${emp.empId}</td>
<td >${emp.empName}</td >
<td >${emp.gender=="M"?"male":"female"}</td >
<td >${emp.email}</td >
<td >${emp.department.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-trash" aria-hidden="true"></span>
删除
</button>
</td >
</tr>
</c:forEach>
</table>
</div>
</div>
<!-- 分页信息 -->
<div class="row">
<!-- 分页文字信息 -->
<div class="col-md-6">
<span>当前${pageInfo.pageNum}页,总${pageInfo.pages}页,共${pageInfo.total}条记录</span>
</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="pageNumber">
<c:if test="${pageNumber == pageInfo.pageNum}">
<li class="active">
<a href="#">${pageNumber}</a>
</li>
</c:if>
<c:if test="${pageNumber != pageInfo.pageNum}">
<li>
<a href="${APP_PATH}/emps?pn=${pageNumber}">${pageNumber}</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>
10.2、返回json数据
准备通用的返回类
package com.atguigu.crud.bean;
import java.util.HashMap;
import java.util.Map;
/**
* 通用的返回类
*/
public class Msg {
//状态码 100-success 200-fail
private int code;
//提示信息
private String msg;
//用户返回给浏览器的数据
private Map<String, Object> extend = new HashMap<String, Object>();
/*================自定义方法开始=======================*/
public static Msg success() {
Msg msg = new Msg();
msg.setCode(100);
msg.setMsg("处理成功!");
return msg;
}
public static Msg fail() {
Msg msg = new Msg();
msg.setCode(200);
msg.setMsg("处理失败!");
return msg;
}
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;
}
}
10.3、使用ajax
10.3.1、使用ajax发起请求
10.3.2、jQuery遍历语法
10.3.3、jQuery添加样式和标签属性
10.3.4、jQuery将新增控件添加到页面语法
10.3.5、jQuery点击事件
10.3.6、jQuery清空表格数据
十一、新增功能
11.1、前端校验
11.1.1、jQuery获取表单的值
11.1.2、jQuery正则表达式使用
11.2、后端数据校验
前后端都要进行数据校验
11.2.1、后端优化校验JSR303和Hibernate Validator
使用Hibernate Validator
十二、编辑功能
jQuery按钮点击事件
十三、删除功能
十四、jsp完整代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>employees list</title>
<!-- 使用request获取项目路径,使用pageContext添加值到域对象中 -->
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<!-- web路径:
不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题
以/开始的开始的相对路径,找资源,以服务器为标准(http//localhost/端口号)需要加项目名;
就是http//localhost/端口号/crud/...
${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
-->
<!-- Bootstrap -->
<link href="${APP_PATH}/static/bootstrap-3.4.1-dist/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="${APP_PATH}/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 员工修改的模态框 -->
<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_add_input" class="col-sm-2 control-label">empName</label>
<div class="col-sm-10">
<p class="form-control-static" id="empName_update_static"></p>
</div>
</div>
<div class="form-group">
<label for="email_add_input" 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="aaa@aaa.aaa"> <span
class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">gender</label>
<div class="col-sm-10">
<label class="radio-inline"> <input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked">
男
</label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_update_input" value="W"> 女
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<select class="form-control" name="dId" id="dept_update_select">
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
</div>
</div>
</div>
</div>
<!-- 员工添加的模态框 -->
<div class="modal fade" id=empAddModal tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">员工添加</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">empName</label>
<div class="col-sm-10">
<input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
<span id="helpBlock2" 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" class="form-control" name="email" id="email_add_input" placeholder="aaa@qq.com"> <span
class="help-block"></span> <span id="helpBlock2" class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">性别</label>
<div class="col-sm-10">
<label class="radio-inline"> <input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked">
男
</label> <label class="radio-inline"> <input type="radio" name="gender" id="gender2_add_input" value="W"> 女
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">部门名称</label>
<div class="col-sm-4">
<select class="form-control" name="dId" id="dept_add_select">
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_save_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 id="emp_add_modal_btn" class="btn btn-primary">添加</button>
<button id="emp_delete_all_btn" 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><input type="checkbox" id="check_all"></th>
<th>员工Id</th>
<th>员工姓名</th>
<th>性别</th>
<th>email</th>
<th>部门名称</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 currentPage;//当前页码
/*========页面加载完成以后,直接发送ajax请求,要到分页数据=========*/
$(function() {
to_page(1);//默认显示第一页
})
/*===================查询所有信息=================*/
function to_page(pageNumber) {
$.ajax({
url: "${APP_PATH}/emps/",
data: "pn=" + pageNumber,
type: "GET",
success: function(result) {
//console.log(result);
//1、解释并显示员工数据
bulid_emps_table(result);
//2、解释并显示分页文字信息
bulid_page_info(result);
//3、解释并显示分页导航信息
bulid_page_nav(result);
}
});
}
/*=================解释并显示员工数据===============*/
function bulid_emps_table(result) {
//先清空表体数据
$("#emps-table tbody").empty();
var emps = result.extend.pageInfo.list;
$.each(emps, function(index, item) {
var checkBoxTd = $("<td></td>").append("<input type='checkbox' class='check_item'/>");
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var empGenderTd = $("<td></td>").append(item.gender == "M" ? 'male' : "female");
var empEmailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
var editBtn = $("<button></button>")//添加button,并返回button对象
.addClass("btn btn-primary btn-sm edit_btn")//给button添加样式
.append($("<span></span>").addClass("glyphicon glyphicon-pencil"))//给span添加样式
.append("编辑");//给span添加内容
//为编辑按钮添加一个自定义的属性,来表示当前员工id
editBtn.attr("edit_id", item.empId);
var delBtn = $("<button></button>")
.addClass("btn btn-danger btn-sm delete_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-trash"))
.append("删除");
//为删除按钮添加属性表示id
delBtn.attr("del_id", item.empId);
//将编辑按钮和删除按钮放在同一个单元格中
var btnTd = $("<td></td>")
.append(editBtn)
.append(" ")
.append(delBtn);
//将单元格添加到行显示
$("<tr></tr>").append(checkBoxTd)
.append(empIdTd)
.append(empNameTd)
.append(empGenderTd)
.append(empEmailTd)
.append(deptNameTd)
.append(btnTd)
.appendTo("#emps-table tbody");
})
}
/*=================解释并显示分页文字信息===============*/
function bulid_page_info(result) {
$("#page-info-area").empty()//先清空
.append("当前" + result.extend.pageInfo.pageNum + "页,总" +
result.extend.pageInfo.pages + "页,共" +
result.extend.pageInfo.total + "条记录");
//记录当前总记录数
totalRecord = result.extend.pageInfo.total;
//记录当前页吗,更新员工信息后,需返回显示当前页
currentPage = result.extend.pageInfo.pageNum;
}
/*=================解释并显示分页导航信息===============*/
function bulid_page_nav(result) {
$("#page_nav_area").empty();//先清空
var ul = $("<ul></ul>").addClass("pagination");
//构建元素
var firstPageLi = $("<li></li>")
.append($("<a></a>").append("首页").attr("href", "#"));
var prePageLi = $("<li></li>")
.append($("<a></a>").append("«"));
//如果请求结果没有前一页,则首页和前一页按钮不能点击
if (result.extend.pageInfo.hasPreviousPage == false) {
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
} else {
//为元素添加翻页事件
firstPageLi.click(function() {
to_page(1);
});
prePageLi.click(function() {
to_page(result.extend.pageInfo.pageNum - 1);
});
}
var nextPageLi = $("<li></li>")
.append($("<a></a>").append("»"));
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);
});
}
//页码1,2,3,4
ul.append(firstPageLi).append(prePageLi);
$.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 reset_form(ele) {
//清空表单内容
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
//清空校验信息
$(ele).find(".help-block").text("");
}
/*=================添加功能:点击新增按钮弹出模态框===============*/
$("#emp_add_modal_btn").click(function() {
//清除表单数据(表单重置)
reset_form("#empAddModal form");
//发送ajax请求,查出部门信息,显示在下拉列表中
getDepts("#empAddModal select");
//弹出模态框
$("#empAddModal").modal({
backdrop: "static"
});
});
/*=============查出所有部门信息,显示在下拉列表中=============*/
function getDepts(selectName) {
$.ajax({
url: "${APP_PATH}/depts",
type: "GET",
success: function(result) {
$(selectName).empty();//清空
//使用each循环显示所有部门到下拉列表中
$.each(result.extend.depts, function() {
var optionEle = $("<option></option>")
.append(this.deptName)
//添加一个自定义的属性,来表示当前部门id
.attr("value", this.deptId);
optionEle.appendTo(selectName);
});
}
});
}
/*=================校验用户名是否可用===============*/
$("#empName_add_input").change(
function() {
//发送ajax请求校验用户名是否可用
var empName = this.value;
$.ajax({
url: "${APP_PATH}/checkuser/",
data: "empName=" + empName,
type: "POST",
success: function(result) {
if (result.code == 100) {
show_validate_msg(
"#empName_add_input",
"success",
"用户名可用"
);
$("#emp_save_btn").attr("ajax-va", "success");
} else {
show_validate_msg(
"#empName_add_input",
"error",
result.extend.va_msg
);
$("#emp_save_btn").attr("ajax-va", "error");
}
}
})
});
/*=================点击保存,保存员工===============*/
$("#emp_save_btn").click(
function() {
//1、模态框中填写的数据提交到服务器进行保存
//2、先对提交给服务器的数据进行校验
if (!validate_add_form()) {
return false;
}
//1、判断之前的ajax用户名校验是否成功
if ($(this).attr("ajax-va") == "error") {
return false;
}
//保存新增数据
$.ajax({
url: "${APP_PATH}/emp/",
type: "POST",
data: $("#empAddModal form").serialize(),
success: function(result) {
if (result.code == 100) {
//员工保存成功
//1、关闭模态框
$("#empAddModal").modal('hide');
//2、来到最后一页,显示刚才保存的数据
//发送ajax请求显示最后一页数据即可
to_page(totalRecord);
} else {
// 显示失败信息
if (undefined != result.extend.errorFields.email) {
//显示邮箱的错误信息
show_validate_msg(
"#email_add_input",
"error",
result.extend.errorFields.email);
}
if (undefined != result.extend.errorFields.empName) {
//员工的错误信息
show_validate_msg(
"#empName_add_input",
"error",
result.extend.errorFields.empName);
}
}
}
});
})
/*=============先对提交给服务器的数据进行校验=============*/
function validate_add_form() {
//1、校验员工姓名信息
var empName = $("#empName_add_input").val();//员工姓名获取输入框的输入值
//a-z0-9_-六到十六位,或二到五位中文
var regName = /(^[a-z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;//校验规则
//使用test()进行校验,员工姓名不符合校验规则
if (!regName.test(empName)) {
show_validate_msg(
"#empName_add_input",
"error",
"用户名为2-5中文或4-16英文数字组合"
);
return false;
}
//2、校验邮箱信息
var empEmail = $("#email_add_input").val();
var regEmail = /^([a-zA-Z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
//邮箱不符合校验规则
if (!regEmail.test(empEmail)) {
show_validate_msg(
"#email_add_input",
"error",
"邮箱格式错误"
);
return false;
} else {
show_validate_msg(
"#email_add_input",
"success",
""
);
}
return true;
}
/*===============回显校验信息===============*/
function show_validate_msg(ele, status, msg) {
//首先清空当前元素
$(ele).parent().removeClass("has-success has-error");
$(ele).next("span").text("");
if ("success" == status) {
$(ele).parent().addClass("has-success");
} else if ("error" == status) {
$(ele).parent().addClass("has-error");
}
$(ele).next("span").text(msg);
}
/*=============编辑功能:=============*/
//1)、我们是按钮创建之前就绑定了click,所以绑不上
//2)、可以在创建按钮的时候绑定事件
//3)、绑定点击.live()
//jquery新版没有live,使用on方法进行替代
$(document).on("click", ".edit_btn", function() {
//清除表单数据(表单重置)
reset_form("#empUpdateModal form");
//1、查出部门信息,显示部门列表
getDepts("#empUpdateModal select");
//2、查出员工信息,显示员工信息
getEmp($(this).attr("edit_id"));
//3、把员工的id传递给模态框的更新按钮
$("#emp_update_btn").attr("edit_id", $(this).attr("edit_id"));
$("#empUpdateModal").modal({
backdrop: "static"
});
})
/*=============根据id获取部门信息=============*/
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=empGender]").val([empData.gender]);
$("#empUpdateModal select").val([empData.dId]);
}
})
}
/*=============点击更新,更新员工信息=============*/
$("#emp_update_btn").click(function() {
//验证邮箱是否合法
//1、校验邮箱信息
var empEmail = $("#email_update_input").val();
var regEmail = /^([a-zA-Z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(empEmail)) {
show_validate_msg(
"#email_update_input",
"error",
"邮箱格式错误"
);
return false;
} else {
show_validate_msg(
"#email_update_input",
"success",
""
);
}
//2、发送ajax请求,保存更新员工信息
$.ajax({
url: "${APP_PATH}/emp/" + $(this).attr("edit_id"),
type: "PUT",
data: $("#empUpdateModal form").serialize(),
success: function() {
$("#empUpdateModal").modal("hide");
to_page(currentPage);
}
});
});
/*=============单个删除=============*/
$(document).on("click", ".delete_btn", function() {
//1、弹出确认删除对话框
var empName = $(this).parents("tr").find("td:eq(2)").text();
var empId = $(this).attr("del_id");
if (confirm("确认删除【" + empName + "】吗?")) {
//发送ajax请求删除
$.ajax({
url: "${APP_PATH}/emp/" + empId,
type: "DELETE",
success: function(result) {
alert(result.msg);
//回到本页
to_page(currentPage);
}
});
}
});
/*=============完成全选/全不选功能=============*/
$("#check_all").click(function() {
var is_All_Check = $(this).prop("checked");
$(".check_item").prop("checked", is_All_Check);
});
/*=============check_item,复选框选择操作=============*/
$(document).on("click", ".check_item", function() {
//判断当前选择中的元素是否选满
var flag = $(".check_item:checked").length == $(".check_item").length;
$("#check_all").prop("checked", flag);
});
/*=============点击全部删除,就批量删除=============*/
$("#emp_delete_all_btn").click(function() {
var empNames = "";
var del_idstr = "";
$.each($(".check_item:checked"), function() {
//组装员工字符串
empNames += $(this).parents("tr").find("td:eq(2)").text() + ",";
//组织员工id字符串
del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";
});
//去除empnames多余的“,”
empNames = empNames.substring(0, empNames.length - 1);
//去除员工删除id多余的“-”
del_idstr = del_idstr.substring(0, del_idstr.length - 1);
if (confirm("确认删除【" + empNames + "】吗?")) {
//发送ajax请求
$.ajax({
url: "${APP_PATH}/emp/" + del_idstr,
type: "DELETE",
success: function(result) {
alert(result.msg);
//回到当前页面
to_page(currentPage);
$("#check_all").prop("checked", false);
}
})
}
});
</script>
</body>
</html>
版权声明:本文为weixin_45084986原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。