基于SSM框架的CRUD小项目,外加JSR303,使用Maven搭建工程,前端使用Jquery对Ajax的封装进行异步请求

建议先学

  1. 五万字的Spring5学习笔记,带你熟悉运用Spring5
  2. 四万多字的SpringMVC学习总结,带你领略不一样的SpringMVC
  3. 怎么请求数据库的数据?这套四万多字的Mybatis学习笔记给你答案,只做入门,不做深层次分析

概要

在这里插入图片描述

  • 我们的目标是整个三大框架,来做一个简单的增删改查系统。
  • 该系统有以下几个要点
    • 该系统在网页中显示,数据要列出在网页上。
    • 系统提供增删改查的选项功能。
    • 系统提供分页的功能。
    • 系统提供数据检测的功能,检查增加的数据是否符合现实规则。

创建工程

  • 创建一个Maven工程,利用webapp模块。
  • 创建完毕后,里面是没有正常的Maven工程的包的,比如java test包之类,我们需要根据正常模板导入,但webapp模块不要删除。

导入依赖

  • 创建模块后,就要导入依赖,在pom.xml 中我们要配置基本的jar。

    • spring springMvc mybatis spring-mybatis
    • jstl servlet mysql-connnector durid 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.hyb</groupId>
      <artifactId>SSM_CRUD</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
    
      <dependencies>
        <!--测试包-->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
    
        <!--配置ssm框架jar-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.3.9</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aspects</artifactId>
          <version>5.3.9</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.3.9</version>
        </dependency>
    
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.7</version>
        </dependency>
    
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>2.0.6</version>
        </dependency>
    
        <!--数据库连接池和驱动-->
    
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.22</version>
        </dependency>
    
    
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.26</version>
        </dependency>
    
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
          <version>1.1.2</version>
        </dependency>
    
    
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.1</version>
          <scope>provided</scope>
        </dependency>
    
      </dependencies>
    
    </project>
    

    注意,有时候你导入的依赖刷新Maven的时候可能还是会报红,这可能是镜像网站网络的问题,可以上网查阅更换aliyun的镜像网站。一般的解决办法还是在本地的镜像仓库的jar的垃圾文件删除,重新刷新一遍,若还是不行,就更换不同版本的jar。

  • 写完pom.xml文件后,我们要进行一些web的文件导入,这里我们使用前端框架Bootstrap 和JQuery 来进行。前面的框架主要用来解决css,后面的主要用来解决js。我们可以在index.jsp中看看如何导入

    <%--
      Created by IntelliJ IDEA.
      User: 黄渝斌
      Date: 2021/9/11
      Time: 10:36
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>index.jsp</title>
        <!-- Bootstrap -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
        <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
        <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
        <script type="text/javascript" href="js/jquery-3.5.1.js"></script>
    </head>
    <body>
        <button type="button" class="btn btn-default">这是一个按钮</button>
    </body>
    </html>
    

    注意,这里的Bootstrap 框架由于支持cdn,所以不用下载包,而JQuery则需要下载。

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>



  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>


  <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>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>


  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

注意,这个xml中,注意标签的优先级。

dispatcherServlet-servlet.xml

  • 该配置文件是SpringMVC的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--配置SpringMVC-->
    <context:component-scan base-package="com.hyb.crud" use-default-filters="false">
        <!--只是扫描控制器-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--两个标准配置-->
        <!--将SpringMVC不能处理的请求交给Tomcat-->
    <mvc:default-servlet-handler/>
        <!--加载注解驱动,支持JSR303校验,快捷ajax请求-->
    <mvc:annotation-driven/>
</beans>

applicationContext.xml

  • 该配置是Spring的配置文件和Spring和Mybatis整合的配置文件
<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">

    <context:component-scan base-package="com.hyb.crud">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <context:property-placeholder location="classpath:jdbcSql.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!-- 事务 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启基于注解的事务-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

    <!--整合mybatis

    -->
    <!--创建SqlSessionFactory 对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- MyBatis的配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- MyBatis的SQL映射文件 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
        <property name="typeAliasesPackage" value="com.hyb.myBatis"></property>
    </bean>
    <mybatis-spring:scan base-package="com.hyb.crud.dao"/>
</beans>

mybatis-config.xml

  • 该配置是mybatis配置文件
<?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.hyb.crud.bean"/>
    </typeAliases>

</configuration>

创建表

  • 创建员工表和部门表,两个表都有各自的id,员工表的外键属于部门表的id

逆向工程创建ssm项目

  • 首先导入逆向工程的包。

  • 我们先创建应有的包名,然后可以用逆向工程创建ssm项目

  • 首先,我们得在工程目录下,创建一个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>
    <!--    <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />-->
    
        <context id="DB2Tables" targetRuntime="MyBatis3">
            <!--阻止生成注释-->
            <commentGenerator>
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
    
            <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/hyb?serverTimezone=UTC"
                            userId="root"
                            password="15717747056HYB">
            </jdbcConnection>
    
            <javaTypeResolver >
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
    
            <javaModelGenerator targetPackage="com.hyb.crud.bean"
                                targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
    
            <sqlMapGenerator targetPackage="mapper"  targetProject=".\src\main\resources">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>
    
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.hyb.crud.dao"
                                 targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
    
            <table tableName="employee" domainObjectName="Employee"></table>
            <table tableName="department_1" domainObjectName="Department"></table>
        </context>
    </generatorConfiguration>
    
  • 然后我们编写测试类,来测试,一次测试就可以创建出一个逆向工程

    @Test
    public void testReserval() 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);
    }
    
  • 执行,逆向工程创建完毕,完成所有基本代码实现。

修改逆向工程

  • 在创建好的逆向工程中,我们会发现,在Employee的javabean中,是没有属性Department的,但是我们表里面是有这个属性的主键的,也就是Employee表里的外键。而且,我们在查询的时候,我们希望,通过员工表里的外键可以查出该部门信息。但是我们生成的sql映射文件里,是没有改sql语句执行,所以我们要修改。

  • 首先,我们要修改Employee 类的属性,为其加上get set方法。

    private Department department;
    
  • 之后,我们要在Employee 的dao的mapper接口,写出该带有部门信息的查询方法

    List<Employee> selectByExampleWithDept(EmployeeExample example);
    Employee selectByPrimaryKeyWithDept(Integer empId);
    
  • 写完后,要写其对应的sql语句,由于该sql映射文件是动态sql,所以我们可以仿照没有部分信息的查询方法来写。

    首先写我们resultMap

    <resultMap id="WithDeptResultMap" type="com.hyb.crud.bean.Employee">
      <id column="emp_id" jdbcType="INTEGER" property="empId" />
      <result column="emp_name" jdbcType="VARCHAR" property="empName" />
      <result column="gender" jdbcType="VARCHAR" property="gender" />
      <result column="email" jdbcType="VARCHAR" property="email" />
      <result column="dept_id" jdbcType="INTEGER" property="deptId" />
      <association property="department" javaType="com.hyb.crud.bean.Department">
        <id column="dept_id" property="deptId"/>
        <result column="dept_name" property="deptName"/>
      </association>
    </resultMap>
    

    注意,该resultMa不能在原来的resultMap中写,因为原来的resultMap是没有关联Department这个属性的,其sql语句也没有。我们写这个resultMap是为写我们带有部门信息的查询方法。

    下面,我们可以写这两个对应的动态sql语句

    <sql id="WithDept_Column_List">
      emp_id, emp_name, gender, email, employee.dept_id, department_1.dept_name
    </sql>
    
    <select id="selectByExampleWithDept" parameterType="com.hyb.crud.bean.EmployeeExample" resultMap="WithDeptResultMap">
      select
      <if test="distinct">
        distinct
      </if>
      <include refid="WithDept_Column_List" />
      from employee,deaprtment_1
      where employee.dept_id=department_1.dept_id
      <if test="_parameter != null">
        <include refid="Example_Where_Clause" />
      </if>
      <if test="orderByClause != null">
        order by ${orderByClause}
      </if>
    </select>
    
    <select id="selectByPrimaryKeyWithDept" parameterType="java.lang.Integer" resultMap="WithDeptResultMap">
      select
      <include refid="WithDept_Column_List" />
      from employee,department_1
      where emp_id = #{empId,jdbcType=INTEGER}
    </select>
    

测试逆向工程

  • 我们首先来测试DepartmentMapper ,而且,我们要用Spring-test的测试框架来测试

  • 首先,我们新建一个test测试类,然后新建一个带有Test注解的test测试方法,之后,我们在pom.xml中加入spring-test框架。请上镜像网站搜索。

  • 然后我们在测试类上,加上以下两个注解

    //使用Spring的单元测试模块
    @RunWith(SpringJUnit4ClassRunner.class)
    //解析的文件地址
    @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
    

    注意,如果没有这两个注解,而你又在pom.xml文件中加入了jar,是因为你没有刷新Maven

    加入这两个注解后,我们可以自动注入DepartmentMapper了,然后尝试是否可以获取departmentMapper对象

    //    先测试DepartmentMapper
        @Autowired
        DepartmentMapper departmentMapper;
    
        @Test
        public void testReserval_1(){
            System.out.println(departmentMapper);
        }
    

    注意,这里的注入在IDEA中可能会标红,这不是错误的原因,不要管它。测试后,若是报错,会经常报spring-test junit 需要4.12版本以上。

  • 获取对象成功后,说明我们的配置文件基本完成和没有错误,可以进行真实测试,我们可以进行简单的增删改查测试

    //        departmentMapper.insertSelective(new Department(null,"开发部"));
    
    //        Department department = departmentMapper.selectByPrimaryKey(1);
    //        System.out.println(department);
    
    //        DepartmentExample e = new DepartmentExample();
    //        e.createCriteria().andDeptNameLike("%部");
    //        List<Department> departments = departmentMapper.selectByExample(e);
    //        System.out.println(departments);
    
    //        DepartmentExample e = new DepartmentExample();
    //        e.createCriteria().andDeptNameLike("%部");
    //        departmentMapper.updateByExample(new Department(1,"高级开发部"),e);
    //        System.out.println(departmentMapper.selectByPrimaryKey(1));
    
    //        DepartmentExample e = new DepartmentExample();
    //        e.createCriteria().andDeptNameLike("%高级%");
    //        departmentMapper.deleteByExample(e);
    

首页列表数据

编写Controller

  • 我们都知道,服务器启动的时候跳转的默认都是index.jsp,为了方便管理,我们可以在index.jsp中进行页面跳转。

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

    注意,这个页面只保留这两项,其他都删除。

  • 可以看到,我们跳转到emps 页面,但这是ssm框架,我们需要处理数据,所以这里跳转的是Controller,我们可以创建一个Controller,然后编写一个方法,将里面数据写全。

    package com.hyb.crud.controller;
    
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import com.hyb.crud.bean.Employee;
    import com.hyb.crud.service.EmployeeService;
    import org.apache.ibatis.annotations.Param;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.List;
    
    @Controller
    public class EmployeeController {
    
        @Autowired
        EmployeeService employeeService;
    
        @RequestMapping("/emps")
        public String getEmps(@RequestParam(value = "page",defaultValue = "1") Integer page, Model model){
    
    //        从第几页开始查,每页有几条数据
            PageHelper.startPage(page,5);
            List<Employee> emps = employeeService.getAll();
    //        交给PageInfo,连续显示5页
            PageInfo<Employee> employeePageInfo = new PageInfo<Employee>(emps,5);
            model.addAttribute("pageInfo",employeePageInfo);
            return "list";
        }
    }
    

    这里,只要我们将Service层写好就可以了。在利用分页框架的时候,记得先将PageHelper的jar导入。

  • 完成后,进行测试,这里的测试,我们还是用spring-test的测试方法。

    package com.hyb.crud.test;
    
    import com.github.pagehelper.PageInfo;
    import com.hyb.crud.bean.Employee;
    import com.sun.xml.internal.ws.api.client.WSPortInfo;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mock.web.MockHttpServletRequest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.MockMvcBuilder;
    import org.springframework.test.web.servlet.MvcResult;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    import java.util.List;
    
    //使用Spring的单元测试模块
    @RunWith(SpringJUnit4ClassRunner.class)
    //装配SpringMVC的
    @WebAppConfiguration
    //解析的文件地址
    @ContextConfiguration(locations = {"classpath:applicationContext.xml","file:src/main/webapp/WEB-INF/dispatcherServlet-servlet.xml"})
    public class MVCTest {
    
    //    装配SpringMVC
        @Autowired
        WebApplicationContext context;
    //    虚拟mvc请求
        MockMvc mockMvc;
    
        @Before
        public void initMockMvc(){
            mockMvc= MockMvcBuilders.webAppContextSetup(context).build();
        }
    
        @Test
        public void testPage() throws Exception {
            MvcResult page = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("page", "1")).andReturn();
    //        取出pageINfo
            MockHttpServletRequest request = page.getRequest();
            PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
            System.out.println(pageInfo);
        }
    }
    

编写jsp页面

  • 因为这里我们是通过index请求到Controller然后到list页面,所以,我们接下来就利用BootStrap 框架来编写该jsp页面。然后读取出数据。

    <%--
      Created by IntelliJ IDEA.
      User: 黄渝斌
      Date: 2021/9/12
      Time: 12:31
      To change this template use File | Settings | File Templates.
    --%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page isELIgnored="false" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@include file="/common/base.jsp"%>
    <html>
    <head>
        <title>员工列表</title>
        <%@include file="/common/link.jsp"%>
    </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-success">
                        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
                    </button>
                    <button class="btn btn-warning">
                        <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除
                    </button>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12">
                    <table class="table table-hover">
                        <tr>
                            <th>编号</th>
                            <th>姓名</th>
                            <th>性别</th>
                            <th>邮箱</th>
                            <th>部门</th>
                            <th >操作</th>
                        </tr>
                        <c:forEach items="${pageInfo.list}" var="emps">
                        <tr>
                            <th>${emps.empId}</th>
                            <th>${emps.empName}</th>
                            <th>${emps.gender=="1"?"男":"女"}</th>
                            <th>${emps.email}</th>
                            <th>${emps.department.deptName}</th>
                            <th>
                                <button class="btn btn-success">
                                    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> 修改
                                </button>
                                <button class="btn btn-warning">
                                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> 删除
                                </button>
                            </th>
                        </tr>
                        </c:forEach>
                    </table>
                </div>
            </div>
            <%@include file="/common/page.jsp"%>
        </div>
    </body>
    </html>
    
  • 从上面这个jsp页面可以知道,我们有几个jsp页面的抽取,首先是链接的抽取,我们可以将动态获取服务器地址的方法写在一个jsp页面中

    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%
        /*改路径是以/开始没有以/结束*/
        pageContext.setAttribute("basePath",request.getContextPath());
    %>
    

    这个jsp页面是共用的。

  • 由于链接JQuery的文件和链接BootStrap框架的都需要,我们也可以抽取在一个jsp页面中

    <%--
      Created by IntelliJ IDEA.
      User: 黄渝斌
      Date: 2021/9/12
      Time: 12:29
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <script type="text/javascript" href="${basePath}/js/jquery-3.5.1.js"></script>
    <!-- Bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
    <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    
  • 然后还有分页功能,我们也可以抽取出在一个jsp页面中

    <%--
      Created by IntelliJ IDEA.
      User: 黄渝斌
      Date: 2021/9/12
      Time: 15:04
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <div class="row">
        <div class="col-md-6">
            当前${pageInfo.pageNum}页,总${pageInfo.pages}页,总${pageInfo.total}记录
        </div>
        <div class="col-md-6">
            <nav aria-label="Page navigation">
                <ul class="pagination">
                    <c:if test="${!pageInfo.isFirstPage}">
                        <li>
                            <a href="${basePath}/emps?page=1">首页</a>
                        </li>
                    </c:if>
    
                    <c:if test="${pageInfo.hasPreviousPage}">
                        <li>
                            <a href="${basePath}/emps?page=${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>${page_num}</a></li>
                        </c:if>
                        <c:if test="${page_num!=pageInfo.pageNum}">
                            <li><a href="${basePath}/emps?page=${page_num}">${page_num}</a></li>
                        </c:if>
                    </c:forEach>
    
                    <c:if test="${pageInfo.hasNextPage}">
                        <li>
                            <a href="${basePath}/emps?page=${pageInfo.pageNum+1}" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                    </c:if>
    
                    <c:if test="${!pageInfo.isLastPage}">
                        <li>
                            <a href="${basePath}/emps?page=${pageInfo.pages}">末页</a>
                        </li>
                    </c:if>
    
                </ul>
            </nav>
        </div>
    </div>
    
  • 注意,在这里我们需要导入Jsp的jar和JSl中taglib 两个重要jar包

升级查询技术

  • 上面的首页列表数据,我们是利用了index.jsp发送请求到Controller ,然后再请求到具体页面,但这只适合于浏览器和客户进行交互。

  • 要先做到手机端和电脑端都能和客户交互,可以使用Ajax请求的方式查询数据。

  • 首先,导入Json jar包。

    com.fasterxml.jackson.core jackson-databind 2.12.3
  • 然后在Controller中,我们可以直接返回一个PageInfo的数据,就会转换为JSON

        @RequestMapping("/emps")
        /*下面的注解代表返回一个JSON*/
        @ResponseBody
        public PageInfo<Employee> getEmpsByAjax(@RequestParam(value = "page",defaultValue = "1") Integer page){
    //        从第几页开始查,每页有几条数据
            PageHelper.startPage(page,5);
            List<Employee> emps = employeeService.getAll();
    //        交给PageInfo,连续显示5页
            return new PageInfo<Employee>(emps,5);
        }
    
  • 但是这个JSON不是通用的,因为我们返回这个是PageInfo,那若是别的请求返回的不是PageInfo呢?而且,java行为大致都是一样的,所以我们可以做一个通用的返回javabean

    package com.hyb.crud.bean;
    
    import sun.applet.resources.MsgAppletViewer;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Msg {
    //    状态码,
        private String code;
        private String msg;
    
    //    用Map保存数据
        private Map<String,Object> map=new HashMap<String, Object>();
    
        /*
        * 报错PageInfo的数据,做链式方法
        * */
        public Msg add(String s,Object v){
            this.map.put(s,v);
            return this;
        }
    
        public static Msg fail(){
            Msg msg = new Msg();
            msg.setCode("100");
            msg.setMsg("处理失败!");
            return msg;
        }
    
        public static Msg success(){
            Msg msg = new Msg();
            msg.setCode("200");
            msg.setMsg("处理成功!");
            return msg;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public Map<String, Object> getMap() {
            return map;
        }
    
        public void setMap(Map<String, Object> map) {
            this.map = map;
        }
    }
    

    这个javabean就具备了响应警告,和数据保存的功能,这两个功能,所有请求都需要用的。

  • 做出了公共返回类型,我们就得修改我们方法

        public Msg getEmpsByAjax(@RequestParam(value = "page",defaultValue = "1") Integer page){
    //        从第几页开始查,每页有几条数据
            PageHelper.startPage(page,5);
            List<Employee> emps = employeeService.getAll();
    //        交给PageInfo,连续显示5页
            return Msg.success().add("pageInfo",new PageInfo<Employee>(emps,5));
        }
    

    这里add方法不是static的,但是前面success方法是静态,调用该方法后就获取到一个Msg对应,所以可以调用该非静态方法。不仅如此,该add方法是链式方法,即add后面还可以调用add,若有其他数据,就可以添加新的数据。

  • 于是乎,我们就不需要list.jsp了,我们只在index.jsp做ajax请求,并将数据反馈在这个页面上。

    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page isELIgnored="false" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@include file="/common/base.jsp"%>
    <html>
    <head>
        <title>员工列表</title>
        <%@include file="/common/link.jsp"%>
        <script type="text/javascript" >
            $(function () {
                to_page(1);
            })
            function to_page(pn) {
                $.ajax({
                    url:"${basePath}/emps",
                    data:"page="+pn,
                    type:"GET",
                    success:function (data) {
                        build_list(data);
                        build_page_count(data);
                        build_page(data);
                    }
                })
            }
    
            function build_list(data) {
                //清空表格里的数据
                $("#emps_table tbody").empty();
                var emps=data.map.pageInfo.list;
                $.each(emps,function (index,item) {
                    // alert(item.empName);
                    var empIdTd=$("<td></td>").append(item.empId);
                    var empNameTd=$("<td></td>").append(item.empName);
                    var empGenderTd=$("<td></td>").append(item.gender=="1"?"男":"女");
                    var empEmailTd=$("<td></td>").append(item.email);
                    var empDeptTd=$("<td></td>").append(item.department.deptName);
                    var button_1=$("<button></button>").addClass("btn btn-success")
                                    .append($("<span></span>")).addClass("glyphicon glyphicon-pencil")
                                    .append("编辑");
                    var button_2=$("<button></button>").addClass("btn btn-warning")
                                    .append($("<span></span>")).addClass("glyphicon glyphicon-trash")
                                    .append("删除")
                    var button_1_2=$("<td></td>").append(button_1).append(" ").append(button_2);
                    $("<tr></tr>").append(empIdTd).append(empNameTd)
                                    .append(empGenderTd).append(empEmailTd)
                                    .append(empDeptTd).append(button_1_2)
                                    .appendTo("#emps_table tbody");
                })
            }
            function build_page_count(data) {
                $("#page_count").empty();
                var page=data.map.pageInfo;
                $("#page_count").append("当前"+page.pageNum+"页,总"+page.pages+"页,总"+
                        page.total+"记录");
    
            }
            function build_page(data) {
                $("#page").empty();
                var ul=$("<ul></ul>").addClass("pagination");
    
                //首页
                var firstPage=$("<li></li>").append($("<a></a>").append("首页").attr("href","#"));
                firstPage.click(function () {
                    to_page(1);
                });
    
                //上一页
                var upPage=$("<li></li>").append($("<a></a>").append("<span></span>").append("&laquo;").attr("href","#"));
                upPage.click(function () {
                    to_page(data.map.pageInfo.pageNum-1);
                });
    
                if(!data.map.pageInfo.hasPreviousPage){
                    firstPage.addClass("disabled");
                    upPage.addClass("disabled");
                }
                //首页,前一页
                ul.append(firstPage).append(upPage);
    
                $.each(data.map.pageInfo.navigatepageNums,function (index,itme) {
                    var numi=$("<li></li>").append($("<a></a>").append(itme).attr("href","#"));
                    numi.click(function () {
                        to_page(itme);
                    });
    
                    if (data.map.pageInfo.pageNum===itme){
                        numi.addClass("active");
                    }
                //    当前页
                    ul.append(numi);
                })
                //下一页
                var downPage=$("<li></li>").append($("<a></a>").append("<span></span>").append("&raquo;").attr("href","#"));
                downPage.click(function () {
                    to_page(data.map.pageInfo.pageNum+1);
                });
    
                //末页
                var endPage=$("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
                endPage.click(function () {
                    to_page(data.map.pageInfo.pages);
                });
    
                if(!data.map.pageInfo.hasNextPage){
                    endPage.addClass("disabled");
                    downPage.addClass("disabled");
                }
               ul.append(downPage).append(endPage);
    
               var nav=$("<nav></nav>").append(ul);
    
               $("#page").append(nav);
    
    
            }
        </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-success">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
                </button>
                <button class="btn btn-warning">
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除
                </button>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <table class="table table-hover" id="emps_table">
                    <thead>
                        <tr>
                            <th>编号</th>
                            <th>姓名</th>
                            <th>性别</th>
                            <th>邮箱</th>
                            <th>部门</th>
                            <th >操作</th>
                        </tr>
                    </thead>
                    <tbody>
    
                    </tbody>
                </table>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6" id="page_count">
    
            </div>
            <div class="col-md-6" id="page">
    
            </div>
        </div>
    </div>
    </body>
    </html>
    
    

    注意,在这里,我们要配置插件分页合理化,不然虽然我们在分页栏到达极限的时候跳转不了,但页面记录数还是会跳转。

    在mybatis-config

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 配置分页合理化 -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
    

新增员工

  • 点击新增员工,探出BootStrap 模态框,我们可以将这模态框框架修改,变成属于自己的模态框。

    <div class="modal fade" id="myModal" 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">新增员工</h4>
                </div>
                <div class="modal-body">
                    <form class="form-horizontal">
                        <div class="form-group">
                            <label for="empName" class="col-sm-2 control-label">姓名</label>
                            <div class="col-sm-10">
                                <input type="email" class="form-control" id="empName" placeholder="Name">
                            </div>
                        </div>
    
                        <div class="form-group">
                            <label  class="col-sm-2 control-label">性别</label>
                            <div class="col-sm-10">
                                <label class="radio-inline">
                                    <input type="radio" name="inlineRadioOptions" id="gender_1" value="1" checked="checked">男
                                </label>
                                <label class="radio-inline">
                                    <input type="radio" name="inlineRadioOptions" id="gender_0" value="0">女
                                </label>
                            </div>
    
                        </div>
    
                        <div class="form-group">
                            <label for="email" class="col-sm-2 control-label">邮箱</label>
                            <div class="col-sm-10">
                                <input type="password" class="form-control" id="email" placeholder="Email">
                            </div>
                        </div>
    
                        <div class="form-group">
                            <label for="deptId" class="col-sm-2 control-label">部门</label>
                            <div class="col-sm-10">
                                <select class="form-control" id="deptId">
                                </select>
                            </div>
    
                        </div>
    
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-primary">保存</button>
                </div>
            </div>
        </div>
    </div>
    
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button id="add_bnt" class="btn btn-success"  data-keyboard="true" >
                <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
            </button>
            <button id="del_bnt" class="btn btn-warning">
                <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除
            </button>
        </div>
    </div>
    

    下面按钮对应。

  • 写好,可以发送ajax请求,请求数据库中部门的名字。

    //    对列表框发送ajax请求,将部门的数据显示在下拉列表框中
        $(function () {
            $("#add_bnt").click(function () {
                getDepts();
                $("#myModal").modal({
                    //防止点击背景就消失
                    backdrop:"static"
                });
            });
        })
    
        function getDepts() {
            $.ajax({
                url:"${basePath}/depts",
                type:"GET",
                success:function (data) {
                    console.log(data)
                    $.each(data.map.depts,function () {
                        var select=$("<option></option>").append(this.deptName).attr("value",this.deptId);
                        select.appendTo("#deptId");
                    })
                }
            })
        }
    

前端+后端校验

前端

  • 前端校验于程序猿来说不合理,在浏览器的开发者工具中,可以修改前端代码,如果只是用前端的知识来进行表单的验证,数据会极度的不安全,所以有必要采用后端校验。
  • 说明:其实前端校验可以不要,只用后端+前端知识结合校验就可以了。

后端

  • 后端校验的好处是,我们从前端发送ajax请求,然后在后端去请求数据库,例如:出现相同或者为空的时候,可以将警告保存,然后交给浏览器去处理。

例子

  • 首先,我们得导入JSR303校验 的包,博主用

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.1.0.Final</version>
    </dependency>
    

    这个版本相对比较稳定,而且import class的时候一定不要搞错,这个版本是javax的。

  • 这个jar提供了相当多的注解,方便我们可以直接在javabean的属性上加入校验注解,然后jar会给我自动解析这个注解,实现错误信息的记录。

    //    自定义校验模式,表示识别一个正则表达式,后面是错误信息
        @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{2,15}$",
                message = "字母开头,允许3-16位节,允许字母数字下划线")
        private String empName;
    
    //    官方的正则表达式
    //    @Email(message = "邮箱格式不正确")
    //    这里注意,在java / 代表转义字符,所以要改成//
        @Pattern(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$",message = "邮箱格式不正确")
        private String email;
    
  • 这时,当我们增加员工的时候,该注解会自动保存信息。当然,我们要在Controller里面获取

        @RequestMapping(value = {"/emp"},method = RequestMethod.POST)
        @ResponseBody
    //    下面的参数注解代表返回的校验
    //    第二份参数代表返回的错误信息结果集
        public Msg addEmp(@Valid Employee e, BindingResult result){
            Map<String,Object> resultMap=new HashMap<String, Object>();
            System.out.println(result.hasErrors());
            if (result.hasErrors()){
    //        返回错误信息
                List<FieldError> fieldErrors = result.getFieldErrors();
                for (FieldError error:fieldErrors
                ) {
    //         将数据放进map里,
                    resultMap.put(error.getField(),error.getDefaultMessage());
                }
                return Msg.fail().add("resultMap",resultMap);
            }
            employeeService.add(e);
            return Msg.success();
        }
    

    这里面是在原来的基础上改进的。

  • 然后就是前端的一些代码,这里为了方便,我将前段校验和后端校验都发上来。

    <%--
      Created by IntelliJ IDEA.
      User: 黄渝斌
      Date: 2021/9/12
      Time: 12:31
      To change this template use File | Settings | File Templates.
    --%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page isELIgnored="false" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@include file="/common/base.jsp"%>
    <html>
    <head>
        <title>员工列表</title>
    
        <%@include file="/common/link.jsp"%>
        <script type="text/javascript" >
            var totalPage;
            $(function () {
                to_page(1);
            })
            function to_page(pn) {
                $.ajax({
                    url:"${basePath}/emps",
                    data:"page="+pn,
                    type:"GET",
                    success:function (data) {
                        totalData=data;
                        build_list(data);
                        build_page_count(data);
                        build_page(data);
                    }
                })
            }
    
            function build_list(data) {
                //清空表格里的数据
                $("#emps_table tbody").empty();
                var emps=data.map.pageInfo.list;
                $.each(emps,function (index,item) {
                    var empIdTd = $("<td></td>").append(item.empId);
                    var empNameTd = $("<td></td>").append(item.empName);
                    var genderTd = $("<td></td>").append(item.gender==='1'?"男":"女");
                    var emailTd = $("<td></td>").append(item.email);
                    var deptNameTd = $("<td></td>").append(item.department.deptName);
                    var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm")
                        .append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
    
                    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方法执行完成以后还是返回原来的元素,这里每次append都会产生新的<tr></tr>
                    var tr=$("<tr></tr>").append(empIdTd).append(empNameTd)
                        .append(genderTd).append(emailTd).append(deptNameTd)
                        .append(btnTd)
                    $("#emps_table tbody").append(tr)
                })
            }
            function build_page_count(data) {
                $("#page_count").empty();
                var page=data.map.pageInfo;
                $("#page_count").append("当前"+page.pageNum+"页,总"+page.pages+"页,总"+
                        page.total+"记录");
                totalPage=page.total;
    
            }
            function build_page(data) {
                $("#page").empty();
                var ul=$("<ul></ul>").addClass("pagination");
    
                //首页
                var firstPage=$("<li></li>").append($("<a></a>").append("首页").attr("href","#"));
                firstPage.click(function () {
                    to_page(1);
                });
    
                //上一页
                var upPage=$("<li></li>").append($("<a></a>").append("<span></span>").append("&laquo;").attr("href","#"));
                upPage.click(function () {
                    to_page(data.map.pageInfo.pageNum-1);
                });
    
                if(!data.map.pageInfo.hasPreviousPage){
                    firstPage.addClass("disabled");
                    upPage.addClass("disabled");
                }
                //首页,前一页
                ul.append(firstPage).append(upPage);
    
                $.each(data.map.pageInfo.navigatepageNums,function (index,itme) {
                    var numi=$("<li></li>").append($("<a></a>").append(itme).attr("href","#"));
                    numi.click(function () {
                        to_page(itme);
                    });
    
                    if (data.map.pageInfo.pageNum===itme){
                        numi.addClass("active");
                    }
                //    当前页
                    ul.append(numi);
                })
                //下一页
                var downPage=$("<li></li>").append($("<a></a>").append("<span></span>").append("&raquo;").attr("href","#"));
                downPage.click(function () {
                    to_page(data.map.pageInfo.pageNum+1);
                });
    
                //末页
                var endPage=$("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
                endPage.click(function () {
                    to_page(data.map.pageInfo.pages);
                });
    
                if(!data.map.pageInfo.hasNextPage){
                    endPage.addClass("disabled");
                    downPage.addClass("disabled");
                }
               ul.append(downPage).append(endPage);
    
               var nav=$("<nav></nav>").append(ul);
    
               $("#page").append(nav);
            }
    
        //    对列表框发送ajax请求,将部门的数据显示在下拉列表框中
            $(function () {
                $("#add_bnt").click(function () {
    
                    getDepts();
                    $("#myModal").modal({
                        //防止点击背景就消失
                        backdrop:"static"
                    });
                });
    
            })
    
            function getDepts() {
                $("#_deptId").empty();
                $.ajax({
                    url:"${basePath}/depts",
                    type:"GET",
                    success:function (data) {
                        $.each(data.map.depts,function () {
                            var select=$("<option></option>").append(this.deptName).attr("value",this.deptId).attr("name","deptId");
                            select.appendTo("#_deptId");
                        })
                    }
                })
            }
    
            //点击保存按钮
            $(function () {
                $("#add_emp").click(function () {
                    //若用户不合法,阻止提交ajax请求
                    if (!userJudge()){
                        return false;
                    }
    
                    //若用户名已存在,阻止其提交ajax请求
                    if ($(this).attr("ajax_alert")==="error"){
                        return false;
                    }
                    $.ajax({
                        url:"${basePath}/emp",
                        type:"POST",
                        //表单序列化,变成json
                        data:$("#myModal form").serialize(),
                        success:function (data) {
                            /*
                            * 因为我们在后端进行校验,所以我们要在关闭模态框之前进行判断
                            * */
                            if (data.code==="200"){
    
                                //    关闭模态框
                                $("#myModal").modal('hide');
    
                                //清空表单项
                                clear();
    
                                //    跳转到最后一页
                                to_page(totalPage);
                            }else {
                                if (undefined!==data.map.resultMap.email){
                                   // 显示员工名错误信息
                                    $("#email").parent().addClass("has-error");
                                    $("#inputErrorEmail").text(data.map.resultMap.email);
                                }
                                if (undefined!==data.map.resultMap.empName){
                                //    显示邮箱错误信息
                                    $("#empName").parent().addClass("has-error");
                                    $("#inputErrorName").text(data.map.resultMap.empName);
                                }
                            }
                        }
                    })
                });
            })
    
            //表单的清空
            $(function () {
                $("#_reset").click(function () {
                    clear();
                });
            })
            function clear() {
                //表单重置
                $("#myModal form")[0].reset();
    
                // $("#empName").val("");
                // $("#email").val("");
            }
    
            //用户名是否存在校验
            $(function () {
                //注意,这里一定要有这个失去焦点事件,或者其他事件,不然你直接让$(function(){})先加载,弹出框都没出来便发送ajax请求,对后来的验证就没有了
                $("#empName").blur(function () {
                    ifUser();
                });
    
            //    前端email校验,会有bug
                $("#email").blur(function () {
                    emailJudge();
                });
    
            });
    
            function ifUser() {
                var empName=$("#empName").val();
                $.ajax({
                    url:"${basePath}/change",
                    type:"GET",
                    data:"empName="+empName,
                    success:function (data) {
                        if (data.code==="200"){
                            $("#empName").parent().removeClass("has-error");
                            $("#empName").parent().addClass("has-success");
                            $("#inputErrorName").text("");
                            //设置状态属性
                            $("#add_emp").attr("ajax_alert","success")
                        }else {
                            $("#empName").parent().removeClass("has-success");
                            $("#empName").parent().addClass("has-error");
                            $("#inputErrorName").text(data.map.success_msg);
                            $("#add_emp").attr("ajax_alert","error")
    
                        }
                    }
                })
            }
    
            //前端email校验
            function emailJudge() {
                var email=$("#email").val();
                var jemail=/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
                if (!jemail.test(email)) {
                    $("#email").parent().addClass("has-error");
                    $("#inputErrorEmail").text("请输入正确的邮箱格式");
                    return false;
                }
                if (jemail.test(email)) {
                    $("#email").parent().removeClass("has-error");
                    $("#email").parent().addClass("has-success");
                    $("#inputErrorEmail").text("");
                }
    
            }
    
    
            //表单校验,前端校验
            function userJudge() {
                var username= $("#empName").val();
    
                //帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)
                var juser=/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/;
    
                if (!juser.test(username)) {
                    $("#empName").parent().addClass("has-error");
                    $("#inputErrorName").text("字母开头,允许3-16位,允许字母数字下划线");
                    return false;
                }
                if (juser.test(username)) {
                    $("#empName").parent().removeClass("has-error");
                    $("#empName").parent().addClass("has-success");
                    // $("#inputErrorName").text("")
                    ifUser();
                    return true;
                }
    
                return false;
            }
    
        </script>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <h1>SSM_CRUD</h1>
            </div>
        </div>
    
        <%--弹出框新增--%>
        <div class="modal fade" id="myModal" 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">新增员工</h4>
                    </div>
                    <div class="modal-body">
                        <form class="form-horizontal" id="_form">
                            <div class="form-group">
                                <label for="empName" class="col-sm-2 control-label">姓名</label>
                                <div class="col-sm-10">
                                    <input type="email" class="form-control" name="empName" id="empName" placeholder="Name">
                                    <span id="inputErrorName" class="help-block"></span>
                                </div>
                            </div>
    
                            <div class="form-group">
                                <label  class="col-sm-2 control-label">性别</label>
                                <div class="col-sm-10">
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender_1" value="1" checked="checked">男
                                    </label>
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender_0" value="0">女
                                    </label>
                                </div>
    
                            </div>
    
                            <div class="form-group">
                                <label for="email" class="col-sm-2 control-label">邮箱</label>
                                <div class="col-sm-10">
                                    <input type="email" class="form-control" name="email" id="email" placeholder="Email">
                                    <span id="inputErrorEmail" class="help-block"></span>
                                </div>
                            </div>
    
                            <div class="form-group">
                                <label for="_deptId" class="col-sm-2 control-label" >部门</label>
                                <div class="col-sm-10">
                                    <select class="form-control" name="deptId" id="_deptId">
                                    </select>
                                </div>
    
                            </div>
    
                        </form>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" name="_reset" id="_reset">
                            清空
                        </button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                        <button type="button" class="btn btn-primary" id="add_emp">保存</button>
                    </div>
                </div>
            </div>
        </div>
    
        <div class="row">
            <div class="col-md-4 col-md-offset-8">
                <button id="add_bnt" class="btn btn-success"  data-keyboard="true" >
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
                </button>
                <button id="del_bnt" class="btn btn-warning">
                    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>删除
                </button>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <table class="table table-hover" id="emps_table">
                    <thead>
                        <tr>
                            <th>编号</th>
                            <th>姓名</th>
                            <th>性别</th>
                            <th>邮箱</th>
                            <th>部门</th>
                            <th >操作</th>
                        </tr>
                    </thead>
                    <tbody>
    
                    </tbody>
                </table>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6" id="page_count">
    
            </div>
            <div class="col-md-6" id="page">
    
            </div>
        </div>
    </div>
    </body>
    </html>
    

    里面还设计一个后端设计

        @RequestMapping(value={"/change"},method = RequestMethod.GET)
        @ResponseBody
        public Msg queryIsEmpty(@RequestParam("empName") String empName){
            boolean isEmpty = employeeService.queryIsEmptyByName(empName);
    //        在前端校验中的测试中,我们会发现,当我们输入了不可用的名字会显示可用之后才执行不可用的判断,
    //        这是因为在判断不可用的同时,加入了一层用户名是否存在的校验,所以我们要用户名是否存在的后端中加一层校验
            String s="^[a-zA-Z][a-zA-Z0-9_]{2,15}$";
    //        这是String里一种支持校验正则表达式的方法
            boolean matches = empName.matches(s);
            if (!matches){
                return Msg.fail().add("success_msg","字母开头,允许3-16位,允许字母数字下划线");
            }
            if (isEmpty){
                return Msg.success();
            }else {
                return Msg.fail().add("success_msg","用户名已存在");
            }
        }
    

    上面这个设计,是纯手写的后端校验。JSR303 是一个后端校验的框架,这两个是区分开的。

编辑员工

  • 编辑员工我们要弹出模态框,然后将数据回显在表单上,最后做数据验证。

  • 首先是探出模态框,和添加员工的jsp代码一样,但是属性名字不能一样。

    <div class="modal fade" id="myModal_update" 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_update">修改员工</h4>
                </div>
                <div class="modal-body">
                    <form class="form-horizontal" id="_form_update">
                        <div class="form-group">
                            <label for="empName_update" class="col-sm-2 control-label">姓名</label>
                            <div class="col-sm-10">
                                <input type="email" class="form-control" name="empName" id="empName_update" placeholder="Name">
                                <span id="inputErrorName_update" class="help-block"></span>
                            </div>
                        </div>
    
                        <div class="form-group">
                            <label  class="col-sm-2 control-label">性别</label>
                            <div class="col-sm-10">
                                <label class="radio-inline">
                                    <input type="radio" name="gender" id="gender_1_update" value="1" checked="checked">男
                                </label>
                                <label class="radio-inline">
                                    <input type="radio" name="gender" id="gender_0_update" value="0">女
                                </label>
                            </div>
    
                        </div>
    
                        <div class="form-group">
                            <label for="email_update" class="col-sm-2 control-label">邮箱</label>
                            <div class="col-sm-10">
                                <input type="email" class="form-control" name="email" id="email_update" placeholder="Email">
                                <span id="inputErrorEmail_update" class="help-block"></span>
                            </div>
                        </div>
    
                        <div class="form-group">
                            <label for="_deptId_update" class="col-sm-2 control-label" >部门</label>
                            <div class="col-sm-10">
                                <select class="form-control" name="deptId" id="_deptId_update">
                                </select>
                            </div>
    
                        </div>
    
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" name="_reset_update" id="_reset_update">
                        清空
                    </button>
                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                    <button type="button" class="btn btn-primary" id="add_emp_update">修改</button>
                </div>
            </div>
        </div>
    </div>
    
  • 之后,便是进行数据回显,进行数据回显,我们要知道一点,这个编辑的按钮是随着数据的加载而产生的,也就是动态产生的,所以我们要为其绑定单击事件,一定要在有了该按钮的时候才可以绑定。

    为了方便绑定,我们可以在产生数据的时候,为这个编辑的按钮增加一些属性。

    var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm edit_emp")
        .append($("<span></span>").addClass("glyphicon glyphicon-pencil")).append("编辑");
    
    /*
    * 这里一定得这样赋值,因为这个按钮是动态增加的
    * 所以,可以每一次动态增加的时候添加一个属性
    * */
    editBtn.attr("this_id",item.empId);
    /*
    * $("#add_emp_update").attr("empId",item.empId) 不能将这个设置在这里,
    * 因为下面的按钮在页面加载完成后已经结束了,然后根据循环,只会将最后一次的数据赋值
    * */
    // $("#add_emp_update").attr("empId",item.empId)
    
    //下面这个设置是为传递一个部门id,可以根据这个部门id更改选中的属性
    editBtn.attr("this_deptId",item.deptId);
    
  • 可以看到,上面我们将编辑的按钮动态的增加了两个属性,然后我们为编辑这个按钮增加一个单击事件,但这个按钮的单击事件要注意,因为这个是根据数据显示才出现的按钮,所以要在数据加载时绑定。绑定方法有些不同。

            /*
            * 下面是对修改用户功能
            * */
    
            //当我们窗体加载完成,事件绑定完成,而数据还需要发送ajax请求才能出来(修改的按钮),所以,我们要在全局document中绑定
    
            $(document).on("click",".edit_emp",function () {
                //我们要将部门信息显示出来,可以调用增加员工那里的getDept的方法,
                //但是员工那里写死了,所以我们可以将那个方法稍作修改
                //将要植入数据的标签通过参数传入就可以了
                getDepts("#_deptId_update")
    
                //发送ajax请求,请求当前修改的数据到表中
                //下列不能用val()方法
                var id=$(this).attr("this_id");
    
                /*
                * 下面的按钮一定要这样赋值,因为这是动态的,每次点击编辑,将当前的id获取,赋值给更新按钮的属性
                * 就不会出现只能取到最后一个值的情况
                * */
                $("#add_emp_update").attr("empId",id)
                var deptId=$(this).attr("this_deptId");
                // $("#_deptId_update option").val([deptName]);
                // $("#_deptId_update option").append(deptName).attr("value",this_data.deptId)
                this_list(id,deptId);
                $("#myModal_update").modal({
                    //防止点击背景就消失
                    backdrop:"static"
                });
    
                /*
                * 下面一定不能这样调用,代码虽然看清来很美,但是按钮是动态生成的。
                * 第一次你修改的时候没有错,
                * */
                // edit(id);
                /*function edit(id){
                    $.ajax({
                        <%--url:"${basePath}/emp/"+id,--%>
                        type:"PUT",
                        data:$("#myModal_update form").serialize(),
                        success:function (data) {
                            //    关闭模态框
                            $("#myModal_update").modal('hide');
                            clear("#myModal_update form");
                            to_page(presentPage);
                        }
                    })
                }*/
    
            })
    
    
    
    
            function this_list(id,deptId) {
                $.ajax({
                    url:"${basePath}/emp",
                    type:"GET",
                    data:"empId="+id,
                    success:function (data) {
                        var this_data=data.map.thisEmp;
                        $("#empName_update").attr("value",this_data.empName).text(this_data.empName);
                        var gender=this_data.gender;
                        if (gender==="1"){
                            $("#gender_1_update").val([gender]);
                        }else{
                            $("#gender_0_update").val([gender]);
                        }
                        $("#email_update").attr("value",this_data.email).text(this_data.email);
                        $("#_deptId_update option[value="+deptId+"]").prop("selected", true);
                    }
                })
            }
    
    /*
    * 根据id搜索数据
    * */
    @RequestMapping(value = {"/emp"},method = RequestMethod.GET)
    @ResponseBody
    public Msg queryEmpById(@RequestParam("empId")Integer empId){
        Employee employee = employeeService.queryEmpById(empId);
        return Msg.success().add("thisEmp",employee);
    }
    

    注意:在ajax中,除了get和post以外的请求是不支持的,除非你的加了个参数_method=put…,若你想在type中直接输入请求方式而不加参数,要在web.xml中设置过滤器参数

    <!--此过滤器FormContentFilter为了让SpringMVC使得Ajax支持put请求-->
    <filter>
      <filter-name>FormContentFilter</filter-name>
      <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
    </filter>
    
    <filter-mapping>
      <filter-name>HiddenHttpMethodFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
      <filter-name>FormContentFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  • 搜索了数据之后,就可以根据表单进行回显数据,回显成功后,就可以和前面的一样,进行前端和后端的验证

    //用户名是否存在校验
    $(function () {
        //注意,这里一定要有这个失去焦点事件,或者其他事件,不然你直接让$(function(){})先加载,弹出框都没出来便发送ajax请求,对后来的验证就没有了
        $("#empName").blur(function () {
            ifUser();
        });
    
    //    前端email校验,会有bug
        $("#email").blur(function () {
            emailJudge("#email","#inputErrorEmail");
        });
    
        $("#email_update").blur(function () {
            emailJudge("#email_update","#inputErrorEmail_update");
        });
    
        $("#empName_update").blur(function () {
            userJudge("#empName_update","#inputErrorName_update");
        });
    
    });
    

    前端验证完毕后,就可以进行修改的单击事件的绑定

    $(document).on("click","#add_emp_update",function () {
        /*
        * 下面注释的一定不能这样获取id
        * 因为这个类是动态的,也就是说,我们将所有编辑的按钮都加上这个类的时候
        * 当这个页面加载完成,我们获取的值就是第一个类的按钮的值,
        * */
        // var id=$(".edit_emp").attr("this_id");
    
        /*
        * 而通过下面去获取id的属性,就是每一次点击编辑按钮赋值给修改按钮的值,这个值是动态的,只有在点击编辑按钮的时候才会被赋值
        * */
        var id=$(this).attr("empId");
        $.ajax({
    
            /*
            * 这里一定要传入一个id值,因为我们下面的表单序列化,得到的对象是没法将当前的id属性放进去的
            * 如果单单传入这个对象,系统无法根据id属性修改
            * 而如果在表单序列化后面加入连接符,连接一个id属性上去也是不行的,
            * 这样的意思只是将id属性传了过去,我们也没有用到,如果是在传入地址到时候传进去,会自动解析成对象里的id属性
            * */
            url:"${basePath}/emp/"+id,
            type:"PUT",
            data:$("#myModal_update form").serialize(),
            success:function (data) {
                if (data.code==="200"){
                    $("#add_emp_update").attr("ajax_alert","success")
                    //    关闭模态框
                    $("#myModal_update").modal('hide');
                    clear("#myModal_update form");
                    to_page(presentPage);
                }else {
    
                    $("#add_emp_update").attr("ajax_alert","error")
                    if (!data.map.isNoEmpty){
                        $("#empName_update").parent().addClass("has-error");
                        $("#inputErrorName_update").text(data.map.isNoEmptyText);
    
                    }
                    if (undefined!==data.map.resultMapPlus.email){
                        // 显示员工名错误信息
                        $("#email_update").parent().addClass("has-error");
                        $("#inputErrorEmail_update").text(data.map.resultMapPlus.email);
                    }
                    if (undefined!==data.map.resultMapPlus.empName){
                        //    显示邮箱错误信息
                        $("#empName_update").parent().addClass("has-error");
                        $("#inputErrorName_update").text(data.map.resultMapPlus.empName);
    
                    }
    
    
                }
    
            }
        })
    });
    

    我们可以看到,单击事件成功后,在后端会回传数据,下面是后端的代码

       /*
        * 修改员工信息
        * 这里必须穿一个id值过来,因为你在前端的表单序列化里,是没有id属性的
        * 但是在sql语句里,是通过id给你更新一个值的
        * */
        @RequestMapping(value = {"/emp/{empId}"},method = RequestMethod.PUT)
        @ResponseBody
        public Msg updateEmp(@Valid Employee e,BindingResult result){
            Map<String,Object> resultMap=new HashMap<String, Object>();
            if (result.hasErrors()){
    //        返回错误信息
                List<FieldError> fieldErrors = result.getFieldErrors();
                for (FieldError error:fieldErrors
                ) {
    //         将数据放进map里,
                    resultMap.put(error.getField(),error.getDefaultMessage());
                }
                return Msg.fail().add("resultMapPlus",resultMap);
            }
    //        如果数据没有错误,就要判断,重新改变的用户名是否已经存在
    //        这里的判断要注意的一点是,我们的判断是要排除自己本身的
            Boolean isEmpty= employeeService.queryIsEmptyOtherName(e.getEmpId(),e.getEmpName());
            if (isEmpty) {
                return Msg.fail().add("isNoEmpty",false).add("isNoEmptyText","员工已存在");
            }
            employeeService.updateEmp(e);
            return Msg.success().add("isNoEmpty",true).add("isNoEmptyText","");
        }
    

    这个后端便同时进行了数据的查询和验证。

  • 注意:在做编辑员工的时候,原来一些方法是写死的,所以这里我做了一些简单的抽取。

删除员工

简单删除

  • 在每一列中,我们可以点击删除按钮,提示是否删除

  • 其原理和编辑员工几乎一样,首先得获取该tr里的id,用于后端删除,还有tr里的name,用于前端警告

    var delBtn = $("<button></button>").addClass("btn btn-danger btn-sm del_emp")
        .append($("<span></span>").addClass("glyphicon glyphicon-trash del_emp")).append("删除");
    
    delBtn.attr("this_id",item.empId);
    
  • 然后发送ajax请求,这里开始验证

    $(document).on("click",".del_emp",function () {
        var id=$(this).attr("this_id");
        var name=$(this).parents("tr").find("td:eq(1)").text();
        if (confirm("你确定要删除"+name+"吗?")){
            $.ajax({
                url:"${basePath}/emp",
                type:"delete",
                data:"empId="+id,
                success:function (data) {
                    to_page(presentPage);
                }
            })
        }
    
    })
    
  • 后端代码比较简单,这里省略。

全选删除

  • 前面我们做的列表是没有全选的,所以这里我们要为其添加上全选按钮,但是要注意的一个细节是,前面的简单删除,我们获取员工时用的eq,所以现在得改变

    <th>
        <label for="checkAll" >
            <input type="checkbox" name="checkAll" id="checkAll">
        </label>
    
    </th
    

    然后我们要为每个tr都添加这个input

    var empChecked=$("<td></td>").append("<input type='checkbox' class='check_item'/>")
    
    var tr=$("<tr></tr>").append(empChecked).append(empIdTd).append(empNameTd)
        .append(genderTd).append(emailTd).append(deptNameTd)
        .append(btnTd)
    
  • 然后我们为全选input添加click属性,也要为单个input添加click属性

    //    为全选绑定单击事件,因为这是已经加载出来的,所以不用动态绑定
        $(function () {
            $("#checkAll").click(function () {
            //    下面我们要做的事情就是选中所有,下面所有的都跟着选中,就要改变input标签里的checked属性
            //    在input标签中,我们没有显示写checked属性,但其是默认有的,
            //    对于这种原生的属性的,我们用attr就不那么好看,所以可以用prop
            //    attr可以获取咱们自定义的属性
    
            //    1.我们先拿到所有的checked
                let allChecked = $(this).prop("checked");
            //    2.上面返回true或者false,然后我们用这个修改单个选择,这里最好用类选择器,因为我们本身就要全部选中
                $(".check_item").prop("checked",allChecked);
            });
    
        //    为单个选中绑定单击事件,这里主要是为了我们全部单个选中的时候,为了美化,全选也要进行选择
        //    单个选中是动态生成的
            $(document).on("click",".check_item",function () {
            //    获取单个全部选中时的长度
                let totalLength=$(".check_item").length;
            //    单个选中的总个数
                let itemLength=$(".check_item:checked").length;
    
                if (totalLength===itemLength) $("#checkAll").prop("checked",true);
    
                if (totalLength!==itemLength) $("#checkAll").prop("checked",false);
            })
        })
    
  • 之后就是点击总删除按钮,提示信息,发送请求

    $(function () {
        $("#del_bnt").click(function () {
            // $(".check_item").prop("checked",$("#checkAll").prop("checked",true));
            var empNames="";
            var empIds="";
            $.each($(".check_item:checked"),function () {
                empNames+=$(this).parents("tr").find("td:eq(2)").text()+",";
                empIds+=$(this).parents("tr").find("td:eq(1)").text()+"-";
            })
            //去掉后缀多余符号
            empNames=empNames.substring(0,empNames.length-1);
            empIds=empIds.substring(0,empIds.length-1);
            let confirmAll;
            if (totalPage===0){
                confirm("该表没有员工数据!")
            } else if (empNames.length===0){
                confirm("你还未选中,请选择!")
            } else if ($("#checkAll").prop("checked")){
                confirmAll=confirm("你确定全部删除吗?");
            } else {
                confirmAll=confirm("确定要删除"+"["+empNames+"]"+"吗?")
            }
            if (confirmAll){
                $.ajax({
                    url:"${basePath}/emp",
                    type:"delete",
                    data:"empIds="+empIds,
                    success:function (data) {
                        to_page(presentPage);
                        $("#checkAll").prop("checked",false);
                    }
                })
            }else {
                $("#checkAll").prop("checked",false);
                $.each($(".check_item:checked"),function () {
                   $(this).prop("checked",false);
                })
            }
        });
    })
    
  • 发送请求后,我们去后端写代码,注意这里的Controller代码可以在单个删除的原基础上改变成批量删除

    @RequestMapping(value = {"/emp"},method = RequestMethod.DELETE)
    @ResponseBody
    public Msg delEmp(@RequestParam("empIds")String empIds){
        if (empIds.length()==1) {
            employeeService.delEmp(Integer.parseInt(empIds));
        }else {
            List<Integer> list=new ArrayList<Integer>();
            String[] empIdsString = empIds.split("-");
            for (String s:empIdsString
                 ) {
                list.add(Integer.parseInt(s));
            }
            employeeService.delEmpByBath(list);
        }
        return Msg.success();
    }
    
    public void delEmpByBath(List<Integer> list){
        EmployeeExample example = new EmployeeExample();
        example.createCriteria().andEmpIdIn(list);
        employeeMapper.deleteByExample(example);
    }
    
    public void delEmp(Integer empId) {
        employeeMapper.deleteByPrimaryKey(empId);
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值