文章目录
github地址功能点技术点环境搭建整体结构Maven配置静态资源导出问题
ssm整合配置文件web.xml配置applicationContext.xml配置springmvc.xml配置mybatis.xml配置db.properties配置
逆向工程运行添加联表查询bean实体类dao层接口mapper文件配置添加新的resultmap添加新的字段列表添加方法的实现
测试使用spring单元测试导入springTest模块测试部门与员工插入测试批量插入
规定URI标准查询后端分页查询相关配置查询所有员工调用分页查询使用spring的测试模块来测试请求
前端页面展示list页面页面效果ajax实现引入json依赖添加处理返回信息的工具类返回json字符串返回的字符串使用ajax构建页面效果
新增逻辑后端保存员工获得部门信息检测用户名是否存在
前端添加表单校验添加校验用户名使用JSR303
修改逻辑后端查询单个员工信息更新员工信息
前端测试问题:原因:解决方法:
删除单个删除逻辑后端前端测试
批量删除逻辑后端前端测试
项目源码Controller层Service层Msg工具类index页面
sql
github地址:https://github.com/zuijiaxizi/ssm-crud
github地址
功能点
分页
数据校验
jQuery前端校验+JSR303后端校验
ajax
Rest风格的URI:使用HTTP协议请求方式的动词,来表示对资源的操作GET(查询),POST(新增),PUT(修改),DELETE(删除)
技术点
基础框架-ssm(Spring+SpringMVC+MaBatis)数据库-Mysql前端框架-bootstrap快速搭建简洁美观的界面项目的依赖管理-Maven分页-pagehelper逆向工程-MyBatis Generator
环境搭建
整体结构
Maven配置
<dependencies>
<dependency>
<groupId>junit
</groupId>
<artifactId>junit
</artifactId>
<version>4.13
</version>
<scope>test
</scope>
</dependency>
<dependency>
<groupId>mysql
</groupId>
<artifactId>mysql-connector-java
</artifactId>
<version>5.1.47
</version>
</dependency>
<dependency>
<groupId>com.mchange
</groupId>
<artifactId>c3p0
</artifactId>
<version>0.9.5.5
</version>
</dependency>
<dependency>
<groupId>javax.servlet
</groupId>
<artifactId>javax.servlet-api
</artifactId>
<version>3.1.0
</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp
</groupId>
<artifactId>javax.servlet.jsp-api
</artifactId>
<version>2.3.1
</version>
</dependency>
<dependency>
<groupId>javax.servlet
</groupId>
<artifactId>jstl
</artifactId>
<version>1.2
</version>
</dependency>
<dependency>
<groupId>org.mybatis
</groupId>
<artifactId>mybatis
</artifactId>
<version>3.5.5
</version>
</dependency>
<dependency>
<groupId>org.mybatis
</groupId>
<artifactId>mybatis-spring
</artifactId>
<version>2.0.5
</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator
</groupId>
<artifactId>mybatis-generator-core
</artifactId>
<version>1.4.0
</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper
</groupId>
<artifactId>pagehelper
</artifactId>
<version>5.2.0
</version>
</dependency>
<dependency>
<groupId>org.springframework
</groupId>
<artifactId>spring-webmvc
</artifactId>
<version>5.2.9.RELEASE
</version>
</dependency>
<dependency>
<groupId>org.springframework
</groupId>
<artifactId>spring-jdbc
</artifactId>
<version>5.2.9.RELEASE
</version>
</dependency>
<dependency>
<groupId>org.springframework
</groupId>
<artifactId>spring-aspects
</artifactId>
<version>5.2.9.RELEASE
</version>
</dependency>
<dependency>
<groupId>org.springframework
</groupId>
<artifactId>spring-test
</artifactId>
<version>5.2.9.RELEASE
</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core
</groupId>
<artifactId>jackson-databind
</artifactId>
<version>2.10.0
</version>
</dependency>
<dependency>
<groupId>org.hibernate
</groupId>
<artifactId>hibernate-validator
</artifactId>
<version>6.1.0.Final
</version>
</dependency>
</dependencies>
静态资源导出问题
<build>
<resources>
<resource>
<directory>src/main/java
</directory>
<includes>
<include>**/*.properties
</include>
<include>**/*.xml
</include>
</includes>
<filtering>false
</filtering>
</resource>
<resource>
<directory>src/main/resources
</directory>
<includes>
<include>**/*.properties
</include>
<include>**/*.xml
</include>
</includes>
<filtering>false
</filtering>
</resource>
</resources>
</build>
ssm整合配置文件
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">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation
</param-name>
<param-value>classpath:applicationContext.xml
</param-value>
</context-param>
<servlet>
<servlet-name>DispatcherServlet
</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation
</param-name>
<param-value>classpath:springmvc.xml
</param-value>
</init-param>
<load-on-startup>1
</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet
</servlet-name>
<url-pattern>/
</url-pattern>
</servlet-mapping>
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter
</filter-name>
<url-pattern>/*
</url-pattern>
</filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilter
</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter
</filter-name>
<url-pattern>/*
</url-pattern>
</filter-mapping>
<filter>
<filter-name>FormContentFilter
</filter-name>
<filter-class>org.springframework.web.filter.FormContentFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>FormContentFilter
</filter-name>
<url-pattern>/*
</url-pattern>
</filter-mapping>
</web-app>
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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.lzx">
<context:exclude-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 name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.pwd}"/>
<property name="maxPoolSize" value="15"/>
<property name="minPoolSize" value="2"/>
<property name="autoCommitOnClose" value="false"/>
<property name="checkoutTimeout" value="10000"/>
<property name="acquireRetryAttempts" value="2"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis.xml"/>
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.lzx.dao"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
<constructor-arg name="executorType" value="BATCH"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<aop:config>
<aop:pointcut id="txPoint" expression="execution(* com.lzx.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.lzx.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
mybatis.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.lzx.bean"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="reasonable" value="true"/>
</plugin>
</plugins>
</configuration>
db.properties配置
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ssmbuild?useSSL=false
jdbc.user=root
jdbc.pwd=liuzhenxiao
逆向工程
mbg.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>
<properties resource="db.properties"/>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.user}"
password="${jdbc.pwd}"/>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="com.lzx.bean" targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="mapper" targetProject="./src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.lzx.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<table tableName="tbl_emp" domainObjectName="Employee"/>
<table tableName="tbl_dept" domainObjectName="Department"/>
</context>
</generatorConfiguration>
运行
@Test
public void testGenerator() throws Exception
{
List
<String> warnings
=new ArrayList<String>();
boolean overWriter
=true;
File configFile
=new File("src/main/resources/mbg.xml");
ConfigurationParser cp
=new ConfigurationParser(warnings
);
Configuration config
=cp
.parseConfiguration(configFile
);
DefaultShellCallback callback
=new DefaultShellCallback(overWriter
);
MyBatisGenerator myBatisGenerator
=new MyBatisGenerator(config
,callback
,warnings
);
myBatisGenerator
.generate(null
);
}
添加联表查询
逆向工程生成的文件没有联表查询,如本案例中职员表中只有部门id字段,但在实际工作中,需要查询到的是部门名称
逆向工程自动生成的职员相关属性跟字段如下
因此,我们需要手动添加联表查询
bean实体类
在职员的实体类中添加部门实体类属性
dao层接口
添加含部门名称的两个新方法接口
mapper文件配置
添加新的resultmap
注意这里不要写成jdbcType
添加新的字段列表
为防止字段冲突,指定表名称(使用别名)
添加方法的实现
使用上面自定义的resultMap,refid(字段),使用联表查询语句,使用别名(上面字段使用了别名,这里不定义别名的话会报错)
测试
使用spring单元测试
导入springTest模块
@ContextConfiguration,指定spring配置文件的位置,如果有多个,就用逗号分隔
@RunWith,指定用什么环境进行单元测试
测试部门与员工插入
测试批量插入
注意这里要在spring和mybatis的整合文件中配置批量执行的 sqlSession
规定URI标准
/emp/{id} GET请求 查询员工
/emp POST请求 保存员工
/emp/{id} PUT请求 修改员工
/emp/{id} DELETE 删除员工
查询
后端
分页查询相关配置
在maven中引入分页查询的依赖
在MyBatis的配置文件中配置分页插件
查询所有员工
service层
controller层
调用分页查询
使用spring的测试模块来测试请求
这里spring和springMVC的配置都要引入
首页可以直接转发到需要的页面
前端页面展示
list页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Title</title>
<%
pageContext.setAttribute("APP_PATH",request.getContextPath());
%>
<!--web路径:
不以/开始的相对路径,找资源时会以当前资源的路径为基准,很容易出问题
以/开始的相对路径,找资源是以服务器的路径为标准(http://localhost:3306)需要加上项目名
如:http://localhost:3306/crud
-->
<%-- <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css"><!--引入bootstrap的css样式库-->--%>
<%-- <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script><!--引入jQuery-->--%>
<%-- <!--bootstrap是基于jQuery库的,所以应该先导入jQuery-->--%>
<%-- <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script><!--引入bootstrap-->--%>
<!--引入jQuery-->
<!-- Bootstrap -->
<link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
<script type="text/javascript" src="${APP_PATH}/static/jQuery/jquery-1.12.4.min.js"></script>
<script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
<%--搭建显示页面--%>
<div class="container-fluid">
<%--标题--%>
<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 type="button" class="btn btn-primary">新增</button>
<button type="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="emps">
<tr>
<th>${emps.empId}</th>
<th>${emps.empName}</th>
<th>${emps.gender}</th>
<th>${emps.email}</th>
<th>${emps.department.deptName}</th>
<th>
<button class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
编辑
</button>
</th>
<th>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
删除
</button>
</th>
</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">
<c:if test="${pageInfo.hasPreviousPage}">
<li><a href="${APP_PATH}/emps?pn=1">首页</a> </li>
<li>
<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum-1}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<c:forEach items="${pageInfo.navigatepageNums}" var="page_num">
<c:if test="${page_num == pageInfo.pageNum}">
<li class="active"><a href="#">${page_num}</a></li>
</c:if>
<c:if test="${page_num != pageInfo.pageNum}">
<li><a href="${APP_PATH}/emps?pn=${page_num}">${page_num}</a></li>
</c:if>
</c:forEach>
<c:if test="${pageInfo.hasNextPage}">
<li>
<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum+1}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">末页</a> </li>
</c:if>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
页面效果
ajax实现
index.jsp页面直接发送ajax请求进行员工分页数据的查询服务器将查出的数据,以json字符串的形式返回给浏览器浏览器接收到json字符串,可以使用js对json字符串进行解析,使用js通过dom增删改变页面返回json,实现客户端的无关性
引入json依赖
添加处理返回信息的工具类
返回json字符串
返回的字符串
使用ajax构建页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Title</title>
<%
pageContext.setAttribute("APP_PATH",request.getContextPath());
%>
<link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
<script type="text/javascript" src="${APP_PATH}/static/jQuery/jquery-1.12.4.min.js"></script>
<script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
<%--搭建显示页面--%>
<div class="container-fluid">
<%--标题--%>
<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 type="button" class="btn btn-success" id="emp_add_modal_btn">新增</button>
<button type="button" class="btn btn-danger" id="emp_del_btn">删除</button>
</div>
</div>
<%--显示表格数据--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover" id="emps_table">
<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(1);
});
function to_page(pn){
$.ajax({
url:"${APP_PATH}/emps",
data:"pn="+pn,
type:"GET",
success:function (result) {
//1,解析并显示员工数据
build_emps_table(result);
//2,解析并显示分页信息
build_page_info(result);
//3,解析并显示分页条数据
build_page_nav(result);
}
});
}
function build_emps_table(result){
//清空table表格
$("#emps_table tbody").empty();
var emps = result.extend.pageInfo.list;
$.each(emps,function (index,item){
var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var genderTd = $("<td></td>").append(item.gender=='M'?"男":"女");
var emailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");
var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
$("<tr></tr>").append(checkBoxTd).append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd)
.append(btnTd).appendTo("#emps_table tbody");
});
}
//解析显示分页信息
function build_page_info(result){
//清空分页信息
$("#page_info_area").empty();
$("#page_info_area").append("当前第"+result.extend.pageInfo.pageNum+"页,共有"+
result.extend.pageInfo.pages+"页,共有"+result.extend.pageInfo.total+"条记录");
}
//解析显示分页条
function build_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{
//为元素添加翻页事件
prePageLi.click(function (){
to_page(result.extend.pageInfo.pageNum-1);
});
firstPageLi.click(function (){
to_page(1);
});
}
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
if(result.extend.pageInfo.hasNextPage ===false){
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
}else{
nextPageLi.click(function (){
to_page(result.extend.pageInfo.pageNum+1);
});
lastPageLi.click(function (){
to_page(result.extend.pageInfo.pages);
});
}
ul.append(firstPageLi).append(prePageLi);
//遍历给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");
}
</script>
</body>
</html>
效果
记得清空表格数据和页码信息(使用empty()方法),因为ajax不会刷新页面,不清空会导致下图所示问题
新增
逻辑
在index.jsp页面点击新增,弹出新增对话框
去数据库查询部门列表,显示在对话框中
用户输入数据,进行校验
jQuery前端校验,ajax用户名重复校验,重要数据后端校验(JSR303),设置唯一约束,防止用户提交非法数据
完成保存
后端
保存员工
controller层
service层
获得部门信息
service层
检测用户名是否存在
service层
controller层
前端
员工新增模态框
绑定新增按钮,点击后跳出员工新增的模态框
模态框中部门处要获得部门信息
绑定保存按钮,填写好数据后发送ajax请求
测试
添加表单校验
检测输入的名称和邮箱是否符合规范
用户名规范可以在前台检测,但是用户名是否已经存在只能在后端检测,因此直接在后端检测用户名,前端检测邮箱格式
添加校验用户名
测试
注意:前端检测是不安全的!!!
改成sucess
保存成功
使用JSR303
导入相关依赖
在实体类使用@Pattern注解,限制写入的字段
在后端调用员工保存方法时做判断
@Valid用来检测字段是否符合@Pattern规定的标准
index页面
在保存时做判断,如果有错误,拿到后端返回的错误信息并返回前端页面显示
模拟用户跳过前端验证
测试
弊端:数据库没有设置名称字段唯一性
改为success后,插入成功
建表后修改字段唯一
USE ssmbuild;
ALTER TABLE tbl_emp ADD UNIQUE(emp_name);
修改
逻辑
点击编辑,弹出用户修改的模态框(显示用户信息)
点击更新,完成用户修改
后端
查询单个员工信息
service层
controller层
更新员工信息
service层
controller层
前端
添加员工修改的模态框
点击编辑按钮,触发事件
注意:编辑按钮是在页面创建完成后,构建表格内容时才创建的,直接像下图这样绑定是不行的
可以使用jQuery的on()方法(在1.7之前是live()方法)
on()方法在被选元素及子元素上添加一个或多个事件处理程序
为编辑按钮添加自定义属性获取员工id
绑定修改按钮,调出模态框
获得员工信息
绑定更新按钮,发送ajax请求给后端更新员工信息
测试
可以看到是有数据信息的
问题:
请求体中有数据;但是Employee对象封装不上;
在后端更新方法中传入原生Request,查看请求体中的值
原因:
Tomcat:
1、将请求体中的数据,封装一个map。
2、request.getParameter(“empName”)就会从这个map中取值。
3、SpringMVC封装POJO对象的时候,会把POJO中每个属性的值,调用request.getParamter()取出
AJAX发送PUT请求引发的血案:
PUT请求,请求体中的数据,request.getParameter("empName")拿不到
Tomcat一看是PUT不会封装请求体中的数据为map,只有POST形式的请求才封装请求体为map
org.apache.catalina.connector.Request--parseParameters() (3111);
protected String parseBodyMethods = "POST";
if( !getConnector().isParseBodyMethod(getMethod()) ) {
success = true;
return;
}
解决方法:
1,发送POST请求并转为PUT
2,使用spring提供的解决方案,在web.xml中配置HttpPutFormContentFilter
spring5.1之后使用FormContentFilter代替该方法,FormContentFilter也支持PATCH和DELETE请求
配置之后再次测试
删除
单个删除
逻辑
点击删除,弹出是否确认删除的弹窗
点击确认,完成删除用户;点击取消,取消删除
后端
根据id删除用户
service层
controller层
前端
为删除按钮添加自定义属性,获取用户id
测试
批量删除
逻辑
添加多选框,完成全选全不选功能
选定后点击删除,弹出提示框,提示是否删除【用户1,用户2】
点击确认,完成批量删除用户
后端
service层
增加批量删除方法
cortroller层
更改之前的删除方法
前端
添加多选框
记得更改之前单个删除绑定的员工名称元素
添加全选全不选
当手动选择本页全部数据时,全选框应自动被选定
测试
项目源码
Controller层
@Controller
public class DepartmentController {
@Autowired
DepartmentService departmentService
;
@RequestMapping("/depts")
@ResponseBody
public Msg
getDepts(){
List
<Department> list
= departmentService
.getDepts();
return Msg
.success().add("depts",list
);
}
}
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService
;
@RequestMapping(value
= "/emp/{ids}",method
= RequestMethod
.DELETE
)
@ResponseBody
public Msg
deleteEmp(@PathVariable("ids") String ids
){
if(ids
.contains("-")){
List
<Integer> del_ids
= new ArrayList<>();
String
[] idList
= ids
.split("-");
for(String id
:idList
){
del_ids
.add(Integer
.valueOf(id
));
}
employeeService
.delBatch(del_ids
);
}else{
int id
= Integer
.parseInt(ids
);
employeeService
.delEmp(id
);
}
return Msg
.success();
}
@RequestMapping(value
= "/emp/{empId}",method
= RequestMethod
.PUT
)
@ResponseBody
public Msg
updateEmp(Employee employee
, HttpServletRequest request
){
System
.out
.println(request
.getParameter("gender"));
System
.out
.println("将要更新的员工数据" + employee
);
employeeService
.updateEmp(employee
);
System
.out
.println("调用成功");
return Msg
.success();
}
@RequestMapping(value
= "/emp/{id}",method
= RequestMethod
.GET
)
@ResponseBody
public Msg
getEmp(@PathVariable("id") Integer id
){
Employee employee
= employeeService
.getEmp(id
);
return Msg
.success().add("emp",employee
);
}
@RequestMapping("/emps")
@ResponseBody
public Msg
getEmpsWithJson(@RequestParam(value
= "pn", defaultValue
= "1") Integer pn
) {
PageHelper
.startPage(pn
, 5);
List
<Employee> emps
= employeeService
.getAll();
PageInfo page
= new PageInfo(emps
, 5);
return Msg
.success().add("pageInfo", page
);
}
@RequestMapping(value
= "/emp", method
= RequestMethod
.POST
)
@ResponseBody
public Msg
saveEmp(@Valid Employee employee
, BindingResult result
) {
if (result
.hasErrors()) {
Map
<String, Object> map
= new HashMap<>();
List
<FieldError> fieldErrors
= result
.getFieldErrors();
for (FieldError fieldError
: fieldErrors
) {
map
.put(fieldError
.getField(), fieldError
.getDefaultMessage());
}
return Msg
.fail().add("errors", map
);
} else {
employeeService
.saveEmp(employee
);
return Msg
.success();
}
}
@RequestMapping("/checkUser")
@ResponseBody
public Msg
checkUser(@RequestParam("empName") String empName
) {
String regx
= "[\\u4e00-\\u9fa5_a-zA-Z0-9_]{4,12}";
if (!empName
.matches(regx
)) {
return Msg
.fail().add("user_msg", "用户名不合法,可以是4-12位的中文,英文,数字和_的组合");
}
boolean flag
= employeeService
.checkUser(empName
);
if (flag
) {
return Msg
.success();
} else {
return Msg
.fail().add("user_msg", "用户名已存在");
}
}
public String
getEmps(@RequestParam(value
= "pn", defaultValue
= "1") Integer pn
, Model model
) {
PageHelper
.startPage(pn
, 5);
List
<Employee> emps
= employeeService
.getAll();
PageInfo page
= new PageInfo(emps
, 5);
model
.addAttribute("pageInfo", page
);
return "list";
}
}
Service层
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper
;
public List
<Department> getDepts() {
List
<Department> list
= departmentMapper
.selectByExample(null
);
return list
;
}
}
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper
;
public List
<Employee> getAll() {
return employeeMapper
.selectByExampleWithDept(null
);
}
public void saveEmp(Employee employee
) {
employeeMapper
.insertSelective(employee
);
}
public boolean checkUser(String empName
) {
EmployeeExample example
= new EmployeeExample();
EmployeeExample
.Criteria criteria
= example
.createCriteria();
criteria
.andEmpNameEqualTo(empName
);
long count
= employeeMapper
.countByExample(example
);
return count
== 0;
}
public Employee
getEmp(Integer id
) {
return employeeMapper
.selectByPrimaryKey(id
);
}
public void updateEmp(Employee employee
) {
employeeMapper
.updateByPrimaryKeySelective(employee
);
}
public void delEmp(Integer id
) {
employeeMapper
.deleteByPrimaryKey(id
);
}
public void delBatch(List
<Integer> idList
) {
EmployeeExample example
= new EmployeeExample();
EmployeeExample
.Criteria criteria
= example
.createCriteria();
criteria
.andEmpIdIn(idList
);
employeeMapper
.deleteByExample(example
);
}
}
Msg工具类
public class Msg {
private int code
;
private String msg
;
private Map
<String,Object> extend
= new HashMap<>();
public Msg
add(String key
,Object value
){
this.getExtend().put(key
,value
);
return this;
}
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 Map
<String, Object> getExtend() {
return extend
;
}
public void setExtend(Map
<String, Object> extend
) {
this.extend
= extend
;
}
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
;
}
}
index页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Title</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.css" rel="stylesheet">
<script type="text/javascript" src="${APP_PATH}/static/jQuery/jquery-1.12.4.min.js"></script>
<script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
<%--员工添加的模态框--%>
<div class="modal fade" tabindex="-1" role="dialog" id="empAddModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">员工添加</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">lastname</label>
<div class="col-sm-10">
<input type="text" name="empName" class="form-control" id="empName_add_input"
placeholder="empName">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control" id="email_add_input"
placeholder="email@gmail.com">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">gender</label>
<div>
<label class="radio-inline">
<input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2_add_input" value="F"> 女
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<!-- 部门提交部门id即可 -->
<select class="form-control" name="dId"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
</div>
</div>
</div>
</div>
<%--员工修改的模态框--%>
<div class="modal fade" tabindex="-1" role="dialog" id="empUpdateModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">员工修改</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">lastname</label>
<div class="col-sm-10">
<p class="form-control-static" id="empName_update_static"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control" id="email_update_input"
placeholder="email@gmail.com">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">gender</label>
<div>
<label class="radio-inline">
<input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked"> 男
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2_update_input" value="F"> 女
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<!-- 部门提交部门id即可 -->
<select class="form-control" name="dId"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
</div>
</div>
</div>
</div>
<%--搭建显示页面--%>
<div class="container-fluid">
<%--标题--%>
<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 type="button" class="btn btn-success" id="emp_add_modal_btn">新增</button>
<button type="button" class="btn btn-danger" id="emp_del_batch_btn">批量删除</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>#</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,currentPage;
//页面加载完成后,直接去发送ajax请求,要到分页数据
$(function () {
//默认去首页
to_page(1);
});
//页面跳转
function to_page(pn) {
$.ajax({
url: "${APP_PATH}/emps",
data: "pn=" + pn,
type: "GET",
success: function (result) {
//1,解析并显示员工数据
build_emps_table(result);
//2,解析并显示分页信息
build_page_info(result);
//3,解析并显示分页条数据
build_page_nav(result);
}
});
}
//构建表格内容
function build_emps_table(result) {
//清空table表格
$("#emps_table tbody").empty();
var emps = result.extend.pageInfo.list;
$.each(emps, function (index, item) {
var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var genderTd = $("<td></td>").append(item.gender == 'M' ? "男" : "女");
var emailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
//为编辑按钮添加一个自定义属性,来表示当前员工id
editBtn.attr("edit-id",item.empId);
var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-trash")).append("删除");
//为删除按钮添加一个自定义属性,来表示当前员工id
deleteBtn.attr("del-id",item.empId);
var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
$("<tr></tr>").append(checkBoxTd).append(empIdTd).append(empNameTd).append(genderTd).append(emailTd).append(deptNameTd)
.append(btnTd).appendTo("#emps_table tbody");
});
}
//解析显示分页信息
function build_page_info(result) {
//清空分页信息
$("#page_info_area").empty();
$("#page_info_area").append("当前第" + result.extend.pageInfo.pageNum + "页,共有" +
result.extend.pageInfo.pages + "页,共有" + result.extend.pageInfo.total + "条记录");
//记录总页码数,方便保存时跳转
totalPage = result.extend.pageInfo.pages;
currentPage = result.extend.pageInfo.pageNum;
}
//解析显示分页条
function build_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 {
//为元素添加翻页事件
prePageLi.click(function () {
to_page(result.extend.pageInfo.pageNum - 1);
});
firstPageLi.click(function () {
to_page(1);
});
}
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
//没有下一页时,不显示下一页及末页
if (result.extend.pageInfo.hasNextPage === false) {
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
} else {
nextPageLi.click(function () {
to_page(result.extend.pageInfo.pageNum + 1);
});
lastPageLi.click(function () {
to_page(result.extend.pageInfo.pages);
});
}
ul.append(firstPageLi).append(prePageLi);
//遍历给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 reset_form(ele){
$(ele)[0].reset();
//清空表单内容
$(ele).find("*").removeClass("has-success has-error");
$(ele).find(".help-block").text("");
}
//点击新增按钮弹出模态框。
$("#emp_add_modal_btn").click(function () {
//清除表单数据(表单完整重置(表单的数据,表单的样式))
reset_form("#empAddModal form");
//发送ajax请求,查出部门信息,显示在下拉列表中
getDepts("#empAddModal select");
//弹出模态框
$("#empAddModal").modal({
backdrop: "static"
});
});
//获得部门信息
function getDepts(ele) {
$(ele).empty();
$.ajax({
url: "${APP_PATH}/depts",
type: "GET",
success: function (result) {
$.each(result.extend.depts, function () {
var optionEle = $("<option></option>").append(this.deptName).attr("value", this.deptId);
optionEle.appendTo(ele);
});
}
});
}
//校验表单数据
function validate_add_form(){
//校验用户名
//拿到要校验的数据,使用正则表达式
// var empName=$("#empName_add_input").val();
// //匹配中英文,数字及_
// var regname=/[\u4e00-\u9fa5_a-zA-Z0-9_]{4,12}/
// if(!regname.test(empName)){
// show_validate_msg("#empName_add_input","error","用户名不合法,可以是4-12位的中文,英文,数字和_的组合");
// 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-success has-error");
$(ele).next("span").text("");
if("success"===status){
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg);
}else if("error"===status){
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg);
}
}
//校验用户名是否可用
$("#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_user","success");
}else{
//用户名不可用时显示后台传过来的错误信息
show_validate_msg("#empName_add_input","error",result.extend.user_msg);
$("#emp_save_btn").attr("ajax_user","error");
}
}
});
});
//点击保存员工
$("#emp_save_btn").click(function () {
//先对要提交给服务器的数据进行校验
if(!validate_add_form()){
return false;
}
//保存时判断用户名是否可用(用户名是否已经存在)
if($(this).attr("ajax_user")==="error"){
return false;
}
//1,模态框中填写的表单数据提交给服务器进行保存
//2,发送ajax请求保存员工
$.ajax({
url: "${APP_PATH}/emp",
type: "POST",
data: $("#empAddModal form").serialize(),
success: function (result) {
if(result.code===100){
//员工保存成功
//保存完成后关闭模态框
$("#empAddModal").modal('hide');
//跳转到最后一页查看保存的数据
// 此处设置了分页合理化,所以可以设置为跳转到超过当前总页码数的位置
to_page(totalPage+1);
}else{
//显示失败信息
//有哪个字段的错误信息就显示哪个字段的
if(undefined !== result.extend.errors.email){
//显示邮箱错误信息
show_validate_msg("#email_add_input","error",result.extend.errors.email);
alert("邮箱错误");
}
if(undefined !== result.extend.errors.empName){
//显示员工名字的错误信息
show_validate_msg("#empName_add_input","error",result.extend.errors.empName);
alert("用户名错误");
}
}
}
});
});
//绑定修改按钮,调出模态框
$(document).on("click",".edit_btn",function (){
//查出部门信息,并显示部门列表
getDepts("#empUpdateModal select");
//查出员工信息,显示员工信息
getEmp($(this).attr("edit-id"));
//把员工的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 empDate = result.extend.emp;
$("#empName_update_static").text(empDate.empName);
$("#email_update_input").val(empDate.email);
$("#empUpdateModal input[name=gender]").val([empDate.gender]);
$("#empUpdateModal select").val([empDate.dId]);
}
});
}
//绑定更新按钮,保存修改后的员工信息
$("#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(currentPage);
}
});
});
//单个删除
$(document).on("click",".delete_btn",function (){
//父元素下的第二个td的值,即是员工名称
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 (){
//注意,这里不要使用attr,attr获取checked的属性是underfined
//prop修改和读取dom原生属性的值,attr对应自定义属性
$(".check_item").prop("checked",$(this).prop("checked"));
});
//当手动将本页全部选择时,标题栏全选框应自动选定
$(document).on("click",".check_item",function (){
var flag = $(".check_item:checked").length===$(".check_item").length;
$("#check_all").prop("checked",flag);
});
//点击批量删除,就批量删除
$("#emp_del_batch_btn").click(function (){
var empName="";
var del_id_str="";
$.each($(".check_item:checked"),function (){
//拼装员工名称
empName += $(this).parents("tr").find("td:eq(2)").text()+",";
//拼装员工id字符串
del_id_str += $(this).parents("tr").find("td:eq(1)").text()+"-";
});
//去除员工名称多余的,
empName = empName.substring(0,empName.length-1);
//去除员工id多余的-
del_id_str = del_id_str.substring(0,del_id_str.length-1);
if(confirm("确认删除【" + empName + "】吗?")){
//发送ajax请求批量删除员工
$.ajax({
url:"${APP_PATH}/emp/"+del_id_str,
type:"DELETE",
success:function (result){
alert(result.msg);
to_page(currentPage);
}
});
}
});
</script>
</body>
</html>
sql
DROP TABLE IF EXISTS `tbl_dept
`;
CREATE TABLE `tbl_dept
` (
`dept_id
` int(11) NOT NULL AUTO_INCREMENT,
`dept_name
` varchar(20) NOT NULL,
PRIMARY KEY (`dept_id
`),
UNIQUE KEY `dept_name
` (`dept_name
`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
DROP TABLE IF EXISTS `tbl_emp
`;
CREATE TABLE `tbl_emp
` (
`emp_id
` int(11) NOT NULL AUTO_INCREMENT,
`emp_name
` varchar(255) NOT NULL,
`gender
` char(1) DEFAULT NULL,
`email
` varchar(255) DEFAULT NULL,
`d_id
` int(11) NOT NULL,
PRIMARY KEY (`emp_id
`),
UNIQUE KEY `emp_name
` (`emp_name
`),
KEY `fk_emp_dept
` (`d_id
`),
CONSTRAINT `fk_emp_dept
` FOREIGN KEY (`d_id
`) REFERENCES `tbl_dept
` (`dept_id
`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
DROP TABLE IF EXISTS `tbl_mgr
`;
CREATE TABLE `tbl_mgr
` (
`mgr_id
` int(11) NOT NULL AUTO_INCREMENT,
`mgr_name
` varchar(20) NOT NULL,
`mgr_pwd
` varchar(25) NOT NULL,
`d_id
` int(11) NOT NULL,
PRIMARY KEY (`mgr_id
`),
KEY `fk_mgr_dept
` (`d_id
`),
CONSTRAINT `fk_mgr_dept
` FOREIGN KEY (`d_id
`) REFERENCES `tbl_dept
` (`dept_id
`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;