ssm整合笔记

    科技2025-10-29  9

    文章目录

    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配置

    <!--导入相关依赖: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">&laquo;</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">&raquo;</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("&laquo;")); 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("&raquo;")); 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">&times;</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">&times;</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("&laquo;")); //没有上一页时,不显示上一页及首页 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("&raquo;")); 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;
    Processed: 0.009, SQL: 8