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配置
<!--导入相关依赖:junit,数据库驱动,数据库连接池,servlet,jsp,mybatis,mybatis-spring,spring等-->
<dependencies>
<!--junit-->
<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>
<!--servlet,jsp-->
<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>
<!--mybatis-->
<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>
<!--spring-->
<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>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
<!--JSR303数据校验支持-->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<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>
<!--springMVC前端控制器-->
<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>
<!--使用Rest风格的URI,将普通的post请求转化为delete或者put请求-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置FormContentFilter拦截PUT和DELETE请求-->
<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">
<!--扫描除Controller层之外的所有层-->
<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}"/>
<!--c3p0连接池的私有属性-->
<property name="maxPoolSize" value="15"/>
<property name="minPoolSize" value="2"/>
<!--关闭连接后不自动commit-->
<property name="autoCommitOnClose" value="false"/>
<!--获取连接超时时间-->
<property name="checkoutTimeout" value="10000"/>
<!--当获取连接失败重试次数-->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!--配置和MyBatis的整合-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis.xml"/>
<property name="dataSource" ref="dataSource"/>
<!--指定MyBatis的Mapper文件位置-->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!--配置扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描所有的dao接口-->
<property name="basePackage" value="com.lzx.dao"/>
</bean>
<!--配置一个可以批量执行的sqlSession-->
<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="*"/>
<!--以get开始的所有方法-->
<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"/>
<!-- <setting name="logImpl" value="STDOUT_LOGGING"/>-->
</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>
<!--是否去除自动生成的注释 true是:false 否-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库连接-->
<jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.url}" userId="${jdbc.user}"
password="${jdbc.pwd}"/>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL和NUMERIC类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--targetPackage目标包,生成实体类的位置-->
<javaModelGenerator targetPackage="com.lzx.bean" targetProject="src/main/java">
<!--enableSubPackages,是否让schema作为包的后缀-->
<property name="enableSubPackages" value="false"/>
<!--从数据库返回的值被清除前后空格-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--targetProject:mapper映射文件生成的位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="./src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!--targetPackage:mapper接口生成的位置-->
<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;
/**
* 返回所有的部门信息
* @return
*/
@RequestMapping("/depts")
@ResponseBody
public Msg getDepts(){
List<Department> list = departmentService.getDepts();
return Msg.success().add("depts",list);
}
}
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
/**
* 根据id删除用户
* 整合单个删除和批量删除
* 批量删除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("-")){
//批量删除
List<Integer> del_ids = new ArrayList<>();
String[] idList = ids.split("-");
//取到String数组中的值拼接为Integer数组
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();
}
/**
* 更新员工信息
* @return
*/
@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();
}
/**
* 查询单个员工
* @return
*/
@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);
}
/**
* 查询所有员工
*
* @param pn
* @return
*/
@RequestMapping("/emps")
@ResponseBody
public Msg getEmpsWithJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn) {
//引入PageHelper分页插件
//在查询之前调用,传入页码和每页的大小
PageHelper.startPage(pn, 5);
//startPage后面紧跟的查询就是一个分页查询
List<Employee> emps = employeeService.getAll();
//使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就可以
//封装了详细的分页信息,包括有我们查询出来的数据,可以传入连续显示的页数
PageInfo page = new PageInfo(emps, 5);
return Msg.success().add("pageInfo", page);
}
/**
* 员工保存
* @param employee
* @return
*/
@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) {
// System.out.println("错误的字段名" + fieldError.getField());
// System.out.println("错误的字段值" + fieldError.getDefaultMessage());
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return Msg.fail().add("errors", map);
} else {
employeeService.saveEmp(employee);
return Msg.success();
}
}
/**
* 检验用户名是否可用
*
* @param empName
* @return
*/
@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", "用户名已存在");
}
}
// @RequestMapping("/emps")
public String getEmps(@RequestParam(value = "pn", defaultValue = "1") Integer pn, Model model) {
//引入PageHelper分页插件
//在查询之前调用,传入页码和每页的大小
PageHelper.startPage(pn, 5);
//startPage后面紧跟的查询就是一个分页查询
List<Employee> emps = employeeService.getAll();
//使用pageInfo包装查询后的结果,只需要将pageInfo交给页面就可以
//封装了详细的分页信息,包括有我们查询出来的数据,可以传入连续显示的页数
PageInfo page = new PageInfo(emps, 5);
model.addAttribute("pageInfo", page);
return "list";
}
}
Service层
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
/**
* 获得所有部门信息
* @return
*/
public List<Department> getDepts() {
List<Department> list = departmentMapper.selectByExample(null);
return list;
}
}
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
* @return
*/
public List<Employee> getAll() {
return employeeMapper.selectByExampleWithDept(null);
}
/**
* 保存员工
* @param employee
*/
public void saveEmp(Employee employee) {
employeeMapper.insertSelective(employee);
}
/**
* 检验当前用户名是否可用
* @param empName
* @return true:代表当前用户名可用 false:代表当前用户名不可用
*/
public boolean checkUser(String empName) {
//相当于select count(*) from tbl_emp where emp_name=empName
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
criteria.andEmpNameEqualTo(empName);
long count = employeeMapper.countByExample(example);
return count == 0;
}
/**
* 查询单个员工
* @param id
* @return
*/
public Employee getEmp(Integer id) {
return employeeMapper.selectByPrimaryKey(id);
}
/**
* 更新员工信息
* @param employee
*/
public void updateEmp(Employee employee) {
employeeMapper.updateByPrimaryKeySelective(employee);
}
/**
* 根据id删除员工
* @param id
*/
public void delEmp(Integer id) {
employeeMapper.deleteByPrimaryKey(id);
}
/**
* 批量删除,传入id集合
* @param idList
*/
public void delBatch(List<Integer> idList) {
//相当于 delete from xxx where emp_id in(1,2,3...)
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
criteria.andEmpIdIn(idList);
employeeMapper.deleteByExample(example);
}
}
Msg工具类
public class Msg {
/**状态码 100成功 200失败*/
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
-- ----------------------------
-- Table structure for tbl_dept
-- ----------------------------
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;
-- ----------------------------
-- Table structure for tbl_emp
-- ----------------------------
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;
-- ----------------------------
-- Table structure for tbl_mgr
-- ----------------------------
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;