SSM整合(maven)

一、新建maven工程

二、引入项目依赖

Maven Repository: Search/Browse/Explore (mvnrepository.com)https://mvnrepository.com/

  • spring
  • springMVC
  • mybatis
  • 数据库驱动、连接池
  • 其他(servlet-api,junit等)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ice.ssm</groupId>
    <artifactId>ssm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!--springMVC  spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--spring jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--spring面向切面编程-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!--spring mybatis整合-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--数据库连接池、驱动-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <!--servlet-api-->
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5-20081211</version>
            <scope>provided</scope>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--mybatis逆向工程-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>
    </dependencies>

</project>

三、引入前端框架

        如bootstrap

Bootstrap · The most popular HTML, CSS, and JS library in the world. (getbootstrap.com)https://getbootstrap.com/

四、编写SSM整合的关键配置文件

        1. 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">
    <!--启动spring容器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!--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>
    <!--配置springMVC的编码过滤器-->
    <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>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!--使用REST风格的URI-->
    <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>

</web-app>

        2. 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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--springmvc配置文件,主要包含网站跳转逻辑的控制配置-->
    <context:component-scan base-package="com.ice.ssm" use-default-filters="false">
        <!--只扫描控制器  也可以直接写 base-package="com.ice.ssm.controller"-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--两个标准配置-->
    <!--DispatcherServlet不能处理的请求交给默认的servlet-->
    <mvc:default-servlet-handler/>
    <!--开启注解驱动 映射动态请求
         支持SpringMVC更高级的功能,比如JSR303校验,快捷的ajax等
    -->
    <mvc:annotation-driven/>
</beans>

        3. spring(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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--spring配置的核心点:数据源、与mybatis整合、事务控制-->
    
    
    <!--组件扫描-->
    <context:component-scan base-package="com.ice">
        <!--配置Spring的扫描器不扫描@Controller-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--spring配置文件,主要配置和业务逻辑有关的-->
    <!--数据源,事务控制等-->
    <context:property-placeholder location="classpath:dbconfig.properties"/>
    <bean id="DruidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--配置spring和mybatis整合-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--指定mybatis全局配置文件的位置-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!--数据源-->
        <property name="dataSource" ref="DruidDataSource"></property>
        <!--指定mybatis的mapper文件的位置-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>
    <!--配置扫描器,将mybatis接口的实现(是一个代理对象)加入到IOC容器中-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--扫描所有dao接口,加入到ioc容器中-->
        <property name="basePackage" value="com.ice.ssm.dao"></property>
    </bean>

    <!--事务控制-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--数据源-->
        <property name="dataSource" ref="DruidDataSource"></property>
    </bean>
    <!--开启基于注解的事务,使用xml配置形式的事务【推荐重要的都使用配置式】-->
    <aop:config>
        <!--配置切入点
            切入点表达式 execution(* com.ice.ssm.service..*(..)
                两个点表示service下面还有子包也可以
        -->
        <aop:pointcut id="txPoint" expression="execution(* com.ice.ssm.service..*(..))"/>
        <!--配置切面 事务增强-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
    </aop:config>
    <!--配置事务增强 ,事务如何切入-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--* : 表示所有方法都是事务方法-->
            <tx:method name="*"/>
            <!--get* : 表示以get开始的所有方法
                read-only="true":如果所有get开头的方法都认为是查询,这个配置会做一些优化???
            -->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    

</beans>

        4. mybatis

        使用mybatis的逆向工程生成对应的bean以及mapper

        (mbg.xml配置得想吐。。。)

MyBatis Generator Core – Introduction to MyBatis Generatorhttp://mybatis.org/generator/

        pom.xml中添加依赖:

        <!--mybatis逆向工程-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        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>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!--设置逆向生成的文件没有注释-->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--配置数据库连接信息-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_crud?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT"
                        userId="root"
                        password="123456">
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!--指定Javabean生成的位置-->
        <javaModelGenerator targetPackage="com.ice.ssm.bean" targetProject="src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!--指定sql映射文件生成的位置-->
        <sqlMapGenerator targetPackage="mapper"  targetProject="src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!--指定dao接口生成的位置 mapper接口-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.ice.ssm.dao"  targetProject="src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!--table指定每个表的生成策略-->
        <table tableName="tbl_emp" domainObjectName="Employee">
        </table>
        <table tableName="tbl_dept" domainObjectName="Department"></table>

    </context>
</generatorConfiguration>

        mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--别名-->
    <typeAliases>
        <package name="com.ice.ssm.bean"/>
    </typeAliases>
</configuration>

        生成代码:

public class MBGTest {
    @Test
    public void test() throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("mbg.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
}

五、测试

        1. 按照需要修改了逆向工程生成的mapper文件后老是报错:

 但是相关的sql片段都是有的,最后发现:

    

        服…… 

        2. 批量sqlSession

        在applicationConfig.xml中添加:

    <!--配置一个可以执行批量的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
        <constructor-arg name="executorType" value="BATCH"></constructor-arg>
    </bean>

        测试自动装配执行批量操作的sqlSession ,使用该sqlSession: 

public class MapperTest {
    @Autowired
    DepartmentMapper departmentMapper;
    @Autowired
    EmployeeMapper employeeMapper;
    @Autowired
    SqlSession sqlSession;

    @Test
    public void testDept(){
//        //1. 创建springIOC容器
//        ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
//        //2. 从容器中获取mapper
//        DepartmentMapper bean = ioc.getBean(DepartmentMapper.class);

        //推荐使用Spring的单元测试,自动注入
        //需要导入SpringTest依赖 ,@ContextConfiguration指定Spring配置文件的位置,autowired需要的组件
        System.out.println(departmentMapper);

        //1. 插入几个部门
//        departmentMapper.insertSelective(new Department(null,"艺术部"));
//        departmentMapper.insertSelective(new Department(null,"开发部"));
//        departmentMapper.insertSelective(new Department(null,"测试部"));

        //2. 插入几个员工
        //employeeMapper.insertSelective(new Employee(null,"zt","F","zt@323.com",1));

        //3. 批量插入多个员工
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 10; i++) {
            String name = UUID.randomUUID().toString().substring(0, 5);
            mapper.insertSelective(new Employee(null,name,"M",name+"@163.com",1));
        }

    }
}

六、项目目录

 URI:

  • /emp/{id} GET 查询员工
  • /emp POST 保存员工
  • /emp/{id} PUT 修改员工
  • /emp/{id} DELETE 删除员工

 

后面随便看看啦,主要看逻辑,要不然js写到吐……

七、实例功能实现——查询

        查询URI:/emps

  1.  访问index.jsp页面
  2.  index.jsp页面发送出查询员工列表请求
  3.  EmployeeController接受请求,查出员工数据
  4.  list.jsp进行页面展示

7.1 分页插件

        1. 导入依赖pom.xml

        <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.0.0</version>
        </dependency>

         2. 在mybatis全局配置文件mybatis-config.xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--别名-->
    <typeAliases>
        <package name="com.ice.ssm.bean"/>
    </typeAliases>
    <!--分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--分页参数合理化 页码显示在合理的范围之内
                页码合理范围:小于0显示第一页,大于总页码显示最后一页
            -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
</configuration>

        3. service和controller

@Service
public class EmployeeService {
    @Autowired
    EmployeeMapper employeeMapper;

    /**
     * 查询所有员工信息
     * @return
     */
    public List<Employee> getAll() {
        return employeeMapper.selectByExampleWithDept(null);
    }
}
/**
 * 处理员工CRUD请求
 */
@Controller
public class EmployeeController {
    @Autowired
    EmployeeService employeeService;

    /**
     * 分页查询
     * @param pn 从第几页开始查,默认从第1页
     * @return
     */
    @RequestMapping(value = "/emps")
    public String getEmps(@RequestParam(value = "pn",defaultValue = "1")Integer pn, Model model){

        //引入Page Helper 插件
        //从第pn页开始查,每页2条数据
        PageHelper.startPage(pn,2);
        //设置分页后,startPage后面紧跟的这个查询就是分页查询
        List<Employee> emps = employeeService.getAll();
        //用pageInfo包装查出来的员工列表,只需要将PageInfo(其中封装了详细的分页信息)交给页面就能做分页了!
        //设置连续显示的页数:5页
        PageInfo page = new PageInfo(emps,5);
        model.addAttribute("pageInfo",page);
        return "list";
    }
}

        spring单元测试需要servlet3,所以需要添加servlet3的依赖 :

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>

        4. 测试

7.2 实现

7.2.1 jsp实现

            需要jstl依赖:

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
  1.         访问index.jsp页面
  2.         index.jsp页面发送出查询员工列表请求
  3.         EmployeeController来接受请求,查出员工数据
  4.         来到list.jsp页面进行展示
  5.         pageHelper分页插件完成分页查询功能

        index.jsp: 

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<jsp:forward page="/emps"></jsp:forward>

        list.jsp: 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH",request.getContextPath());
    %>
    <%--web路径:不以/开始的相对路径,找资源以当前资源的路径为基准,容易出现问题
                 以/开始的相对路径,找资源以服务器路径为标准:http://localhost:8080/ssm  需要加上项目名
    --%>

    <%--引入样式--%>
    <link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <%--引入jQuery--%>
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
</head>
<body>

    <div class="container">
        <%--标题--%>
        <div class="row">
            <div class="col-md-12">
                <h1>SSM-CRUD</h1>
            </div>
        </div>
            <%--按钮--%>
        <div class="row">
            <div class="col-md-4 col-md-offset-8">
                <button class="btn btn-primary">新增</button>
                <button class="btn btn-danger">删除</button>
            </div>
        </div>
            <%--表格--%>
        <div class="row">
            <div class="col-md-12">
                <table class="table table-hover">
                    <tr>
                        <th>#</th>
                        <th>empName</th>
                        <th>email</th>
                        <th>gender</th>
                        <th>departName</th>
                        <th>op</th>
                    </tr>
                    <c:forEach items="${pageInfo.list}" var="emp">
                        <tr>
                            <td>${emp.empId}</td>
                            <td>${emp.empName}</td>
                            <td>${emp.gender=="M"?"男":"女"}</td>
                            <td>${emp.email}</td>
                            <td>${emp.department.deptName}</td>
                            <td>
                                <button class="btn btn-primary btn-sm"> 编辑
                                    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
                                </button>
                                <button class="btn btn-danger btn-sm">删除
                                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
                                </button>
                            </td>
                        </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">
                            <li><a href="${APP_PATH}/emps?pn=1">首页</a></li>
                            <c:if test="${pageInfo.hasPreviousPage}">
                                <li>
                                    <a href="${APP_PATH}/emps?pn=${pageInfo.pageNum-1}" aria-label="Previous">
                                        <span aria-hidden="true">&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>
                            </c:if>
                            <li><a href="${APP_PATH}/emps?pn=${pageInfo.pages}">末页</a></li>
                        </ul>
                    </nav>
                </div>
        </div>
    </div>
</body>
</html>

        添加一些数据并改为每页显示4条数据:

7.2.2 ajax+json实现 (所有功能都是ajax+json实现)

  1.         index.jsp页面直接发送ajax请求进行员工分页数据的查询
  2.         服务器将查出的数据,以json字符串的形式返回给浏览器
  3.         浏览器收到json字符串,使用js解析json,使用js通过dom增删改,改变页面
  4.         返回json。实现客户端的无关性(浏览器,安卓,IOS)

        导入JSON依赖:

        <!--JSON-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.8</version>
        </dependency>

        新建一个通用的返回JSON数据的类: 

/**
 * 返回json数据的通用类
 */
public class Msg {
    //状态码 100-成功  200-失败
    private int code;

    //提示信息
    private String msg;

    //用户要返回给浏览器的信息
    private Map<String, Object> extend = new HashMap<String, Object>();

    /**
     * 成功
     *
     * @return
     */
    public static Msg success() {
        Msg result = new Msg();
        result.setCode(100);
        result.setMsg("success");
        return result;
    }

    /**
     * 失败
     *
     * @return
     */
    public static Msg fail() {
        Msg result = new Msg();
        result.setCode(200);
        result.setMsg("fail");
        return result;
    }

    public Msg add(String key, Object value) {
        this.getExtend().put(key, value);
        return this;
    }


    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Map<String, Object> getExtend() {
        return extend;
    }

    public void setExtend(Map<String, Object> extend) {
        this.extend = extend;
    }
}

         修改控制器方法:(@ResponseBody注解可以处理json)

    /**
     * @ResponseBody 需要导入JSON包
     * @param pn
     * @return
     */
    @RequestMapping(value = "/emps")
    @ResponseBody
    public Msg getEmpsWithJson(@RequestParam(value = "pn",defaultValue = "1")Integer pn){
        //引入Page Helper 插件
        //从第pn页开始查,每页4条数据
        PageHelper.startPage(pn,4);
        //设置分页后,startPage后面紧跟的这个查询就是分页查询
        List<Employee> emps = employeeService.getAll();
        //用pageInfo包装查出来的员工列表,只需要将PageInfo(其中封装了详细的分页信息)交给页面就能做分页了!
        //设置连续显示的页数:5页
        PageInfo pageInfo = new PageInfo(emps,5);
        return Msg.success().add("pageInfo",pageInfo);
    }

        启动服务器得到如下结果:(接下来就要用js解析下列json数据)

        index.jsp:(以前的index.jsp改名为index_jsp.jsp)(这个看着太乱了,下一个index.jsp开始用注释隔了一下,不会一看就吐的

        后面的index.jsp都是在这个基础上继续做的,如果怕吐了,要么就直接看最后一个完整版的

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());

    %>
    <%--web路径:不以/开始的相对路径,找资源以当前资源的路径为基准,容易出现问题
                 以/开始的相对路径,找资源以服务器路径为标准:http://localhost:8080/ssm  需要加上项目名
    --%>

    <%--引入jQuery  必须在bootstrap.min.js之前引入--%>
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
    <%--引入样式--%>
    <link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>


</head>
<body>

<div class="container">
    <%--标题--%>
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <%--按钮--%>
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary">新增</button>
            <button class="btn btn-danger">删除</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>email</th>
                        <th>gender</th>
                        <th>departName</th>
                        <th>op</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) {
                //console.log(result);
                //1. 解析并显示员工数据
                build_emp_table(result);
                //2. 解析并显示分页信息
                build_page_info(result);
                //3. 解析显示分页条
                build_page_nav(result);
            }
        });
    }

    //1. 解析并显示员工数据
    function build_emp_table(result) {
        //每一次构建表格之前需要先清空table数据
        $("#emps_table tbody").empty();

        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            //index 索引,  ietm 每一项
            // alert(item.empName)
            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);
            /*
            * <button class="btn btn-primary btn-sm"> 编辑
                   <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
              </button>
            * */
            var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm")
                                                .append($("<span></span>").addClass("glyphicon glyphicon-pencil"))
                                                .append("编辑");
            /*
            * <button class="btn btn-danger btn-sm">删除
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
              </button>
            * */
            var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm")
                                                .append($("<span></span>").addClass("glyphicon glyphicon-trash"))
                                                .append("删除");
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
            //可以链式执行是因为append方法执行完成还是返回原来的元素
            $("<tr></tr>").append(empIdTd)
                          .append(empNameTd)
                          .append(genderTd)
                          .append(emailTd)
                          .append(deptNameTd)
                          .append(btnTd)
                          .appendTo("#emps_table tbody");//appendTo添加到table的tbody中
        })
    }

    //2. 解析并显示分页信息
    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+"条记录");
    }

    //3. 解析显示分页条,点击翻页
    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{
            //为元素添加点击翻页的事件
            firstPageLi.click(function(){
                to_page(1);
            });
            prePageLi.click(function(){
                to_page(result.extend.pageInfo.pageNum -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中添加页码提示  1,2,3,4
        $.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>

 八、实例功能实现——新增

        新增URI:/emp   POST 

  1. 在index.jsp页面点击”新增”
  2. 弹出新增对话框
  3. 去数据库查询部门列表,显示在对话框中
  4. 用户输入数据,并进行校验 【 jquery前端校验,ajax用户名重复校验,重要数据(后端校验(JSR303),唯一约束)】
  5. 完成保存
        <!--JSR303数据校验支持-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>

        department的service和controller:

/**
 * 处理部门相关的请求
 */
@Controller
public class DepartmentController {
    @Autowired
    private DepartmentService departmentService;

    @RequestMapping(value = "/depts")
    @ResponseBody
    public Msg getDepts(){
        //查出所有部门信息
        List<Department> depts = departmentService.getDepts();
        return Msg.success().add("depts",depts);
    }
}
@Service
public class DepartmentService {

    @Autowired
    private DepartmentMapper departmentMapper;

    public List<Department> getDepts() {
        List<Department> depts = departmentMapper.selectByExample(null);
        return depts;
    }
}

        employee的bean、service和controller:

    /**
     * 保存员工
     * @param employee
     */
    public void saveEmp(Employee employee) {
        employeeMapper.insertSelective(employee);
    }

    /**
     * 检验用户名是否可用
     *
     * @param empName
     * @return true:代表当前姓名可用
     */
    public boolean checkUser(String empName) {
        EmployeeExample employeeExample = new EmployeeExample();
        EmployeeExample.Criteria criteria = employeeExample.createCriteria();
        criteria.andEmpNameEqualTo(empName);
        long count = employeeMapper.countByExample(employeeExample);
        return count == 0;
    }
    /**
     * 检查用户名是否已经存在
     * @param empName
     * @return
     */
    @RequestMapping(value = "/checkname")
    @ResponseBody
    public Msg checkname(@RequestParam("empName") String empName){
        //先判断用户名是否符合正则校验
        String regx = "(^[a-zA-Z0-9_-]{2,16}$)|(^[\u2E80-\u9FFF]{2,5})";
        if(!empName.matches(regx)){
            return Msg.fail().add("va_msg", "用户名必须是2-16位数字和字母的组合或者2-5位中文");
        }
        //数据库用户名重复校验
        boolean b = employeeService.checkUser(empName);
        System.out.println(b);
        if(b){
            return Msg.success();
        }else{
            return Msg.fail().add("va_msg","用户名不可用");
        }
    }

    /**
     * 保存员工信息
     * @return
     */
    @RequestMapping(value = "/emp" ,method = RequestMethod.POST)
    @ResponseBody
    public Msg saveEmp(@Valid Employee employee , BindingResult result){//前端的name和bean中的属性名一致,可以自动封装
        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("errorFields",map);
        }else{
            employeeService.saveEmp(employee);
            return Msg.success();
        }
    }

        index.jsp: (全是js……主要是数据校验)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());

    %>
    <%--web路径:不以/开始的相对路径,找资源以当前资源的路径为基准,容易出现问题
                 以/开始的相对路径,找资源以服务器路径为标准:http://localhost:8080/ssm  需要加上项目名
    --%>
    <%--===========================================================================================================--%>
    <%--引入jQuery  必须在bootstrap.min.js之前引入--%>
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
    <%--引入样式--%>
    <link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
    <%--============================================================================================================--%>

</head>
<body>
<!--员工添加的模态框 Modal ======================================================================================-->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">add employee</h4>
            </div>
            <div class="modal-body">
                <%--表单--%>
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">empName</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="empName" id="empName_add_input"
                                   placeholder="empName">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" name="email" id="email_add_input"
                                   placeholder="email@163.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">gender</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_add_input" value="M"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_add_input" value="F" checked="checked"> 女
                            </label>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">deptName</label>
                        <div class="col-sm-3">
                            <%--部门提交时,提交id即可--%>
                            <select class="form-control" name="dId" id="dept_add_select"></select>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" id="emp_save_btn">Save</button>
            </div>
        </div>
    </div>
</div>
<%--==============================================================================================================--%>
<div class="container">
    <%--标题--%>
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <%--按钮--%>
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger">删除</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>email</th>
                    <th>gender</th>
                    <th>departName</th>
                    <th>op</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 totalRecords;//总记录数

    //页面加载完成以后,直接发送一个ajax请求,拿到分页数据=============================================================
    $(function () {
        //第一页数据
        to_page(1);
    });

    //查询某一页的数据
    function to_page(pn) {
        $.ajax({
            url: "${APP_PATH}/emps",
            data: "pn=" + pn,
            type: "GET",
            success: function (result) {
                //console.log(result);
                //1. 解析并显示员工数据
                build_emp_table(result);
                //2. 解析并显示分页信息
                build_page_info(result);
                //3. 解析显示分页条
                build_page_nav(result);
            }
        });
    }

    //1. 解析并显示员工数据========================================================================================
    function build_emp_table(result) {
        //每一次构建表格之前需要先清空table数据
        $("#emps_table tbody").empty();

        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            //index 索引,  ietm 每一项
            // alert(item.empName)
            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);
            /*
            * <button class="btn btn-primary btn-sm"> 编辑
                   <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
              </button>
            * */
            var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm")
                .append($("<span></span>").addClass("glyphicon glyphicon-pencil"))
                .append("编辑");
            /*
            * <button class="btn btn-danger btn-sm">删除
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
              </button>
            * */
            var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm")
                .append($("<span></span>").addClass("glyphicon glyphicon-trash"))
                .append("删除");
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
            //可以链式执行是因为append方法执行完成还是返回原来的元素
            $("<tr></tr>").append(empIdTd)
                .append(empNameTd)
                .append(genderTd)
                .append(emailTd)
                .append(deptNameTd)
                .append(btnTd)
                .appendTo("#emps_table tbody");//appendTo添加到table的tbody中
        })
    }

    //2. 解析并显示分页信息========================================================================================
    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 + "条记录");
        totalRecords = result.extend.pageInfo.total;
    }

    //3. 解析显示分页条,点击翻页==================================================================================
    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 {
            //为元素添加点击翻页的事件
            firstPageLi.click(function () {
                to_page(1);
            });
            prePageLi.click(function () {
                to_page(result.extend.pageInfo.pageNum - 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中添加页码提示  1,2,3,4
        $.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();//jQuery没有reset方法,所以转为DOM对象进行重置
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
    }

    //点击新增按钮弹出模态框=======================================================================================
    $("#emp_add_modal_btn").click(function () {
        //每次弹出之前都重置模态框中的表单数据项
        reset_form("#empAddModal form");
        //发送ajax请求,查出部门信息并显示在下拉列表中
        getDepts();

        //弹出模态框
        $("#empAddModal").modal({
            backdrop: "static"
        });
    });

    //查出部门信息并显示在下拉列表中================================================================================
    function getDepts() {
        //每一次请求需要先清空下拉列表
        $("#dept_add_select").empty();

        $.ajax({
            url: "${APP_PATH}/depts",
            type: "GET",
            success: function (result) {
                //console.log(result);
                //{"code":100,"msg":"success","extend":{"depts":[{"deptName":"艺术部","id":1},{"deptName":"开发部","id":2},{"deptName":"测试部","id":3}]}}
                //显示下拉列表在模态框
                $.each(result.extend.depts, function () {
                    //不传参数时可以使用this
                    var optionEle = $("<option></option>").append(this.deptName).attr("value", this.id);
                    optionEle.appendTo("#dept_add_select");
                });
            }
        });
    }

    //校验模态框中填入数据的合理性==================================================================================
    function validate_add_form() {
        //1、拿到要校验的数据,使用正则表达式
        var empName = $("#empName_add_input").val();
        var regName = /(^[a-zA-Z0-9_-]{2,16}$)|(^[\u2E80-\u9FFF]{2,5}$)/;
        if (!regName.test(empName)) {
            //alert("用户名必须是2-5位中文或者2-16位英文和数字的组合");
            show_validate_msg("#empName_add_input", "error", "用户名必须是2-5位中文或者2-16位英文和数字的组合");
            return false;
        } else {
            show_validate_msg("#empName_add_input", "success", "");
        }


        //2、校验邮箱信息
        var email = $("#email_add_input").val();
        var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)) {
            //alert("邮箱格式不正确");
            //应该清空这个元素之前的样式
            show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
            /* $("#email_add_input").parent().addClass("has-error");
            $("#email_add_input").next("span").text("邮箱格式不正确"); */
            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);
        }
    }

    //发送ajax请求校验用户名是否可用================================================================================
    //给deptName的输入框绑定change事件
    $("#empName_add_input").change(function () {
        //填入的empName
        var name = this.value;
        $.ajax({
            url: "${APP_PATH}/checkname",
            data: "empName=" + name,
            type: "POST",//用GET中文名一致可用???
            success: function (result) {
                if (result.code == 100) {
                    show_validate_msg("#empName_add_input", "success", "用户名可用");
                    $("#emp_save_btn").attr("ajax-va","success");
                } else {
                    show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
                    $("#emp_save_btn").attr("ajax-va","error");
                }

            }
        })

    });

    //给模态框的save按钮绑定单击事件================================================================================
    $("#emp_save_btn").click(function () {
        //模态框中填写的表单数据提交给服务器进行保存

        //1. 对输入的数据进行正则校验
        if (!validate_add_form()) {
            return false;
        }

        //判断ajax请求检验用户名是否可用的返回值
        if($(this).attr("ajax-va")=="error"){
            show_validate_msg("#empName_add_input", "error", "用户名已存在");
            return false;
        }

        //2. 发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: $("#empAddModal form").serialize(),//jquery提供该方法可以序列化整个表单的数据
            success: function (result) {
                //alert(result.msg);
                if(result.code == 100){
                    //员工保存成功后
                    //1. 关闭模态框
                    $('#empAddModal').modal('hide');
                    //2. 跳转到显示新添加的员工的这一页(最后一页),每次都显示最后一页数据即可(因为PageHelper插件配置中设置了页码的合理范围)
                    //to_page(9999);页码合理范围:小于0显示第一页,大于总页码显示最后一页
                    to_page(totalRecords);//页码总会小于等于总记录数
                }else{//如果用户绕过前端校验,那么后端校验就起作用了!
                    //后端校验失败后应该显示失败信息
                    //console.log(result);
                    //有哪个字段的错误信息就显示哪个错误
                    if(undefined != result.extend.errorFields.email){
                        //显示邮箱错误信息
                        show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                    }
                    if(undefined != result.extend.errorFields.empName){
                        //显示姓名错误信息
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        });
    });
</script>
</body>
</html>

  

九、实例功能实现——修改

        修改URI:/emp   PUT

  1. 点击编辑
  2. 弹出用户修改的模态框(显示用户信息)
  3. 点击更新,完成用户修改,显示该员工信息修改后的员工列表页

        web.xml中添加过滤器:

    <!--PUT请求过滤器-->
    <filter>
        <filter-name>httpPutFormContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>httpPutFormContentFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

        employee的service和controller:

    /**
     * 按照id查询员工
     * @param id
     * @return
     */
    public Employee getEmp(Integer id) {
        Employee employee = employeeMapper.selectByPrimaryKey(id);
        return employee;
    }

    /**
     * 更新员工
     * @param employee
     */
    public void updateEmp(Employee employee) {
        employeeMapper.updateByPrimaryKeySelective(employee);
    }
    /**
     * 员工更新
     * @param employee
     * @return
     *
     *
     *
     * 如果直接发送ajax=PUT形式的请求
     * 	 封装的数据
     * 	 Employee
     * 	 [empId=50, empName=null, gender=null, email=null, dId=null]
     *
     * 	 问题:
     * 	 请求体中有数据;
     * 	 但是Employee对象封装不上;
     * 	 update tbl_emp  where emp_id = 50;
     *
     *
     * 	 原因:
     * 	 Tomcat:
     * 	  		1、将请求体中的数据,封装一个map。
     * 	  		2、request.getParameter("empName")就会从这个map中取值。
     * 	  		3、SpringMVC封装POJO对象的时候。
     * 	 				会把POJO中每个属性的值,request.getParameter("email");
     * 	  【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;
     *     }
     *
     *     SpringMVC提供了【解决方法】:配置PUT的过滤器,支持直接发送PUT请求并且封装请求体中的数据
     *     1、配置上HttpPutFormContentFilter;
     * 	   2、他的作用;将请求体中的数据解析包装成一个map。
     * 	   3、request被重新包装,request.getParameter()被重写,就会从自己封装的map中取数据
     *
     *
     */
    @ResponseBody
    @RequestMapping(value="/emp/{empId}",method=RequestMethod.PUT)
    public Msg updateEmp(Employee employee, HttpServletRequest request){
        System.out.println("请求体中的值:"+request.getParameter("gender"));
        System.out.println("将要更新的员工数据:"+employee);
        employeeService.updateEmp(employee);
        return Msg.success();
    }

    /**
     * 根据id查询员工
     * @param id
     * @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);
    }

        index.jsp:(上一个的基础上添加了修改的代码)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());

    %>
    <%--web路径:不以/开始的相对路径,找资源以当前资源的路径为基准,容易出现问题
                 以/开始的相对路径,找资源以服务器路径为标准:http://localhost:8080/ssm  需要加上项目名
    --%>
    <%--===========================================================================================================--%>
    <%--引入jQuery  必须在bootstrap.min.js之前引入--%>
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
    <%--引入样式--%>
    <link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
    <%--============================================================================================================--%>

</head>
<body>

<!--员工修改的模态框 Modal ======================================================================================-->
<div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" >update employee</h4>
            </div>
            <div class="modal-body">
                <%--表单--%>
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">empName</label>
                        <div class="col-sm-10">
                            <p class="form-control-static" id="empName_update_static"></p>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" name="email" id="email_update_input"
                                   placeholder="email@163.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">gender</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_update_input" value="M"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_update_input" value="F" checked="checked"> 女
                            </label>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">deptName</label>
                        <div class="col-sm-3">
                            <%--部门提交时,提交id即可--%>
                            <select class="form-control" name="dId" id="dept_update_select"></select>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" id="emp_update_btn">Update</button>
            </div>
        </div>
    </div>
</div>

<!--员工添加的模态框 Modal ======================================================================================-->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">add employee</h4>
            </div>
            <div class="modal-body">
                <%--表单--%>
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">empName</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="empName" id="empName_add_input"
                                   placeholder="empName">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" name="email" id="email_add_input"
                                   placeholder="email@163.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">gender</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_add_input" value="M"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_add_input" value="F" checked="checked"> 女
                            </label>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">deptName</label>
                        <div class="col-sm-3">
                            <%--部门提交时,提交id即可--%>
                            <select class="form-control" name="dId" id="dept_add_select"></select>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" id="emp_save_btn">Save</button>
            </div>
        </div>
    </div>
</div>
<%--==============================================================================================================--%>
<div class="container">
    <%--标题--%>
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <%--按钮--%>
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger">删除</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>email</th>
                    <th>gender</th>
                    <th>departName</th>
                    <th>op</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 totalRecords;//总记录数
    var currentPage;//当前页

    //页面加载完成以后,直接发送一个ajax请求,拿到分页数据=============================================================
    $(function () {
        //第一页数据
        to_page(1);
    });

    //查询某一页的数据
    function to_page(pn) {
        $.ajax({
            url: "${APP_PATH}/emps",
            data: "pn=" + pn,
            type: "GET",
            success: function (result) {
                //console.log(result);
                //1. 解析并显示员工数据
                build_emp_table(result);
                //2. 解析并显示分页信息
                build_page_info(result);
                //3. 解析显示分页条
                build_page_nav(result);
            }
        });
    }

    //1. 解析并显示员工数据========================================================================================
    function build_emp_table(result) {
        //每一次构建表格之前需要先清空table数据
        $("#emps_table tbody").empty();

        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            //index 索引,  ietm 每一项
            // alert(item.empName)
            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);
            /*
            * <button class="btn btn-primary btn-sm"> 编辑
                   <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
              </button>
            * */
            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);
            /*
            * <button class="btn btn-danger btn-sm">删除
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
              </button>
            * */
            var delBtn = $("<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(delBtn);
            //可以链式执行是因为append方法执行完成还是返回原来的元素
            $("<tr></tr>").append(empIdTd)
                .append(empNameTd)
                .append(genderTd)
                .append(emailTd)
                .append(deptNameTd)
                .append(btnTd)
                .appendTo("#emps_table tbody");//appendTo添加到table的tbody中
        })
    }

    //2. 解析并显示分页信息========================================================================================
    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 + "条记录");
        totalRecords = result.extend.pageInfo.total;
        currentPage = result.extend.pageInfo.pageNum;
    }

    //3. 解析显示分页条,点击翻页==================================================================================
    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 {
            //为元素添加点击翻页的事件
            firstPageLi.click(function () {
                to_page(1);
            });
            prePageLi.click(function () {
                to_page(result.extend.pageInfo.pageNum - 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中添加页码提示  1,2,3,4
        $.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();//jQuery没有reset方法,所以转为DOM对象进行重置
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
    }

    //点击新增按钮弹出模态框=======================================================================================
    $("#emp_add_modal_btn").click(function () {
        //每次弹出之前都重置模态框中的表单数据项
        reset_form("#empAddModal form");
        //发送ajax请求,查出部门信息并显示在下拉列表中
        getDepts("#dept_add_select");

        //弹出模态框
        $("#empAddModal").modal({
            backdrop: "static"
        });
    });

    //查出部门信息并显示在下拉列表中================================================================================
    function getDepts(ele) {
        //每一次请求需要先清空下拉列表
        $(ele).empty();

        $.ajax({
            url: "${APP_PATH}/depts",
            type: "GET",
            success: function (result) {
                //console.log(result);
                //{"code":100,"msg":"success","extend":{"depts":[{"deptName":"艺术部","id":1},{"deptName":"开发部","id":2},{"deptName":"测试部","id":3}]}}
                //显示下拉列表在模态框
                $.each(result.extend.depts, function () {
                    //不传参数时可以使用this
                    var optionEle = $("<option></option>").append(this.deptName).attr("value", this.id);
                    optionEle.appendTo(ele);
                });
            }
        });
    }

    //校验模态框中填入数据的合理性==================================================================================
    function validate_add_form() {
        //1、拿到要校验的数据,使用正则表达式
        var empName = $("#empName_add_input").val();
        var regName = /(^[a-zA-Z0-9_-]{2,16}$)|(^[\u2E80-\u9FFF]{2,5}$)/;
        if (!regName.test(empName)) {
            //alert("用户名必须是2-5位中文或者2-16位英文和数字的组合");
            show_validate_msg("#empName_add_input", "error", "用户名必须是2-5位中文或者2-16位英文和数字的组合");
            return false;
        } else {
            show_validate_msg("#empName_add_input", "success", "");
        }


        //2、校验邮箱信息
        var email = $("#email_add_input").val();
        var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)) {
            //alert("邮箱格式不正确");
            //应该清空这个元素之前的样式
            show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
            /* $("#email_add_input").parent().addClass("has-error");
            $("#email_add_input").next("span").text("邮箱格式不正确"); */
            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);
        }
    }

    //发送ajax请求校验用户名是否可用================================================================================
    //给deptName的输入框绑定change事件
    $("#empName_add_input").change(function () {
        //填入的empName
        var name = this.value;
        $.ajax({
            url: "${APP_PATH}/checkname",
            data: "empName=" + name,
            type: "POST",//用GET中文名一致可用???
            success: function (result) {
                if (result.code == 100) {
                    show_validate_msg("#empName_add_input", "success", "用户名可用");
                    $("#emp_save_btn").attr("ajax-va","success");
                } else {
                    show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
                    $("#emp_save_btn").attr("ajax-va","error");
                }
            }
        })
    });

    //给模态框的save按钮绑定单击事件================================================================================
    $("#emp_save_btn").click(function () {
        //模态框中填写的表单数据提交给服务器进行保存

        //1. 对输入的数据进行正则校验
        if (!validate_add_form()) {
            return false;
        }

        //判断ajax请求检验用户名是否可用的返回值
        if($(this).attr("ajax-va")=="error"){
            show_validate_msg("#empName_add_input", "error", "用户名已存在");
            return false;
        }

        //2. 发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: $("#empAddModal form").serialize(),//jquery提供该方法可以序列化整个表单的数据
            success: function (result) {
                //alert(result.msg);
                if(result.code == 100){
                    //员工保存成功后
                    //1. 关闭模态框
                    $('#empAddModal').modal('hide');
                    //2. 跳转到显示新添加的员工的这一页(最后一页),每次都显示最后一页数据即可(因为PageHelper插件配置中设置了页码的合理范围)
                    //to_page(9999);页码合理范围:小于0显示第一页,大于总页码显示最后一页
                    to_page(totalRecords);//页码总会小于等于总记录数
                }else{//如果用户绕过前端校验,那么后端校验就起作用了!
                    //后端校验失败后应该显示失败信息
                    //console.log(result);
                    //有哪个字段的错误信息就显示哪个错误
                    if(undefined != result.extend.errorFields.email){
                        //显示邮箱错误信息
                        show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                    }
                    if(undefined != result.extend.errorFields.empName){
                        //显示姓名错误信息
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        });
    });

    //点击编辑按钮弹出模态框=======================================================================================
    //这样写是在按钮创建之前就绑定了click(按钮是ajax请求拿到的),所以绑定不上
    /*$(".edit_btn").click(function () {
        alert("edit");
    });*/
    //方法1. 可以在创建按钮的时候绑定单击事件
    //方法2. jQuery的live方法高版本删除了,可以使用on替代【推荐】
    $(document).on("click",".edit_btn",function () {
        //alert("edit");
        //1、查出部门信息,并显示部门列表
        getDepts("#empUpdateModal select");
        //2、查出员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));

        //3、把员工的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){
                //console.log(result);
                var empData = result.extend.emp;
                $("#empName_update_static").text(empData.empName);
                $("#email_update_input").val(empData.email);
                $("#empUpdateModal input[name=gender]").val([empData.gender]);
                $("#empUpdateModal select").val([empData.dId]);
            }
        });
    }

    //点击更新按钮Update,更新员工信息
    $("#emp_update_btn").click(function(){
        //验证邮箱是否合法
        //1、校验邮箱信息
        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", "");
        }

        //2、发送ajax请求保存更新的员工数据
        $.ajax({
            url:"${APP_PATH}/emp/"+$(this).attr("edit-id"),
            type:"PUT",
            data:$("#empUpdateModal form").serialize(),//序列化该表单
            success:function(result){
                //alert(result.msg);
                //1、关闭对话框
                $("#empUpdateModal").modal("hide");
                //2、回到本页面
                to_page(currentPage);
            }
        });
    });

</script>
</body>
</html>

  

十、实例功能实现——删除

       删除URI:/emp/{ids}   DETETE

       employee的service和controller:

    /**
     * 根据id删除员工
     * @param id
     */
    public void deleteEmpById(Integer id) {
        employeeMapper.deleteByPrimaryKey(id);
    }

    /**
     * 批量删除
     * @param ids
     */
    public void deleteBatch(List<Integer> ids) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        //拼接条件后  delete from xxx where emp_id in (1,2,3)
        criteria.andEmpIdIn(ids);
        employeeMapper.deleteByExample(example);
    }
    /**
     * 单个删除/批量删除 二合一
     * 批量删除:1-2-3  多个id用-隔开
     * 单个删除: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[] str_ids = ids.split("-");
            //组装id的集合
            for (String string : str_ids) {
                del_ids.add(Integer.parseInt(string));
            }
            employeeService.deleteBatch(del_ids);
        }else{//单个删除
            Integer id = Integer.parseInt(ids);
            employeeService.deleteEmpById(id);
        }
        return Msg.success();
    }

        index.jsp:(最终版!

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());

    %>
    <%--web路径:不以/开始的相对路径,找资源以当前资源的路径为基准,容易出现问题
                 以/开始的相对路径,找资源以服务器路径为标准:http://localhost:8080/ssm  需要加上项目名
    --%>
    <%--===========================================================================================================--%>
    <%--引入jQuery  必须在bootstrap.min.js之前引入--%>
    <script type="text/javascript" src="${APP_PATH}/static/js/jquery-1.12.4.min.js"></script>
    <%--引入样式--%>
    <link href="${APP_PATH}/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="${APP_PATH}/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
    <%--============================================================================================================--%>

</head>
<body>

<!--员工修改的模态框 Modal ======================================================================================-->
<div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" >update employee</h4>
            </div>
            <div class="modal-body">
                <%--表单--%>
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">empName</label>
                        <div class="col-sm-10">
                            <p class="form-control-static" id="empName_update_static"></p>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" name="email" id="email_update_input"
                                   placeholder="email@163.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">gender</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_update_input" value="M"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_update_input" value="F" checked="checked"> 女
                            </label>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">deptName</label>
                        <div class="col-sm-3">
                            <%--部门提交时,提交id即可--%>
                            <select class="form-control" name="dId" id="dept_update_select"></select>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" id="emp_update_btn">Update</button>
            </div>
        </div>
    </div>
</div>

<!--员工添加的模态框 Modal ======================================================================================-->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">add employee</h4>
            </div>
            <div class="modal-body">
                <%--表单--%>
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">empName</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="empName" id="empName_add_input"
                                   placeholder="empName">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" class="form-control" name="email" id="email_add_input"
                                   placeholder="email@163.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">gender</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_add_input" value="M"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_add_input" value="F" checked="checked"> 女
                            </label>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">deptName</label>
                        <div class="col-sm-3">
                            <%--部门提交时,提交id即可--%>
                            <select class="form-control" name="dId" id="dept_add_select"></select>
                        </div>
                    </div>

                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" id="emp_save_btn">Save</button>
            </div>
        </div>
    </div>
</div>
<%--==============================================================================================================--%>
<div class="container">
    <%--标题--%>
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <%--按钮--%>
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger" id="emp_delete_all_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>email</th>
                    <th>gender</th>
                    <th>departName</th>
                    <th>op</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 totalRecords;//总记录数
    var currentPage;//当前页

    //页面加载完成以后,直接发送一个ajax请求,拿到分页数据=============================================================
    $(function () {
        //第一页数据
        to_page(1);
    });

    //查询某一页的数据
    function to_page(pn) {
        //每次加载某一个数据将全选框设置为不选的状态
        $("#check_all").prop("checked",false);

        $.ajax({
            url: "${APP_PATH}/emps",
            data: "pn=" + pn,
            type: "GET",
            success: function (result) {
                //console.log(result);
                //1. 解析并显示员工数据
                build_emp_table(result);
                //2. 解析并显示分页信息
                build_page_info(result);
                //3. 解析显示分页条
                build_page_nav(result);
            }
        });
    }

    //1. 解析并显示员工数据========================================================================================
    function build_emp_table(result) {
        //每一次构建表格之前需要先清空table数据
        $("#emps_table tbody").empty();

        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            //index 索引,  ietm 每一项
            // alert(item.empName)
            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);
            /*
            * <button class="btn btn-primary btn-sm"> 编辑
                   <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
              </button>
            * */
            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);
            /*
            * <button class="btn btn-danger btn-sm">删除
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
              </button>
            * */
            var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm delete_btn")
                .append($("<span></span>").addClass("glyphicon glyphicon-trash"))
                .append("删除");
            //为删除按钮添加自定义的一个属性,方便后面根据id删除该员工的信息
            delBtn.attr("del-id",item.empId);
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
            //可以链式执行是因为append方法执行完成还是返回原来的元素
            $("<tr></tr>").append(checkBoxTd)
                .append(empIdTd)
                .append(empNameTd)
                .append(genderTd)
                .append(emailTd)
                .append(deptNameTd)
                .append(btnTd)
                .appendTo("#emps_table tbody");//appendTo添加到table的tbody中
        })
    }

    //2. 解析并显示分页信息========================================================================================
    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 + "条记录");
        totalRecords = result.extend.pageInfo.total;
        currentPage = result.extend.pageInfo.pageNum;
    }

    //3. 解析显示分页条,点击翻页==================================================================================
    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 {
            //为元素添加点击翻页的事件
            firstPageLi.click(function () {
                to_page(1);
            });
            prePageLi.click(function () {
                to_page(result.extend.pageInfo.pageNum - 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中添加页码提示  1,2,3,4
        $.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();//jQuery没有reset方法,所以转为DOM对象进行重置
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
    }

    //点击新增按钮弹出模态框=======================================================================================
    $("#emp_add_modal_btn").click(function () {
        //每次弹出之前都重置模态框中的表单数据项
        reset_form("#empAddModal form");
        //发送ajax请求,查出部门信息并显示在下拉列表中
        getDepts("#dept_add_select");

        //弹出模态框
        $("#empAddModal").modal({
            backdrop: "static"
        });
    });

    //查出部门信息并显示在下拉列表中================================================================================
    function getDepts(ele) {
        //每一次请求需要先清空下拉列表
        $(ele).empty();

        $.ajax({
            url: "${APP_PATH}/depts",
            type: "GET",
            success: function (result) {
                //console.log(result);
                //{"code":100,"msg":"success","extend":{"depts":[{"deptName":"艺术部","id":1},{"deptName":"开发部","id":2},{"deptName":"测试部","id":3}]}}
                //显示下拉列表在模态框
                $.each(result.extend.depts, function () {
                    //不传参数时可以使用this
                    var optionEle = $("<option></option>").append(this.deptName).attr("value", this.id);
                    optionEle.appendTo(ele);
                });
            }
        });
    }

    //校验模态框中填入数据的合理性==================================================================================
    function validate_add_form() {
        //1、拿到要校验的数据,使用正则表达式
        var empName = $("#empName_add_input").val();
        var regName = /(^[a-zA-Z0-9_-]{2,16}$)|(^[\u2E80-\u9FFF]{2,5}$)/;
        if (!regName.test(empName)) {
            //alert("用户名必须是2-5位中文或者2-16位英文和数字的组合");
            show_validate_msg("#empName_add_input", "error", "用户名必须是2-5位中文或者2-16位英文和数字的组合");
            return false;
        } else {
            show_validate_msg("#empName_add_input", "success", "");
        }


        //2、校验邮箱信息
        var email = $("#email_add_input").val();
        var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)) {
            //alert("邮箱格式不正确");
            //应该清空这个元素之前的样式
            show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
            /* $("#email_add_input").parent().addClass("has-error");
            $("#email_add_input").next("span").text("邮箱格式不正确"); */
            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);
        }
    }

    //发送ajax请求校验用户名是否可用================================================================================
    //给deptName的输入框绑定change事件
    $("#empName_add_input").change(function () {
        //填入的empName
        var name = this.value;
        $.ajax({
            url: "${APP_PATH}/checkname",
            data: "empName=" + name,
            type: "POST",//用GET中文名一致可用???
            success: function (result) {
                if (result.code == 100) {
                    show_validate_msg("#empName_add_input", "success", "用户名可用");
                    $("#emp_save_btn").attr("ajax-va","success");
                } else {
                    show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
                    $("#emp_save_btn").attr("ajax-va","error");
                }
            }
        })
    });

    //给模态框的save按钮绑定单击事件================================================================================
    $("#emp_save_btn").click(function () {
        //模态框中填写的表单数据提交给服务器进行保存

        //1. 对输入的数据进行正则校验
        if (!validate_add_form()) {
            return false;
        }

        //判断ajax请求检验用户名是否可用的返回值
        if($(this).attr("ajax-va")=="error"){
            show_validate_msg("#empName_add_input", "error", "用户名已存在");
            return false;
        }

        //2. 发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: $("#empAddModal form").serialize(),//jquery提供该方法可以序列化整个表单的数据
            success: function (result) {
                //alert(result.msg);
                if(result.code == 100){
                    //员工保存成功后
                    //1. 关闭模态框
                    $('#empAddModal').modal('hide');
                    //2. 跳转到显示新添加的员工的这一页(最后一页),每次都显示最后一页数据即可(因为PageHelper插件配置中设置了页码的合理范围)
                    //to_page(9999);页码合理范围:小于0显示第一页,大于总页码显示最后一页
                    to_page(totalRecords);//页码总会小于等于总记录数
                }else{//如果用户绕过前端校验,那么后端校验就起作用了!
                    //后端校验失败后应该显示失败信息
                    //console.log(result);
                    //有哪个字段的错误信息就显示哪个错误
                    if(undefined != result.extend.errorFields.email){
                        //显示邮箱错误信息
                        show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                    }
                    if(undefined != result.extend.errorFields.empName){
                        //显示姓名错误信息
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        });
    });

    //点击【编辑】按钮弹出模态框=======================================================================================
    //这样写是在按钮创建之前就绑定了click(按钮是ajax请求拿到的),所以绑定不上
    /*$(".edit_btn").click(function () {
        alert("edit");
    });*/
    //方法1. 可以在创建按钮的时候绑定单击事件
    //方法2. jQuery的live方法高版本删除了,可以使用on替代【推荐】
    $(document).on("click",".edit_btn",function () {
        //alert("edit");
        //1、查出部门信息,并显示部门列表
        getDepts("#empUpdateModal select");
        //2、查出员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));

        //3、把员工的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){
                //console.log(result);
                var empData = result.extend.emp;
                $("#empName_update_static").text(empData.empName);
                $("#email_update_input").val(empData.email);
                $("#empUpdateModal input[name=gender]").val([empData.gender]);
                $("#empUpdateModal select").val([empData.dId]);
            }
        });
    }

    //点击更新按钮Update,更新员工信息
    $("#emp_update_btn").click(function(){
        //验证邮箱是否合法
        //1、校验邮箱信息
        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", "");
        }

        //2、发送ajax请求保存更新的员工数据
        $.ajax({
            url:"${APP_PATH}/emp/"+$(this).attr("edit-id"),
            type:"PUT",
            data:$("#empUpdateModal form").serialize(),//序列化该表单
            success:function(result){
                //alert(result.msg);
                //1、关闭对话框
                $("#empUpdateModal").modal("hide");
                //2、回到本页面
                to_page(currentPage);
            }
        });
    });
    //点击【编辑】按钮删除单个用户信息=================================================================================
    $(document).on("click",".delete_btn",function(){
        //1、弹出是否确认删除对话框
        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获取checked的值是undefined;
        //这些dom原生的属性:attr获取自定义属性的值;
        //                  prop修改和读取dom原生属性的值
        $(".check_item").prop("checked",$(this).prop("checked"));
    });
    //给每一个员工信息前的单选框check_item绑定单击事件=================================================================
    //这些单选框都是后来创建的,所以用on方法
    $(document).on("click",".check_item",function(){
        //判断当前选择中的元素是否等于所有的单选框(除了全选)的个数
        var flag = $(".check_item:checked").length==$(".check_item").length;
        $("#check_all").prop("checked",flag);
    });

    //批量删除======================================================================================================
    $("#emp_delete_all_btn").click(function(){

        var empNames = "";
        var del_idstr = "";
        $.each($(".check_item:checked"),function(){
            //this代表当前遍历的item
            empNames += $(this).parents("tr").find("td:eq(2)").text()+",";
            //组装员工id字符串
            del_idstr += $(this).parents("tr").find("td:eq(1)").text()+"-";
        });
        //去除empNames多余的,
        empNames = empNames.substring(0, empNames.length-1);
        //去除删除的id多余的-
        del_idstr = del_idstr.substring(0, del_idstr.length-1);
        //未选中时,删除按钮点击无反应
        if(del_idstr.length == 0){
            return false;
        }
        if(confirm("确认删除【"+empNames+"】吗?")){
            //发送ajax请求删除
            $.ajax({
                url:"${APP_PATH}/emp/"+del_idstr,
                type:"DELETE",
                success:function(result){
                    alert(result.msg);
                    //回到当前页面
                    to_page(currentPage);
                }
            });
        }
    });
</script>
</body>
</html>

十一、总结

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值