项目三 员工后台管理系统
SSM-CRUDCRUD :create retrieve update delete功能点:分页数据校验 (jquery前端校验+JSR303后端校验)ajaxRest风格URI,使用http资源请求的动词GET(查询) POST(新增) PUT(修改) DELETE(删除)技术点:基础框架ssm数据库 mysql前端框架 – bootstrap项目依赖管理 – Maven分页 – pagehe
- CRUD :create retrieve update delete
- 功能点:
- 分页
- 数据校验 (jquery前端校验+JSR303后端校验)
- ajax
- Rest风格URI,使用http资源请求的动词 GET(查询) POST(新增) PUT(修改) DELETE(删除)
- 技术点:
- 基础框架 ssm
- 数据库 mysql
- 前端框架 – bootstrap
- 项目依赖管理 – Maven
- 分页 – pagehelper
- 逆向工程 – Mybatis Generator
基础环境搭建
1. 创建一个maven工程
2. 引入项目依赖的jar包
• spring
• springmvc
• mybatis
• 数据库连接池,驱动包
• 其他(jstl,servlet-api,junit)
3. 引入bootstrap前端框架
- 在web工程下,创建static文件夹,引入bootstrap(前端样式)和js

在index.jsp中引入样式 在<head>标签中,将上述的地址写进去就可以了
<head>
<title>$Title$</title>
<%-- 引入js样式--%>
<script type="text/javascript" src="static/js/jquery-3.1.1.js"></script>
<%-- 引入bootstrap样式--%>
<link href="static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</head>
4. 编写ssm整合的关键配置文件
web.xml,spring,springmvc,mybatis,
- 在web.xml中配置
<!-- 1.启动spring-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 2.配置springMVC的前端控制器-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/l</url-pattern>
</servlet-mapping>
<!-- 3.字符编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 4.使用rest风格URI 将普通的post请求转换为指定的delete或者put请求-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 将请求体中的数据解析包装成map-->
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 配置dispatcherServlet.xml 主要是springmvc
<!-- SpringMVC的配置文件,包含网站跳转逻辑的控制 use-default-filters="false"禁用默认过滤规则 -->
<context:component-scan base-package="crud" use-default-filters="false">
<!-- 只扫描控制器 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器,方便页面返回-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 两个标配 -->
<!-- 将SpringMVC不能处理的请求交给Tomcat-->
<mvc:default-servlet-handler/>
<!-- 能支持SpringMVC更高级的一些功能,比如JSR303校验,快捷的ajax请求,映射动态请求-->
<mvc:annotation-driven/>

配置applicationContext.xml文件
- spring配制文件,主要配置和业务逻辑有关的
- 配置mybatis整合
- 配置扫描器,将mybatis接口的实现加入到ioc容器中
- 事务控制
<!-- *******************************************************************************************************-->
<!-- spring配制文件,主要配置和业务逻辑有关的-->
<conrtext:component-scan base-package="crud">
<conrtext:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</conrtext:component-scan>
<!-- 引入外部数据源-->
<conrtext:property-placeholder location="classpath:dbconfig.properties"/>
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- *******************************************************************************************************-->
<!-- 配置mybatis整合-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 引用数据源-->
<property name="dataSource" ref="pooledDataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!-- *******************************************************************************************************-->
<!-- 配置扫描器,将mybatis接口的实现加入到ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描crud包下所有接口的实现-->
<property name="basePackage" value="crud.dao"></property>
</bean>
<!-- *******************************************************************************************************-->
<!-- 事务控制-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 控制数据源-->
<property name="dataSource" ref="pooledDataSource"></property>
</bean>
<!-- 开启基于注解的事务和xml配置形式-->
<!-- 开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式)-->
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut id="txPoint" expression="execution(* crud.service..*(..))"/>
<!-- 配置事务增强 (通知器,告诉计算机切点和增强在哪) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!-- 配置事务增强,事务如何切入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- *代表所有方法都是事务方法-->
<tx:method name="*"/>
<!-- 以get开始的所有方法-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
使用mybatis的逆向工程生成对应的bean以及mapper
- 测试mapper
项目底层逻辑
bean.java
写入与数据库对应的 Employee 和 Department 表的相关数据
Department.java
public class Department {
private Integer deptId;
private String deptName;
public Integer getDeptId() {
return deptId;
}
public Department() {
}
public Department(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName == null ? null : deptName.trim();
}
}
Employee.java
public class Employee {
private Integer empId;
private String email;
public Employee() {
}
public Employee(Integer empId, String empName, String gender, String email, Integer dId) {
this.empId = empId;
this.empName = empName;
this.gender = gender;
this.email = email;
this.dId = dId;
}
@Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", gender='" + gender + '\'' +
", email='" + email + '\'' +
", dId=" + dId +
", department=" + department +
'}';
}
private Integer dId;
// 希望查询员工的同时也查询部门信息
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName == null ? null : empName.trim();
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender == null ? null : gender.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public Integer getdId() {
return dId;
}
public void setdId(Integer dId) {
this.dId = dId;
}
}
dao层
dao层与数据库连接,分为 DepartmentMapper.java 和 EmployeeMapper.java
public interface DepartmentMapper {
long countByExample(DepartmentExample example);
int deleteByExample(DepartmentExample example);
int deleteByPrimaryKey(Integer deptId);
int insert(Department record);
int insertSelective(Department record);
List<Department> selectByExample(DepartmentExample example);
Department selectByPrimaryKey(Integer deptId);
int updateByExampleSelective(@Param("record") Department record, @Param("example") DepartmentExample example);
int updateByExample(@Param("record") Department record, @Param("example") DepartmentExample example);
int updateByPrimaryKeySelective(Department record);
int updateByPrimaryKey(Department record);
}
public interface EmployeeMapper {
Employee selectByPrimaryKeyWithDept(Integer empId);
// 模糊查询
List<Employee> selectByVague(String empName);
//======================================================================================
long countByExample(EmployeeExample example);
int deleteByExample(EmployeeExample example);
int deleteByPrimaryKey(Integer empId);
int insert(Employee record);
int insertSelective(Employee record);
List<Employee> selectByExample(EmployeeExample example);
Employee selectByPrimaryKey(Integer empId);
//带部门的员工查询
List<Employee> selectByExampleWithDept(EmployeeExample example);
int updateByExampleSelective(@Param("record") Employee record, @Param("example") EmployeeExample example);
int updateByExample(@Param("record") Employee record, @Param("example") EmployeeExample example);
int updateByPrimaryKeySelective(Employee record);
int updateByPrimaryKey(Employee record);
}
写DepartmentMapper.xml 和EmployeeMapper.xml(Mybatis层写逻辑),与数据库相连接
service层
注入dao层
@Service
public class DepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
public List<Department> getDepts() {
// 查询所有部门,不用加条件
List<Department> list = departmentMapper.selectByExample(null);
return list;
}
}
@Service
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 根据姓名或id搜索员工
*/
public List<Employee> getEmpByVague(String empName){
return employeeMapper.selectByVague(empName);
}
// 按照员工id查询员工,并且加上部门信息
public Employee getEmpWithDept(Integer id) {
Employee employee = employeeMapper.selectByPrimaryKeyWithDept(id);
return employee;
}
/**
* 查询所有员工
* @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) {
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
criteria.andEmpNameEqualTo(empName);
long count = employeeMapper.countByExample(example);
// 如果count=0,返回true
return count == 0;
}
// 按照员工id查询员工
public Employee getEmp(Integer id) {
Employee employee = employeeMapper.selectByPrimaryKey(id);
return employee;
}
/**
* 员工更新
* @param employee
*/
public void updateEmp(Employee employee) {
employeeMapper.updateByPrimaryKeySelective(employee);
}
/**
* 员工删除
* @param id
*/
public void deleteEmp(Integer id) {
employeeMapper.deleteByPrimaryKey(id);
}
/**
* 批量删除
* @param ids
*/
public void deleteBatch(List<Integer> ids) {
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
// delete from tbl_employee where emp_id in (1,2,...)
criteria.andEmpIdIn(ids);
employeeMapper.deleteByExample(example);
}
}
查询
- 访问index.jsp页面
- index.jsp页面发送出查询员工列表请求
- EmployeeController来接受请求,查出员工数据
- 来到list.jsp页面进行展示
EmployeeService.java中注入dao,dao与mybatis映射文件相关联
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
*/
public List<Employee> getAll(){
return employeeMapper.selectByExampleWithDept(null);
}
EmployeeController.java中,注入service,用pageHelper进行分页处理
@Autowired
EmployeeService employeeService;
// 查询员工数据
@RequestMapping("/emps")
public String getEmps(@RequestParam(value = "pn",defaultValue = "1")Integer pn,Model model){
// 这不是一个分页查询,所以我们引入PageHelper插件
// 在查询之前,传入页码和分页中每页的大小
PageHelper.startPage(pn,5);
List<Employee> emps = employeeService.getAll();
// 使用pageInfo包装,只要将pageInfo交给页面就可以了,封装了详细的分页信息,包括我们查询的数据
//
PageInfo page = new PageInfo(emps);
model.addAttribute("pageInfo",page);
return "list";
}
跳转到 list.jsp页面
<html>
<head>
<title>员工列表</title>
<%
pageContext.setAttribute("APP_PATH", request.getContextPath());
%>
<%-- web路径:
不以/开始的相对路径,找资源是以当前资源的路径为基准,经常容易出问题
而以/开始的相对路径,是以服务器的路径为标注的(http://localhost:3306),需要加上项目名
http://localhost:3306/crud
--%>
<script src="${APP_PATH}/static/js/jquery-3.1.1.js"></script>
<link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
<script src="${APP_PATH}/static/bootstrap-3.3.7-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-info">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<%-- 显示表格数据--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<tr>
<th>#</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>deptName</th>
<th>操作</th>
</tr>
<c:forEach items="${pageInfo.list}" var="emp">
<tr>
<th>${emp.empId}</th>
<th>${emp.empName}</th>
<th>${emp.gender == "M" ? "男" : "女"}</th>
<th>${emp.email}</th>
<th>${emp.department.deptName}</th>
<th>
<button class="btn btn-info btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
编辑
</button>
<button class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
删除
</button>
</th>
</tr>
</c:forEach>
</table>
</div>
</div>
<%-- 显示分页信息--%>
<div class="row">
<%-- 分页文字信息--%>
<div class="col-md-6">
当前第${pageInfo.getPageNum()}/${pageInfo.getPages()}页,共${pageInfo.getTotal()}条记录。
</div>
<%-- 分页条信息--%>
<div class="col-md-6">
<nav aria-label="Page navigation">
<ul class="pagination">
<li><a href="${APP_PATH}/emps?pn=1">首页</a></li>
<%-- 判断是否有上一页(是否是第一页),如果是,则不显示该标签,如果不是,点击可以跳转到上一页--%>
<c:if test="${pageInfo.hasPreviousPage}">
<li>
<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum - 1}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<%-- 循环遍历分页条--%>
<c:forEach items="${pageInfo.navigatepageNums}" var="page_num">
<%-- 判断页码是否等于当前页码,如果等于就让他高亮显示,并且点击无效--%>
<c:if test="${page_num == pageInfo.pageNum}">
<li class="active"><a href="#">${page_num}</a></li>
</c:if>
<%-- 如果不等于就正常显示,点击可以正常跳转--%>
<c:if test="${page_num != pageInfo.pageNum}">
<%-- href="${APP_PATH}/emps?pn=${page_num}跳转到点击的页码 --%>
<li><a href="${APP_PATH}/emps?pn=${page_num}">${page_num}</a></li>
</c:if>
</c:forEach>
<%-- 判断是否有下一页(是否是最后一页),如果是,则不显示该标签,如果不是,点击可以跳转到下一页--%>
<c:if test="${pageInfo.hasNextPage}">
<li>
<a href="${APP_PATH}/emps?pn=${pageInfo.pageNum + 1}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">尾页</a></li>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
但是,我们上面写的只适用于浏览器服务器端模型(B/S),如果有安卓,ios客户端发送请求服务器怎么处理呢?采用ajax解决上述问题
0
- index.jsp页面直接发送ajax请求进行员工分页数据的查询
- 服务器将查出的数据,以json字符串的形式返回给浏览器
- 浏览器收到js字符串。可以使用js对json进行解析,使用js通过dom增删改改变页面。
- 返回json。实现客户端的无关性。
在EmployeeController.java中,将之前写的getEmps方法注释掉,用新的方法,这个方法返回json字符串,最后返回的不是list页面,而是
/**
* 返回json数据
* @ResponseBody要能正常工作,需要导入jackson包
*/
@ResponseBody
@RequestMapping("/emps")
public Msg getEmpsWithJson(@RequestParam(value = "pn",defaultValue = "1") Integer pn){
// 引入pageHelper分页查询,
// 在查询之前只需要调用PageHelper.startPage(),传入页码,以及每一页显示的数量
PageHelper.startPage(pn,10);
// 分页完之后的查询就是分页查询
List<Employee> emps = employeeService.getAll();
// 分页查询完之后,可以使用pageInfo来包装查询后的结果,
// 只需要将pageInfo交给页面就行
// pageInfo封装了详细的分页信息,包括我们查询出来的数据
// 比如总共有多少页,当前是第几页等。。。
// 想要连续显示5页,就加上参数5即可
PageInfo pageInfo = new PageInfo(emps,5);
return Msg.success().add("pageInfo", pageInfo);
}
这里public Msg getEmpsWithJson 返回的是Msg类型的数据,我们事先定义好一个Msg类,里面用来接收返回的状态,这样后面做增删改就知道是否成功了,方便处理
在bean下创建 Msg.java
/**
* 用来返回json的数据的通用类
*/
public class Msg {
// 状态码,100成功,200失败
private int code;
// 提示信息
private String msg;
// 用户要返回给浏览器的数据
private Map<String, Object> extend = new HashMap<String, Object>();
// 返回成功方法
public static Msg success(){
Msg res = new Msg();
res.setCode(100);
res.setMsg("处理成功!");
return res;
}
// 返回失败方法
public static Msg fail(){
Msg res = new Msg();
res.setCode(200);
res.setMsg("处理失败!");
return res;
}
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;
}
}
上传json字符串给服务器端,通过ajax显示到前端页面
<script type="text/javascript">
<%-- 1、页面加载完成以后,直接发送一个ajax请求,获取分页数据--%>
<%-- 总记录数,用于跳转到最后一页。
由于有了分页插件,当跳转页面大于总页面数的时候,就会跳转到最后一页 --%>
var totalRecordCount;
//当前页数,用于修改完员工信息之后跳转到本页面。
var currentPage;
$(function () {
//去首页
to_page(1);
});
//实现页面跳转,想跳到第几页就传参数
function to_page(page) {
//每次页面跳转时,都将全选/全不选设置为false
$("#check_all").prop("checked", false);
$.ajax({
url:"${APP_PATH}/emps",
data:"pn=" + page,
type:"GET",
success:function (res) {
// 1、解析并显示员工数据
build_emps_table(res);
// 2、解析并显示分页条
build_page_nav(res);
// 3、解析并显示分页信息
build_page_info(res);
}
});
}
// 1、解析并显示员工数据
function build_emps_table(res) {
//清空table表格,如果不清空,当页面刷新的时候新的数据不会覆盖旧数据,造成页面混乱
$("#emps_table tbody").empty();
//获取所有员工数据
var emps = res.extend.pageInfo.list;
//遍历员工数据
$.each(emps, function (index, item) {
//在员工数据的最左边加上多选框
var checkBoxTd = $("<td><input type='checkbox' class='check_item'/></td>");
//把一个一个的id name gender取出来 放到表单里显示在前端页面上
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var genderTd = $("<td></td>").append(item.gender == 'M' ? "男" : "女");
var emailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
//编辑按钮
var editBtn = $("<button></button>").addClass("btn btn-info btn-sm edit_btn")
.append($("<span></span>").addClass("glyphicon glyphicon-pencil").append("编辑"));
//为编辑按钮添加一个自定义的属性,来表示当前员工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);
//append方法执行完成以后还是会返回原来的元素,所以可以一直.append添加元素,
//将上面的td(姓名邮箱性别等)添加到同一个tr(方便展示)里
$("<tr></tr>").append(checkBoxTd)
.append(empIdTd)
.append(empNameTd)
.append(genderTd)
.append(emailTd)
.append(deptNameTd)
.append(btnTd)
.appendTo("#emps_table tbody");
//将tr添加到tbody标签中
});
}
// 2、解析并显示分页条
function build_page_nav(res) {
//清空分页条,如果不清空,当页面刷新的时候新的数据不会覆盖旧数据,造成页面混乱
$("#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(res.extend.pageInfo.hasPreviousPage == false){
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
}else{
//如果有上一页,才绑定单击事件
//为首页标签添加单击事件
firstPageLi.click(function () {
to_page(1);
});
//为上一页标签添加单击事件
prePageLi.click(function () {
to_page(res.extend.pageInfo.pageNum - 1);
});
}
//下一页和尾页
var nextPageLi = $("<li></li>").append($("<a></a>").append("»"));
var lastPageLi = $("<li></li>").append($("<a></a>").append("尾页").attr("href","#"));
//如果没有下一页,就设置下一页和尾页按钮不可用
if(res.extend.pageInfo.hasNextPage == false){
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
}else{
//如果有下一页,才绑定单击事件
//为下一页标签添加单击事件
nextPageLi.click(function () {
to_page(res.extend.pageInfo.pageNum + 1);
});
//为尾页标签添加单击事件
lastPageLi.click(function () {
to_page(res.extend.pageInfo.pages);
});
}
//添加首页和前一页到ul标签中
ul.append(firstPageLi).append(prePageLi);
//遍历,给ul中添加页码 index:索引, item:当前元素
$.each(res.extend.pageInfo.navigatepageNums, function (index, item) {
var numLi = $("<li></li>").append($("<a></a>").append(item));
//绑定单击事件,点击页码进行跳转
numLi.click(function () {
to_page(item);
})
//当前页数高亮显示
if(res.extend.pageInfo.pageNum == item){
numLi.addClass("active");
}
ul.append(numLi);
})
//添加下一页和尾页到ul标签中
ul.append(nextPageLi).append(lastPageLi);
//把ul添加到nav标签中
var navEle = $("<nav></nav>").append(ul).appendTo("#page_nav_area");
}
// 3、解析并显示分页文字信息
function build_page_info(res) {
//清空分页文字信息,如果不清空,当页面刷新的时候新的数据不会覆盖旧数据,造成页面混乱
$("#page_info_area").empty();
$("#page_info_area").append("当前第" + res.extend.pageInfo.pageNum + "/" +
res.extend.pageInfo.pages + "页,共" +
res.extend.pageInfo.total +"条记录。");
// 赋值总记录数,方便后面调用
totalRecordCount = res.extend.pageInfo.total;
//赋值当前页数,方便后面调用
currentPage = res.extend.pageInfo.pageNum;
}
</script>
新增员工
- 在index.jsp页面点击”新增”
- 弹出新增对话框
- 去数据库查询部门列表,显示在对话框中
- 用户输入数据,并进行校验
jquery前端校验,ajax用户名重复校验,重要数据(后端校验(JSR303),唯一约束); - 完成保存


<%-- 搭建显示页面 --%>
<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-4">
<button class="btn btn-info" id="emp_add_modal_btn">新增</button>
<button class="btn btn-danger" id="emp_delete_batch_btn">删除</button>
</div>
</div>
点击新增按钮,为按钮添加单击事件
//点击新增按钮,弹出模态框(通过js方式调用)
$("#emp_add_modal_btn").click(function () {
//清除表单数据(表单重置,包括表单数据以及表单样式),防止出现点击保存之后再次点击新增,跳出的模态框还是保存上次添加的记录,避免重复添加。
//取出dom对象,调用reset()方法
// $("#empAddModal form")[0].reset();
reset_form("#empAddModal form");
//发送ajax请求,在弹出模态框之前查询部门信息,显示在下拉列表中
getDepts("#empAddModal select");
//弹出模态框
$("#empAddModal").modal({
backdrop:"static"
});
});
创建员工添加模态框
<%------------------------------ 员工添加的模态框 ------------------------------%>
<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">
<%-- empName --%>
<div class="form-group">
<label class="col-sm-2 control-label">empName</label>
<div class="col-sm-10">
<%-- name="empName" name="email" 与javaBean中一样 spring帮我们自动封装 --%>
<input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
<span class="help-block"></span>
</div>
</div>
<%-- email --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control" id="email_add_input" placeholder="email@gmail.com">
<span class="help-block"></span>
</div>
</div>
<%-- gender --%>
<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_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>
<%-- department --%>
<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" id="dept_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>
<%----------------------------------------------------------------------------%>
添加department时,部门有多个,需要从后台服务器中获取,
//查出所有部门信息并显示在下拉列表中
function getDepts(ele) {
//清空下拉菜单信息,如果不清空,当页面刷新的时候新的数据不会覆盖旧数据,造成页面混乱
$(ele).empty();
$.ajax({
url:"${APP_PATH}/depts",
type:"GET",
success:function (res) {
// 点击添加后,最终返回的json字符串是这样的
// {"code":100,"msg":"处理成功!",
// "extend":{"depts":[{"deptId":1,"deptName":"开发部"},{"deptId":2,"deptName":"测试部"}]}}
//遍历部门信息,在下拉列表中显示部门信息
$.each(res.extend.depts, function () {
//在遍历之前
var optionEle = $("<option></option>").append(this.deptName).attr("value", this.deptId);
//将option标签添加到empAddModal下的select标签中
//传入ele参数,调用时只需把对应id作为参数即可
optionEle.appendTo(ele);
//将option标签添加到empUpdateModal下的select标签中,用于编辑的模态框
// optionEle.appendTo("#empUpdateModal select");
});
}
});
}
完成之后,点击保存按钮,id="emp_save_btn",为他添加单击事件(要校验姓名和邮箱)
$("#emp_save_btn").click(function () {
//1、模态框中填写的表单数据提交给服务器进行保存
//2、先对要提交给服务器的数据进行校验,并且判断之前的ajax用户名校验是否成功
// 只要有一个校验失败,就无法保存
if($(this).attr("ajax-value") == "error"){
return false;
}
if(!validate_add_form() || !emailStatus){
return false;
}
//3、校验之后,再发送ajax请求保存员工
// alert($("#empAddModal form").serialize());
$.ajax({
url:"${APP_PATH}/emp",
type:"POST",
data:$("#empAddModal form").serialize(),
success:function (res) {
// alert(res.msg);
//判断状态码,如果是100(成功),才关闭模态框并进行跳转
if(res.code == 100){
// 员工保存陈宫之后,
// 1、关闭模态框
$('#empAddModal').modal('hide');
// 2、跳转到最后一页,显示刚才保存的数据
// 由于有了分页插件,当跳转的页面大于总页面数的时候,就会跳转到最后一页
to_page(totalRecordCount);
}else {
//显示失败信息
// console.log(res);
//有哪个字段的错误信息就显示哪个字段的
//如果邮箱有误
if (res.extend.errorField.email != undefined){
// 显示邮箱错误信息
show_validate_msg("#email_add_input", "error", res.extend.errorField.email);
}
//如果用户名有误
if(res.extend.errorField.empName != undefined){
//显示用户名错误信息
show_validate_msg("#empName_add_input", "error", res.extend.errorField.empName);
}
}
}
});
});
发送ajax请求,请求emp地址,在controller层
/**
* 如果uri为 /emp/{id} ,请求方式为GET,就查询员工
* 如果uri为 /emp , 请求方式为POST,就保存员工
* 如果uri为 /emp/{id} ,请求方式为PUT,就修改员工
* 如果uri为 /emp/{id} ,请求方式为DELETE,就删除员工
*/
/**
* 保存员工
* 要支持JSR303,需要导入Hibernate-Validator包
*
* @Valid :封装对象之后,对数据进行校验
* BindingResult :封装校验的结果
* @return
*/
@ResponseBody
@RequestMapping(value = "/emp", method = RequestMethod.POST)
public Msg saveEmp(@Valid Employee employee, BindingResult result){
if(result.hasErrors()){
// 校验失败,在模态框中显示校验失败的错误信息
Map<String, Object> map = new HashMap<>();
List<FieldError> errors = result.getFieldErrors();
for(FieldError fieldError : errors){
System.out.println("错误的字段名:" + fieldError.getField());
System.out.println("错误信息:" + fieldError.getDefaultMessage());
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
// 把错误信息返回给浏览器
return Msg.fail().add("errorField", map);
}else{
// 校验成功
employeeService.saveEmp(employee);
return Msg.success();
}
}
在提交之前,添加校验方法
//校验方法,判断用户名是否重复或者不可用
function validate_add_form(){
// $("#empName_add_input").parent().removeClass("has-success has-error");
// $("#empName_add_input").next("span").text("");
// $("#email_add_input").parent().removeClass("has-success has-error");
// $("#email_add_input").next("span").text("");
// 拿到要校验的数据,使用正则表达式
var empName = $("#empName_add_input").val();
//允许数字字母以及_-,6-16位或者中文2-5位
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
//1、校验用户名
if(!regName.test(empName)){
//失败
// alert("用户名必须是6-16位数字,字母或者_-,也可以是2-5位中文组成");
//添加错误样式到输入框
// $("#empName_add_input").parent().addClass("has-error");
//给empName_add_input所在标签的下一个span标签加上文本
// $("#empName_add_input").next("span").text("用户名必须是6-16位数字,字母或者_-,也可以是2-5位中文组成");
show_validate_msg("#empName_add_input", "error", "用户名必须是6-16位数字,字母或者_-,也可以是2-5位中文组成");
return false;
}else{
//成功
// $("#empName_add_input").parent().addClass("has-success");
// $("#empName_add_input").next("span").text("");
// console.log("1");
show_validate_msg("#empName_add_input", "success", "");
}
//2、校验邮箱
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if(!regEmail.test(email)){
// alert("邮箱格式不正确!");
// $("#email_add_input").parent().addClass("has-error");
// $("#email_add_input").next("span").text("邮箱格式不正确!");
show_validate_msg("#email_add_input", "error", "邮箱格式不正确!");
return false;
}else{
// $("#email_add_input").parent().addClass("has-success");
// $("#email_add_input").next("span").text("");
show_validate_msg("#email_add_input", "success", "");
}
return true;
}
验证邮箱是否可用
//设置email的校验状态
var emailStatus;
//校验邮箱是否可用
$("#email_add_input").change(function () {
if(!validate_add_form()){
show_validate_msg("#email_add_input", "error", "邮箱格式错误");
emailStatus = false;
}else{
show_validate_msg("#email_add_input", "success","");
emailStatus = true;
}
})
验证用户名
//校验用户名是否可用
$("#empName_add_input").change(function () {
// 发送ajax请求校验用户名是否可用
// 输入框中的值
var empName = this.value;
$.ajax({
url:"${APP_PATH}/checkuser",
data:"empName=" + empName,
type:"POST",
success:function (res) {
if(res.code == 100){
//成功
show_validate_msg("#empName_add_input", "success", "用户名可用");
// 如果用户名可用,将success标志保存到ajax-value属性中
$("#emp_save_btn").attr("ajax-value", "success");
}else{
//失败
show_validate_msg("#empName_add_input", "error", res.extend.va_msg);
// 如果用户名不可用,将error标志保存到ajax-value属性中
$("#emp_save_btn").attr("ajax-value", "error");
}
}
})
})
在controller中写函数
/**
* 检查用户名是否可用
* @param empName
* @return
*/
@ResponseBody
@RequestMapping(value = "/checkuser")
public Msg checkuser(@RequestParam("empName") String empName){
// 先判断用户名是否是合法的表达式,再判断是否重复
String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
if(!empName.matches(regx)){
return Msg.fail().add("va_msg", "用户名必须是6-16位数字,字母或者_-,也可以是2-5位中文组成");
}else{
// 数据库用户名重复校验
boolean b = employeeService.checkUser(empName);
if(b){
return Msg.success();
}else{
return Msg.fail().add("va_msg", "用户名已存在");
}
}
}
后端校验姓名和邮箱
在bean类(Employee.java)中在姓名属性和邮箱属性上添加注解
public class Employee {
// 姓名 自定义校验规则
@Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",
message = "(后端Employee)用户名必须是6-16位数字,字母或者_-,也可以是2-5位中文组成")
private String empName;
// Email 自定义校验规则
@Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",
message = "(后端Employee)邮箱格式不正确!")
private String email;
private String gender;
private Integer empId;
}
在congtroller中 ,校验员工信息方法上添加注解即可
/**
* 如果uri为 /emp/{id} ,请求方式为GET,就查询员工
* 如果uri为 /emp , 请求方式为POST,就保存员工
* 如果uri为 /emp/{id} ,请求方式为PUT,就修改员工
* 如果uri为 /emp/{id} ,请求方式为DELETE,就删除员工
*/
/**
* 保存员工
* 要支持JSR303,需要导入Hibernate-Validator包
*
* @Valid :封装对象之后,对数据进行校验
* BindingResult :封装校验的结果
* @return
*/
@ResponseBody
@RequestMapping(value = "/emp", method = RequestMethod.POST)
public Msg saveEmp(@Valid Employee employee, BindingResult result){
if(result.hasErrors()){
// 校验失败,在模态框中显示校验失败的错误信息
Map<String, Object> map = new HashMap<>();
// 提取每个字段的错误信息,遍历
List<FieldError> errors = result.getFieldErrors();
for(FieldError fieldError : errors){
System.out.println("错误的字段名:" + fieldError.getField());
System.out.println("错误信息:" + fieldError.getDefaultMessage());
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
// 把错误信息返回给浏览器
return Msg.fail().add("errorField", map);
}else{
// 校验成功
employeeService.saveEmp(employee);
return Msg.success();
}
}
员工修改
- 点击编辑
- 弹出用户修改的模态框(显示用户信息)
- 点击更新,完成用户修改
后端代码
首先 根据员工的id来找其他的信息
service创建getEmp方法,传入员工的id
// 按照员工id查询员工
public Employee getEmp(Integer id) {
Employee employee = employeeMapper.selectByPrimaryKey(id);
return employee;
}
// <%------------------------------------------------------------------%>
@ResponseBody
@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
public Msg updateEmp(Employee employee, HttpServletRequest request){
System.out.println("将要更新的员工数据:" + employee);
employeeService.updateEmp(employee);
return Msg.success();
}
controller层
/**
* 如果uri为 /emp/{id} ,请求方式为GET,就查询员工
* 如果uri为 /emp , 请求方式为POST,就保存员工
* 如果uri为 /emp/{id} ,请求方式为PUT,就修改员工
* 如果uri为 /emp/{id} ,请求方式为DELETE,就删除员工
*/
/**
* 根据id查询员工
* @param id
* @return
*/
// @PathVariable 从路径中取出id
@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);
}
// <%------------------------------------------------------------------%>
@ResponseBody
@RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
public Msg updateEmp(Employee employee, HttpServletRequest request){
System.out.println("将要更新的员工数据:" + employee);
employeeService.updateEmp(employee);
return Msg.success();
}
前端代码
页面展示,点击按钮后弹出修改模态框
<%------------------------------ 员工修改的模态框 -----------------------------%>
<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">
<%-- empName --%>
<div class="form-group">
<label class="col-sm-2 control-label">empName</label>
<div class="col-sm-10">
<p class="form-control-static" id="empName_update_static"></p>
</div>
</div>
<%-- email --%>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control" id="email_update_input" placeholder="email@gmail.com">
<span class="help-block"></span>
</div>
</div>
<%-- gender --%>
<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="F"> 女
</label>
</div>
</div>
<%-- department --%>
<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" id="dept_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>
<%----------------------------------------------------------------------------------------%>
为empUpdateModal绑定单击事件绑定单击事件
//为每个员工的编辑按钮绑定单击事件
//但是,这里的单击事件是在编辑按钮被创建出来之前就已经开始绑定了,所以这里无法绑定单击事件
//有两种办法
// 1)可以在创建按钮的时候就给他绑定单击事件
// 2)绑定单击.live(),而新版jQuery没有live方法,而是用on进行替代
$(document).on("click", ".edit_btn", function () {
//1、通过edit-id属性查出员工信息,显示员工信息
getEmp($(this).attr("edit-id"));
//2、查出部门信息,并显示部门列表
getDepts("#empUpdateModal select");
//把员工的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 (res) {
// console.log(res);
//获取员工数据
var empData = res.extend.emp;
//添加到标签文本中
$("#empName_update_static").text(empData.empName);
//显示邮箱
$("#email_update_input").val(empData.email);
//选中性别单选框
$("#empUpdateModal input[name = gender]").val([empData.gender]);
//选中部门
$("#empUpdateModal select").val([empData.dId]);
}
});
}
//修改员工时,校验邮箱是否可用
$("#email_update_input").change(function () {
validate_update_email();
})
function validate_update_email(){
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", "");
}
return true;
}
// 点击更新,更新员工信息
$("#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({
//加上之前在修改按钮上保存的edit-id的值
url:"${APP_PATH}/emp/" + $(this).attr("edit-id"),
type:"PUT",
data:$("#empUpdateModal form").serialize(),// + "&_method=PUT",
success:function (res) {
// alert(res.msg);
//关闭对话框
$('#empUpdateModal').modal('hide');
//回到本页面
to_page(currentPage);
}
})
})
删除
/**
* 按照员工id删除
* 单个删除和批量删除二合一
* 如果是批量删除,每个id之间用-分隔开
*/
@ResponseBody
@RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
public Msg deleteEmpById(@PathVariable("ids") String ids){
// 如果包含-就是批量删除
if(ids.contains("-")){
// 批量删除
List<Integer> del_ids = new ArrayList<>();
// 按照-分隔开,转化为String数组
String[] str_ids = ids.split("-");
// 组装id的集合
for(String s : str_ids){
del_ids.add(Integer.parseInt(s));
}
employeeService.deleteBatch(del_ids);
}else{
// 单个删除
Integer id = Integer.parseInt(ids);
employeeService.deleteEmp(id);
}
return Msg.success();
}
service层中包含两个方法
/**
* 员工删除
* @param id
*/
public void deleteEmp(Integer id) {
employeeMapper.deleteByPrimaryKey(id);
}
/**
* 批量删除
* @param ids
*/
public void deleteBatch(List<Integer> ids) {
EmployeeExample example = new EmployeeExample();
EmployeeExample.Criteria criteria = example.createCriteria();
// delete from tbl_employee where emp_id in (1,2,...)
criteria.andEmpIdIn(ids);
employeeMapper.deleteByExample(example);
}
}
前端
//单个删除
$(document).on("click", ".delete_btn", function () {
// 弹出是否删除确认框,并显示员工姓名
// 取出员工姓名:找tr标签下的第三个td标签,对应的就是员工名字
var empName = $(this).parents("tr").find("td:eq(2)").text();
//拿到当前员工的id
var empId = $(this).attr("del-id");
//弹出确认框,点击确认就删除
if(confirm("确认删除 [" + empName + "] 吗?")){
// 确认,发送ajax请求删除
$.ajax({
url:"${APP_PATH}/emp/" + empId,
type:"DELETE",
success:function (res) {
alert(res.msg);
//回到本页
to_page(currentPage);
}
})
}
});
// 完成全选/全不选功能
$("#check_all").click(function () {
// attr获取checked是undefined,因为我们没有定义checked属性,attr获取的是自定义属性值
// 而我们这些dom原生的属性,可以用prop来获取这些值
// alert($(this).prop("checked"));
// 让所有复选框状态同步
$(".check_item").prop("checked", $(this).prop("checked"));
});
// 当本页面所有复选框都选上时,自动将全选复选框选上
$(document).on("click", ".check_item", function () {
//判断当前选择中的元素是否是当前页面所有check_item的个数
var flag = $(".check_item:checked").length == $(".check_item").length;
$("#check_all").prop("checked", flag);
})
// 为批量删除绑定单击事件
$("#emp_delete_batch_btn").click(function () {
var empNames = "";
var del_idstr = "";
//遍历每一个被选中的复选框
$.each($(".check_item:checked"), function () {
// 获取要删除的员工姓名
empNames += $(this).parents("tr").find("td:eq(2)").text() + "\n";
//获取要删除的员工的id
del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";
});
//去除多余的-
del_idstr = del_idstr.substring(0, del_idstr.length - 1);
if(confirm("确认删除 \n" + empNames + " 吗?")){
$.ajax({
url:"${APP_PATH}/emp/" + del_idstr,
type:"DELETE",
success:function (res) {
alert(res.msg);
to_page(currentPage);
}
})
}
});
更多推荐



所有评论(0)