ssm整合笔记

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

环境搭建

整体结构

image-20201008105120282

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字段,但在实际工作中,需要查询到的是部门名称

逆向工程自动生成的职员相关属性跟字段如下

image-20201003110005700

因此,我们需要手动添加联表查询

bean实体类

在职员的实体类中添加部门实体类属性

image-20201003110124456

dao层接口

添加含部门名称的两个新方法接口

image-20201003111015962

mapper文件配置
添加新的resultmap

image-20201003111343808

注意这里不要写成jdbcType

添加新的字段列表

为防止字段冲突,指定表名称(使用别名)

image-20201003111423547

添加方法的实现

使用上面自定义的resultMap,refid(字段),使用联表查询语句,使用别名(上面字段使用了别名,这里不定义别名的话会报错)

image-20201003111606148

测试

image-20201003112226483

使用spring单元测试
导入springTest模块

image-20201003112549253

@ContextConfiguration,指定spring配置文件的位置,如果有多个,就用逗号分隔

@RunWith,指定用什么环境进行单元测试

image-20201003193323969

测试部门与员工插入

image-20201003193439629

测试批量插入

image-20201003193513688

注意这里要在spring和mybatis的整合文件中配置批量执行的 sqlSession

image-20201003193609411

规定URI标准

/emp/{id} GET请求 查询员工

/emp POST请求 保存员工

/emp/{id} PUT请求 修改员工

/emp/{id} DELETE 删除员工

查询

后端

分页查询相关配置

在maven中引入分页查询的依赖

image-20201003200726107

在MyBatis的配置文件中配置分页插件

image-20201003200913285

查询所有员工

service层

image-20201004211234686

controller层

调用分页查询

image-20201004211304066

使用spring的测试模块来测试请求

这里spring和springMVC的配置都要引入

image-20201003211022459

image-20201003212603432

image-20201003212541452

首页可以直接转发到需要的页面

image-20201004211120023

前端页面展示

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>
页面效果

image-20201005092433497

ajax实现
  • index.jsp页面直接发送ajax请求进行员工分页数据的查询
  • 服务器将查出的数据,以json字符串的形式返回给浏览器
  • 浏览器接收到json字符串,可以使用js对json字符串进行解析,使用js通过dom增删改变页面
  • 返回json,实现客户端的无关性
引入json依赖

image-20201005092951102

添加处理返回信息的工具类

image-20201005093148715

返回json字符串

image-20201005092938379

返回的字符串

image-20201005093207792

使用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>
效果

image-20201006112054028

记得清空表格数据和页码信息(使用empty()方法),因为ajax不会刷新页面,不清空会导致下图所示问题

image-20201006112116092

新增

逻辑

在index.jsp页面点击新增,弹出新增对话框

去数据库查询部门列表,显示在对话框中

用户输入数据,进行校验

​ jQuery前端校验,ajax用户名重复校验,重要数据后端校验(JSR303),设置唯一约束,防止用户提交非法数据

完成保存

后端

保存员工

controller层

image-20201006112323898

service层

image-20201006150244120

获得部门信息

image-20201006151948764

service层

image-20201006152045754

检测用户名是否存在

service层

image-20201006191007436

controller层

image-20201006191034844

前端

员工新增模态框

image-20201008111443134

绑定新增按钮,点击后跳出员工新增的模态框

image-20201006151221198

image-20201006151905435

模态框中部门处要获得部门信息

image-20201006151925362

绑定保存按钮,填写好数据后发送ajax请求

image-20201006152514419

image-20201006152301033

测试

image-20201006145321363

image-20201006150149195

添加表单校验

检测输入的名称和邮箱是否符合规范

用户名规范可以在前台检测,但是用户名是否已经存在只能在后端检测,因此直接在后端检测用户名,前端检测邮箱格式

image-20201006192151667

image-20201006192216879

image-20201006192239546

image-20201006192516379

添加校验用户名

image-20201006191057270

测试

image-20201006192833499

image-20201006192849938

image-20201006192724566

注意:前端检测是不安全的!!!

image-20201006224447177

改成sucess

image-20201006223920402

保存成功

image-20201006224540848

使用JSR303

导入相关依赖

image-20201006195447115

在实体类使用@Pattern注解,限制写入的字段

image-20201006210434441

在后端调用员工保存方法时做判断

@Valid用来检测字段是否符合@Pattern规定的标准

image-20201006210548315

index页面

在保存时做判断,如果有错误,拿到后端返回的错误信息并返回前端页面显示

image-20201006210737767

模拟用户跳过前端验证

image-20201006210944682

测试

image-20201006211020019

弊端:数据库没有设置名称字段唯一性

image-20201006225657388

改为success后,插入成功

image-20201006225728063

建表后修改字段唯一

USE ssmbuild;

ALTER TABLE tbl_emp ADD UNIQUE(emp_name);

修改

逻辑

点击编辑,弹出用户修改的模态框(显示用户信息)

点击更新,完成用户修改

后端

查询单个员工信息

service层

image-20201007104443997

controller层

image-20201007104455963

更新员工信息

service层

image-20201007104508357

controller层

image-20201007105347451

前端

添加员工修改的模态框

image-20201007101059771

点击编辑按钮,触发事件

注意:编辑按钮是在页面创建完成后,构建表格内容时才创建的,直接像下图这样绑定是不行的

image-20201007093105443

可以使用jQuery的on()方法(在1.7之前是live()方法)

on()方法在被选元素及子元素上添加一个或多个事件处理程序

image-20201007094336430

image-20201007094329781

image-20201007101234640

为编辑按钮添加自定义属性获取员工id

image-20201007092248373

绑定修改按钮,调出模态框

image-20201007170144994

获得员工信息

image-20201007170237495

绑定更新按钮,发送ajax请求给后端更新员工信息

image-20201007170332784

测试

image-20201007170437275

image-20201007170505754

可以看到是有数据信息的

问题:

请求体中有数据;但是Employee对象封装不上;

在后端更新方法中传入原生Request,查看请求体中的值

image-20201007175625302

image-20201007173009915

原因:

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

image-20201007174511319

2,使用spring提供的解决方案,在web.xml中配置HttpPutFormContentFilter

image-20201007175220871

image-20201007174956277

spring5.1之后使用FormContentFilter代替该方法,FormContentFilter也支持PATCH和DELETE请求

image-20201007180811481

image-20201007180558906

配置之后再次测试

image-20201007175659318

image-20201007175710435

删除

单个删除

逻辑

点击删除,弹出是否确认删除的弹窗

点击确认,完成删除用户;点击取消,取消删除

后端

根据id删除用户

service层

image-20201007193259469

controller层

image-20201007193331321

前端

为删除按钮添加自定义属性,获取用户id

image-20201007193546816

image-20201007203518734

测试

image-20201007195933245

image-20201007195941040

image-20201007195947918

批量删除

逻辑

添加多选框,完成全选全不选功能

选定后点击删除,弹出提示框,提示是否删除【用户1,用户2】

点击确认,完成批量删除用户

后端

service层

增加批量删除方法

image-20201007203046776

cortroller层

更改之前的删除方法

image-20201007203111313

前端

添加多选框

image-20201007203413081

image-20201007204120010

image-20201007204133738

记得更改之前单个删除绑定的员工名称元素
image-20201007233747832

添加全选全不选

image-20201007234042040

当手动选择本页全部数据时,全选框应自动被选定

image-20201007234133568

image-20201007235014893

测试

image-20201007235122754

image-20201007235131236

image-20201007235138617

项目源码

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;
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值