SSM_CRUD练习项目

文章目录

      • 功能点
      • 环境与技术
      • 最终的效果图
  • 搭建基本环境
      • 创建maven项目
      • 添加基本目录
      • 引入依赖
      • 配置tomcat服务器
      • 引入bootstrap前端框架
          • 下载
          • 引入
        • 应用测试
      • 创建数据库
      • 编写ssm整合的关键配置文件。
      • 使用mybatis的逆向工程生成对应的bean、dao和mapper
      • 增添查询员工信息时带上部门信息的业务
      • 测试CRUD功能
  • CRUD-查询
        • 步骤
          • 1. index.jsp只用于跳转到查询页面,所以只留以下内容。
          • 2. 在pop.xml中引入分页插件。
          • 3. 在mybatis-config.xml中注册分页插件。
          • 4. 然后在controller下新建一个EmployeeController.java,用于处理员工CRUD请求。
          • 5. 在service下新建一个EmployeeService.java
          • 6. 测试分页查询的数据
          • 7. 在webapp/WEB-INF/views里新建一个list.jsp页面,为员工列表页面。
          • 效果图
  • 查询-ajax
        • 步骤
          • 1. 注释掉EmployeeController.java中的getEmps方法,新建一个getEmpsWithJson方法。
          • 2. 在pop.xml中引入json的依赖
          • 3. 在bean中定义一个Msg.java用于请求的结果进行处理和返回
          • 4. 在mybatis-config.xml中给配置分页插件配置一个参数
          • 5. 舍弃list.jsp,重写index.jsp页面
          • 效果图
  • CRUD-新增
        • 步骤
          • 1. 为index.jsp的新增按钮增加弹窗效果
          • 效果图
          • 2. 编写新建按钮的弹窗的保存按钮的保存效果
          • 效果图
          • 3. 问弹窗表单增加校验功能
            • 校验员工姓名和邮箱
            • 校验员工姓名是否重复
            • 后端校验数据
  • CRUD-修改
        • 步骤
          • 1. 实现点击编辑弹出员工信息模态框
          • 2. 实现点击弹窗内更新按钮修改员工信息
  • CRUD-删除
        • 步骤
          • 1. 实现单个删除
          • 2. 多选删除

功能点

  1. 分页功能
  2. 新增和修改时的数据校验(前端JQuery校验+后端JSR303)
  3. Ajax异步请求
  4. Rest风格的URI(使用不同http协议的请求方式表示对数据的不同操作。GET(查询)、POST(新增)、PUT(修改)、DELETE(删除))

环境与技术

电脑环境:macOS
电脑软件:IDEA、Navicat Premium
基础框架:ssm(Spring+SpringMVC+MyBatis)
前端框架:bootstrap
数据库:MySQL8.0.18
服务器:Tomcat8.5.51
依赖管理:Maven3.5.4
分页工具:pagehelper
逆向工程:MyBatis Generator

最终的效果图

SSM_CRUD练习项目_第1张图片
实现的功能:员工信息的新增、修改、单个和多个删除。

项目地址:https://github.com/angenin/ssm_crud/


搭建基本环境


创建maven项目

创建一个maven项目,选用webapp模板,文件名为ssm_crud。
SSM_CRUD练习项目_第2张图片

添加基本目录

在src下新建test目录,test下再新建java和resources目录,在main目录下也添加java和resources目录。
SSM_CRUD练习项目_第3张图片

引入依赖

  • 在pop.xml中先引入基本的依赖的jar包
  
  <dependencies>


    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webmvcartifactId>
      <version>5.2.4.RELEASEversion>
    dependency>


    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-jdbcartifactId>
      <version>5.2.4.RELEASEversion>
    dependency>


    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-aspectsartifactId>
      <version>5.2.4.RELEASEversion>
    dependency>


    
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatisartifactId>
      <version>3.5.2version>
    dependency>


    
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatis-springartifactId>
      <version>2.0.2version>
    dependency>


    
    <dependency>
      <groupId>com.mchangegroupId>
      <artifactId>c3p0artifactId>
      <version>0.9.5.2version>
    dependency>


    
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.18version>
    dependency>


      
      <dependency>
          <groupId>javax.servletgroupId>
          <artifactId>jsp-apiartifactId>
          <version>2.0version>
          <scope>providedscope>
      dependency>
      
    
    <dependency>
      <groupId>jstlgroupId>
      <artifactId>jstlartifactId>
      <version>1.2version>
    dependency>

    
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>javax.servlet-apiartifactId>
        <version>4.0.1version>
        <scope>providedscope>
    dependency>

    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>4.12version>
      <scope>testscope>
    dependency>
  dependencies>

配置tomcat服务器

SSM_CRUD练习项目_第4张图片
SSM_CRUD练习项目_第5张图片
SSM_CRUD练习项目_第6张图片
SSM_CRUD练习项目_第7张图片
SSM_CRUD练习项目_第8张图片
SSM_CRUD练习项目_第9张图片

引入bootstrap前端框架

下载

进入官网下载:https://www.bootcss.com/


SSM_CRUD练习项目_第10张图片

引入

在项目的webapp目录下新建static目录,并把下载解压好的文件放入,再在static目录下新建一个js目录,用于存放JQuery文件。
- 在index.jsp中的head标签里写入
html

  • 也可以直接在index.jsp的head标签里引入下面这两个标签。
    SSM_CRUD练习项目_第11张图片
    SSM_CRUD练习项目_第12张图片

应用测试

  • 使用bootstrap的样式,点击官网的全局CSS样式。
    SSM_CRUD练习项目_第13张图片
    这里的样式都可以选择使用,我们用按钮来测试效果。
    SSM_CRUD练习项目_第14张图片
    复制到index.jsp中,然后启动。
    SSM_CRUD练习项目_第15张图片
    SSM_CRUD练习项目_第16张图片
    前端的bootstrap的框架就引入成功了。
    SSM_CRUD练习项目_第17张图片

创建数据库

create database ssm_crud;

use ssm_crud;

create table tbl_dept(
	dept_id int(11) PRIMARY KEY auto_increment,
	dept_name varchar(255) not null
);

create table tbl_emp(
	emp_id int(11) PRIMARY KEY auto_increment,
	emp_name varchar(255) not null,
	gender char(1),	
	email varchar(255) not null,
	d_id int(11),
	FOREIGN KEY(d_id) REFERENCES tbl_dept(dept_id)
);


编写ssm整合的关键配置文件。

在main下的java目录里新建以下目录:
SSM_CRUD练习项目_第18张图片

在main目录下的resources目录添加Spring的配置文件,名为applicationContext.xml。
SSM_CRUD练习项目_第19张图片
在main目录下的resources目录添加三个file文件,名为jdbcConfig.properties、springmvc.xml和mybatis-config.xml。
SSM_CRUD练习项目_第20张图片
在resources目录下添加mapper目录。
在WEB-INF目录下新建一个名为views的目录。
在WEB-INF目录下新建一个名为dispatcherServlet-Servlet.xml的配置文件。


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

beans>
  • 配置webapp/WEB-INF/web.xml文件
	

<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_3_1.xsd"
         version="3.1">
  <display-name>Archetype Created Web Applicationdisplay-name>



  <context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:applicationContext.xmlparam-value>
  context-param>
  
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
  listener>

  
  <servlet>
    <servlet-name>dispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>

    <load-on-startup>1load-on-startup>
  servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServletservlet-name>
    <url-pattern>/url-pattern>
  servlet-mapping>


  <filter>
    <filter-name>CharacterEncodingFilterfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>

    <init-param>
      <param-name>encodingparam-name>
      <param-value>UTF-8param-value>
    init-param>

    <init-param>
      <param-name>forceRequestEncodingparam-name>
      <param-value>trueparam-value>
    init-param>
    <init-param>
      <param-name>forceResponseEncodingparam-name>
      <param-value>trueparam-value>
    init-param>
  filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>


  <filter>
    <filter-name>HiddenHttpMethodFilterfilter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
  filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilterfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>

web-app>
  • 配置resources/springmvc.xml文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:ontext="http://www.springframework.org/schema/context"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">


    <ontext:component-scan base-package="com.angenin" use-default-filters="false">

        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    ontext:component-scan>



    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        
        <property name="prefix" value="/WEB-INF/views/"/>
        
        <property name="suffix" value=".jsp"/>
    bean>



    <mvc:default-servlet-handler/>
    
    <mvc:annotation-driven/>

beans>
  • 配置resources/jdbcConfig.properties文件
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=123456
  • 配置resources/applicationContext.xml文件

<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">


    

    <context:component-scan base-package="com.angenin">

        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>
    
    <context:property-placeholder location="classpath:jdbcconfig.properties"/>
    <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    bean>




    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="configLocation" value="classpath:mybatis-config.xml"/>

        <property name="dataSource" ref="pooledDataSource"/>

        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    bean>
    

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

        <property name="basePackage" value="com.angenin.crud.dao"/>
    bean>




    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="pooledDataSource"/>
    bean>


    <aop:config>

        <aop:pointcut id="txPoint" expression="execution(* com.angenin.crud.service..*(..))"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    aop:config>


    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>

            <tx:method name="*"/>


            <tx:method name="get*" read-only="true"/>
        tx:attributes>
    tx:advice>
beans>
  • 配置mybatis-config.xml文件


<configuration>


    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    settings>

    <typeAliases>
        <package name="com.angenin.crud.bean"/>
    typeAliases>

configuration>

使用mybatis的逆向工程生成对应的bean、dao和mapper

在pop.xml中的里引入

      

      <dependency>
          <groupId>org.mybatis.generatorgroupId>
          <artifactId>mybatis-generator-coreartifactId>
          <version>1.3.7version>
      dependency>

然后在resources目录下新建generatorConfig.xml文件,并写入
(在标签里的targetProject属性,因为我是macOS,所有用/,如果是Windows系统,需要把/改为\。)



<generatorConfiguration>

    
    <properties resource="jdbcConfig.properties"/>

    
    
    <context id="mbg" targetRuntime="MyBatis3">

        
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        commentGenerator>

        
        <jdbcConnection connectionURL="${jdbc.jdbcUrl}"
                        driverClass="${jdbc.driverClass}"
                        userId="${jdbc.user}"
                        password="${jdbc.password}"/>

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


        <javaModelGenerator targetPackage="com.angenin.crud.bean"
                            targetProject="./src/main/java">
            
            <property name="enableSubPackages" value="true" />
            
            <property name="trimStrings" value="true" />
        javaModelGenerator>



        <sqlMapGenerator targetPackage="mappers"
                         targetProject="./src/main/resources">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>


        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.angenin.crud.dao"
                             targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>




        <table tableName="tbl_emp" domainObjectName="Employee"/>
        <table tableName="tbl_dept" domainObjectName="Department"/>
    context>
generatorConfiguration>

在test/java目录下新建MBGTest.java,写入

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MBGTest {
     

    public static void main(String[] args) throws Exception {
     
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("src/main/resources/generatorConfig.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);
    }
}

运行后生成对应的bean、dao和mapper文件。
SSM_CRUD练习项目_第21张图片

增添查询员工信息时带上部门信息的业务

在dao/EmployeeMapper.java中添加:

	//  因为逆向工程生成的查询只生成d_id,没有dept表的信息,所以自定义两个查询方法。
	//  自定义,查询时带上dept表里信息
    List<Employee> selectByExampleWithDept(EmployeeExample example);
    Employee selectByPrimaryKeyWithDept(Integer empId);

然后在bean/Employee.java里添加:

	private Department department;

    public Department getDepartment() {
     
        return department;
    }

    public void setDepartment(Department department) {
     
        this.department = department;
    }

最后往resources/mappers/EmployeeMapper.xml中添加:

<!--  自定义返回集合-->
  <resultMap id="WithDeptResultMap" type="com.angenin.crud.bean.Employee">
    <id column="emp_id" jdbcType="INTEGER" property="empId" />
    <result column="emp_name" jdbcType="VARCHAR" property="empName" />
    <result column="gender" jdbcType="CHAR" property="gender" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="d_id" jdbcType="INTEGER" property="dId" />
<!--    指定联合查询出的部门字段的封装-->
    <association property="department" javaType="com.angenin.crud.bean.Department">
      <id column="dept_id" property="deptId"/>
      <result column="dept_name" property="deptName"/>
    </association>
  </resultMap>
  
  <!--  自定义查询集合-->
  <sql id="WithDept_Column_List">
    e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
  </sql>
  
  <!--  自定义查询,查询员工同时带上部门信息-->
  <select id="selectByExampleWithDept" parameterType="com.angenin.crud.bean.EmployeeExample" resultMap="WithDeptResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="WithDept_Column_List" />
    from tbl_emp e left join tbl_dept d on e.d_id=d.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 tbl_emp e left join tbl_dept d on e.d_id=d.dept_id
    where emp_id = #{
     empId,jdbcType=INTEGER}
  </select>

测试CRUD功能

  • 在pop.xml中导入spring的单元测试依赖。

      
      <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-testartifactId>
          <version>5.2.4.RELEASEversion>
          <scope>testscope>
      dependency>
  • 为bean下的Department.java和Employee.java添加有参和无参构造器。
//Department
	public Department() {
     
    }

    public Department(Integer deptId, String deptName) {
     
        this.deptId = deptId;
        this.deptName = deptName;
    }

//==========================
//Employee
	public Employee() {
     
    }

    public Employee(Integer empId, String empName, String gender, String email, Integer dId) {
     
        this.empId = empId;
        this.empName = empName;
        this.gender = gender;
        this.email = email;
        this.dId = dId;
    }
  • 在resources/applicationContext.xml中加入一个可批量插入的sqlSession。

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <constructor-arg name="executorType" value="BATCH"/>
    bean>
  • 在test/java下新建一个MapperTest.java,并写入:
import com.angenin.crud.bean.Department;
import com.angenin.crud.bean.Employee;
import com.angenin.crud.dao.DepartmentMapper;
import com.angenin.crud.dao.EmployeeMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.UUID;

/*测试DepartmentMapper
 * 推荐Spring的项目使用Spring的单元测试,可以自动注入我们需要的组件
 * 1.导入SpringTest模块
 * 2.@ContextConfiguration(locations = {"classpath:applicationContext.xml"})   指定spring配置文件的位置
 */
// - @RunWith(SpringJUnit4ClassRunner.class)指定Test用什么单元测试来运行
// - 如果出现`ExceptionInInitializerError`错误,
//   是因为`SpringJUnit4ClassRunner`要求`JUnit 4.12`或更高,
//   在pop.xml中把junit版本调高即可。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
     "classpath:applicationContext.xml"})
public class MapperTest {
     

    //3.直接autowired要使用的组件即可
    @Autowired
    DepartmentMapper departmentMapper;
    @Autowired
    EmployeeMapper employeeMapper;
    @Autowired
    SqlSession sqlSession;

    @Test
    public void testCRUD(){
     
//        1.插入几个部门
        departmentMapper.insertSelective(new Department(null, "开发部"));
        departmentMapper.insertSelective(new Department(null, "测试部"));
        departmentMapper.insertSelective(new Department(null, "运维部"));

//        2.生成员工数据,测试员工表的插入
        employeeMapper.insertSelective(new Employee(null, "张三", "M", "[email protected]", 1));

//        3.批量插入多个员工;使用可以批量插入操作的sqlSession
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 1000; i++) {
     
            String uid = UUID.randomUUID().toString().substring(0, 5) + i;
            employeeMapper.insertSelective(new Employee(null, uid, "M", uid + "@qq.com", 1));
        }
    }
}

SSM_CRUD练习项目_第22张图片
SSM_CRUD练习项目_第23张图片


CRUD-查询


步骤

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


1. index.jsp只用于跳转到查询页面,所以只留以下内容。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/emps"/>
2. 在pop.xml中引入分页插件。

      <dependency>
          <groupId>com.github.pagehelpergroupId>
          <artifactId>pagehelperartifactId>
          <version>5.1.8version>
      dependency>
3. 在mybatis-config.xml中注册分页插件。

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>
4. 然后在controller下新建一个EmployeeController.java,用于处理员工CRUD请求。
package com.angenin.crud.controller;

import com.angenin.crud.bean.Employee;
import com.angenin.crud.service.EmployeeService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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;

/**
 * 处理员工CRUD请求
 */
@Controller
public class EmployeeController {
     

    @Autowired
    EmployeeService employeeService;

    /**
     * 查询员工数据(分页显示)
     * @param pn 页码
     * @param model
     * @return
     */
    @RequestMapping("/emps")
    public String getEmps(@RequestParam(value="pn", defaultValue = "1")Integer pn, Model model){
     

        //引入PageHelper分页插件
        //查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
        //第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
        PageHelper.startPage(pn, 5, "emp_id asc");
        List<Employee> emps = employeeService.getAll();

        //使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
        PageInfo page = new PageInfo(emps, 5);
        //把page传到下个页面
        model.addAttribute("pageInfo", page);

//        页面跳转到WEB-INF/views下的list.jsp页面(springMVC的视图解析器)
        return "list";
    }
}
5. 在service下新建一个EmployeeService.java
package com.angenin.crud.service;

import com.angenin.crud.bean.Employee;
import com.angenin.crud.dao.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class EmployeeService {
     

    @Autowired
    EmployeeMapper employeeMapper;

    /**
     * 查询所有员工
     * @return
     */
    public List<Employee> getAll() {
     
        return employeeMapper.selectByExampleWithDept(null);
    }
}
6. 测试分页查询的数据

在test/java下新建一个MvcTest.java用于测试。

import com.angenin.crud.bean.Employee;
import com.github.pagehelper.PageInfo;
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.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测试模块提供的测试请求功能,测试crud请求的正确性
 */
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration    //获取springmvc的ioc容器
@ContextConfiguration(locations = {
     "classpath:applicationContext.xml", "classpath:springmvc.xml"})
public class MvcTest {
     

    //传入SpringMVC的IOC
    @Autowired
    WebApplicationContext context;

    //虚拟mvc请求,获取到处理结果
    MockMvc mockMvc;

    @Before     //使用junit的Before
    public void initMockMvc(){
     
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testPage() throws Exception {
     
        //模拟发送get请求     param为请求传入的键值对
        //andReturn为获取返回值
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "1")).andReturn();

        //请求成功以后,请求域中会有pageInfo
        MockHttpServletRequest request = result.getRequest();
        PageInfo pi = (PageInfo) request.getAttribute("pageInfo");

        System.out.println("当前页码:" + pi.getPageNum());
        System.out.println("总页码:" + pi.getPages());
        System.out.println("总记录数:" + pi.getTotal());
        System.out.print("在页面需要连续显示的页码:");
        int[] nums = pi.getNavigatepageNums();
        for (int num : nums) {
     
            System.out.print(" " + num);
        }
        System.out.println();

        //获取员工数据
        List<Employee> list = pi.getList();
        for (Employee employee : list) {
     
            System.out.println("ID: " + employee.getEmpId() + ",name: " + employee.getEmpName());
        }
    }
}

测试效果:
SSM_CRUD练习项目_第24张图片
把传入的键值对改为5,也没有问题。
SSM_CRUD练习项目_第25张图片

7. 在webapp/WEB-INF/views里新建一个list.jsp页面,为员工列表页面。

编写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>

    <%
        //获取当前项目名(得到的是 /加项目名(例:/ssm_crud) ,所以使用的时候前面不用加/而后面需要)
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
<%-- web的路径:
       - 不以/开始的相对路径,找资源,以当前资源的路径为基准,经常出问题。
       - 以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306)再需要加上项目名(项目名也不是写死的)
            http://localhost:8080/ssm_crud
 --%>
    <script type="text/javascript" src="${ APP_PATH }/static/js/jquery-3.4.1.min.js">script>
    <link href="${ APP_PATH }/static/bootstrap-dist/css/bootstrap.min.css" rel="stylesheet"/>
    <script src="${ APP_PATH }/static/bootstrap-dist/js/bootstrap.min.js">script>
head>
<body>
<%--    搭建显示页面(官方的全局CSS样式的栅格系统) --%>
    <div class="container">
<%--        标题--%>
        <div class="row">
            <div class="col-md-12">
                <h1>SSM_CRUDh1>
            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>empIdth>
                        <th>empNameth>
                        <th>genderth>
                        <th>emailth>
                        <th>deptNameth>
                        <th>操作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-info btn-sm">
                                    <span class="glyphicon glyphicon-pencil" aria-hidden="true">span>
                                    编辑
                                button>
                                <button class="btn btn-danger btn-sm">
                                    <span class="glyphicon glyphicon-trash" aria-hidden="true">span>
                                    删除
                                button>
                            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">«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">»span>
                                a>
                            li>
                        c:if>
                        <%--尾页--%>
                            <li><a href="${ APP_PATH }/emps?pn=${ pageInfo.pages }">尾页a>li>
                    ul>
                nav>
            div>
        div>
    div>
body>
html>
效果图

实现了数据的查询和分页以及分页的跳转功能。
SSM_CRUD练习项目_第26张图片
但只能适用于PC浏览器和服务器的交互,实际上发送请求的可能是安卓或iOS,所以这里我们把数据用josn的格式用ajax发送给客户端。


查询-ajax


步骤

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


1. 注释掉EmployeeController.java中的getEmps方法,新建一个getEmpsWithJson方法。
	/**
     * 查询员工数据(分页显示)
     * json和ajax
     * 导入jackson包
     * @param pn 页码
     * @return
     */
    @RequestMapping("/emps")
    @ResponseBody
    public PageInfo getEmpsWithJson(@RequestParam(value="pn", defaultValue = "1")Integer pn){
     
        //引入PageHelper分页插件
        //查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
        //第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
        PageHelper.startPage(pn, 5, "emp_id asc");
        List<Employee> emps = employeeService.getAll();

        //使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
        PageInfo page = new PageInfo(emps, 5);

        return page;
    }
2. 在pop.xml中引入json的依赖

      
      <dependency>
          <groupId>com.fasterxml.jackson.coregroupId>
          <artifactId>jackson-databindartifactId>
          <version>2.10.2version>
      dependency>

启动后页面显示json格式的数据。
SSM_CRUD练习项目_第27张图片
因为PageInfo返回到页面不清楚是成功还是失败,所以我们还需要在bean中定义一个提示信息的类。

3. 在bean中定义一个Msg.java用于请求的结果进行处理和返回
package com.angenin.crud.bean;

import java.util.HashMap;
import java.util.Map;

public class Msg {
     

    //状态码   100:成功;200:失败
    private int code;
    //提示信息
    private String msg;

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

    //请求成功方法
    public static Msg success(){
     
        Msg result = new Msg();
        result.setCode(100);
        result.setMsg("处理成功!");
        return result;
    }

    //请求失败方法
    public static Msg fail(){
     
        Msg result = new Msg();
        result.setCode(200);
        result.setMsg("处理失败!");
        return result;
    }

    //添加信息的方法
    public 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;
    }
}

并修改getEmpsWithJson方法。

public Msg getEmpsWithJson(@RequestParam(value="pn", defaultValue = "1")Integer pn){
     
        //引入PageHelper分页插件
        //查询前调用分页插件,之后的查询就是分页查询(页码和每页显示的数据数)
        //第三个参数:emp_id asc 为指定排序的规则,按emp_id正序排序(不加后面插入数据后排序可能有问题)
        PageHelper.startPage(pn, 5, "emp_id asc");
        List<Employee> emps = employeeService.getAll();

        //使用pageInfo包装查询后的结果,传入查询结果和连续显示的页数
        PageInfo page = new PageInfo(emps, 5);

        return Msg.success().add("pageInfo", page);
    }

重新运行
SSM_CRUD练习项目_第28张图片

4. 在mybatis-config.xml中给配置分页插件配置一个参数
!--    注册PageInterceptor分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">

            <property name="reasonable" value="true"/>
        plugin>
    plugins>
5. 舍弃list.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>

    <%
        //获取当前项目名(得到的是 /加项目名(例:/ssm_crud) ,所以使用的时候前面不用加/而后面需要)
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
    <%-- web的路径:
           - 不以/开始的相对路径,找资源,以当前资源的路径为基准,经常出问题。
           - 以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306)再需要加上项目名(项目名也不是写死的)
                http://localhost:8080/ssm_crud
     --%>
    <script type="text/javascript" src="${ APP_PATH }/static/js/jquery-3.4.1.min.js">script>
    <%--    下载的bootstrap前端框架有问题,用第二种方式引入--%>
    <%--    <link href="${ APP_PATH }/static/bootstrap-dist/css/bootstrap.min.css" rel="stylesheet"/>--%>
    <%--    <script src="${ APP_PATH }/static/bootstrap-dist/js/bootstrap.min.js">script>--%>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous">script>
head>
<body>
    <%--    搭建显示页面(官方的全局CSS样式的栅格系统) --%>
    <div class="container">
        <%-- 标题--%>
        <div class="row">
            <div class="col-md-12">
                <h1>SSM_CRUDh1>
            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>empIdth>
                            <th>empNameth>
                            <th>genderth>
                            <th>emailth>
                            <th>deptNameth>
                            <th>操作th>
                        tr>
                    thead>
                    <tbody>tbody>
                table>
            div>
        div>
        <%-- 显示分页信息--%>
        <div class="row">
            <%-- 分页文字信息--%>
            <div class="col-md-6" id="page_info_area">div>
            <%-- 分页条信息--%>
            <div class="col-md-6" id="page_nav_area">div>
        div>
    div>
    <script type="text/javascript">
        //1.页面加载完成后,发送一个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_emps_table(result);
                    //2.解析并显示分页信息
                    build_page_info(result);
                    //3.解析并显示分页条数据
                    build_page_nav(result);
                }
            });
        }

        //解析显示员工信息
        function build_emps_table(result) {
      
            //每次页面跳转都先清空原先的员工数据
            $("#emps_table tbody").empty();

            var emps = result.extend.pageInfo.list;
            //jquery自带的遍历
            $.each(emps, function (index, item) {
      
                //员工信息单元格
                var empIdTd = $("").append(item.empId);
                var empNameTd = $("").append(item.empName);
                var genderTd = $("").append(item.gender == 'M' ? "男" : "女");
                var emailTd = $("").append(item.email);
                var deptNameTd = $("").append(item.department.deptName);
                //修改删除按钮,在同一个单元格内
                var editBtn = $("").addClass("btn btn-info btn-sm edit_btn")
                        .append($("").addClass("glyphicon glyphicon-pencil"))
                        .append("编辑");
                var delBtn = $("").addClass("btn btn-danger btn-sm delete_btn")
                        .append($("").addClass("glyphicon glyphicon-trash"))
                        .append("删除");
                var btnTd = $("").append(editBtn).append(" ").append(delBtn);
                //把相同员工的单元格添加到同一行
                $("").append(empIdTd)
                    .append(empNameTd)
                    .append(genderTd)
                    .append(emailTd)
                    .append(deptNameTd)
                    .append(btnTd)
                    .appendTo("#emps_table tbody"); //添加到id为emps_table的表里的tbody中
            });
        }

        //解析显示分页信息
        function build_page_info(result) {
      
            //每次页面跳转都先清空分页信息
            $("#page_info_area").empty();

            $("#page_info_area").append("当前 " + result.extend.pageInfo.pageNum + " 页," +
                "总 " + result.extend.pageInfo.pages  + " 页," +
                "总 " + result.extend.pageInfo.total + " 条记录");
        }

        //解析显示分页条
        function build_page_nav(result) {
      
            //每次页面跳转都先清空table表格数据
            $("#page_nav_area").empty();

            var ul = $("
    "
    ).addClass("pagination"); //首页 var firstPageLi = $("
  • "
    ).append($("").append("首页").attr("href", "#")); //上一页 var prePageLi = $("
  • "
    ).append($("").append("«").attr("href", "#")); //如果没有上一页,给首页和前一页按钮增加不能点击的效果 if(!result.extend.pageInfo.hasPreviousPage){ 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 = $("
  • "
    ).append($("").append("»").attr("href", "#")); //尾页 var lastPageLi = $("
  • "
    ).append($("").append("尾页").attr("href", "#")); //如果没有下一页,给后一页和尾页按钮增加不能点击的效果 if(!result.extend.pageInfo.hasNextPage){ 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); //5个连续显示的页码 $.each(result.extend.pageInfo.navigatepageNums, function (index, item) { var numLi = $("
  • "
    ).append($("").append(item).attr("href", "#")); //如果循环到的页码是当前页码 if(item == result.extend.pageInfo.pageNum){ numLi.addClass("active"); } //为页码按钮添加点击事件 numLi.click(function () { //页面跳转到对应的页数 to_page(item); }); //添加页码 ul.append(numLi); }) //添加下一页和尾页 ul.append(nextPageLi).append(lastPageLi); //把ul添加到nav中 var navEle = $("").append(ul).appendTo("#page_nav_area"); }
    script> body> html>
    效果图

    实现效果与第一种做法一致。
    SSM_CRUD练习项目_第29张图片


    CRUD-新增


    步骤

    1、在 index.jsp页面点击”新增”按钮
    2、弹出增对话框(bootstrap框架js插件的模态框里的动态实例)
    3、到数据库查询部门列表,显示在对话框中
    4、用户输入数据后进行校验(jquery前端校验,ajax用户名重复校验,重要数据(后端校验JSR303),唯一约束)
    5、完成保存


    1. 为index.jsp的新增按钮增加弹窗效果

    使用bootstrap官网js插件的模态框。
    SSM_CRUD练习项目_第30张图片

    1. 为新增按钮添加一个id,顺便为删除按钮也添加一个id。
    ...
    <%--  按钮--%>
            <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_modal_btn">删 除button>
                div>
            div>
            <%--  显示表格数据--%>	
            ...
    
    1. 在index.jsp的body里添加模态框代码。
    <%--    员工添加按钮的模态框   --%>
        <div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×span>button>
                        <%--       弹窗标题             --%>
                        <h4 class="modal-title" id="myModalLabel">员工添加h4>
                    div>
                    <%--   弹窗内容     --%>
                    <div class="modal-body">
                        <%--      表单    --%>
                        <%--      empName    --%>
                        <form class="form-horizontal">
                            <div class="form-group">
                                <label class="col-sm-2 control-label">empNamelabel>
                                <div class="col-sm-10">
                                    <%--     员工姓名不可修改     --%>
                                    <p class="form-control-static" id="empName_update_static">p>
                                div>
                            div>
                            <%--      email    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">emaillabel>
                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="email" id="email_add_input" placeholder="[email protected]">
                                div>
                            div>
                            <%--      gender    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">emaillabel>
                                <div class="col-sm-10">
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender1_add_input" value="M" checked>label>
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender2_add_input" value="F">label>
                                div>
                            div>
                            <%--      deptName    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">deptNamelabel>
                                <div class="col-sm-4">
                                    <%--      提交部门id即可    --%>
                                    <select class="form-control" name="dId">select>
                                div>
                            div>
                        form>
                    div>
                    <div class="modal-footer">
                        <%--        弹窗关闭按钮            --%>
                        <button type="button" class="btn btn-default" data-dismiss="modal">关闭button>
                        <%--        弹窗保存按钮            --%>
                        <button type="button" class="btn btn-primary">保存button>
                    div>
                div>
            div>
        div>
    
    1. 在Service包中创建一个名为DepartmentService.java的类,用于处理DepartmentController.java发送过来的业务。
    package com.angenin.crud.service;
    
    import com.angenin.crud.bean.Department;
    import com.angenin.crud.dao.DepartmentMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import java.util.List;
    
    @Service
    public class DepartmentService {
         
    
        @Autowired
        private DepartmentMapper departmentMapper;
    
        public List<Department> getDepts() {
         
    //        查出所有部门信息并返回给对应的controller
            return departmentMapper.selectByExample(null);
        }
    }
    
    1. 在Controller包中新建一个名为DepartmentController.java的控制器,用于处理和部门有关的请求,在里面新建一个名为的方法,用于返回查询到的所有部门信息。
    package com.angenin.crud.controller;
    
    import com.angenin.crud.bean.Department;
    import com.angenin.crud.bean.Msg;
    import com.angenin.crud.service.DepartmentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import java.util.List;
    
    /**
     * 处理和部门有关的请求
     */
    @Controller
    public class DepartmentController {
         
    
        @Autowired
        private DepartmentService departmentService;
    
        /**
         * 返回所有部门的信息
         */
        @RequestMapping("/depts")
        @ResponseBody
        public Msg getDepts(){
         
            //查出所有的部门信息
            List<Department> list = departmentService.getDepts();
            return Msg.success().add("depts", list);
        }
    }
    
    1. 在index.jsp页面底部的script中为新增按钮添加点击弹窗事件。
    		//新增按钮的点击弹窗事件
            $("#emp_add_modal_btn").click(function () {
         
                //发送ajax请求,查出部门信息,显示在下拉列表中
                getDepts("#empAddModal select");
                //调用模态框
                $("#empAddModal").modal({
         
                    backdrop: "static"
                });
            });
    
            //查出所有部门信息并显示在下拉列表中
            function getDepts(ele){
         
            	//清空下拉列表
                $(ele).empty();
                $.ajax({
         
                    url: "${APP_PATH}/depts",
                    type: "get",
                    success: function (result) {
         
                        //显示部门信息到下拉列表中
                        $.each(result.extend.depts, function () {
           //不传参使用this代表当前被遍历的对象
                            var optionEle = $("").append(this.deptName)
                                .attr("value", this.deptId).appendTo("ele");
                        });
                    }
                });
            }
    
    效果图

    SSM_CRUD练习项目_第31张图片

    2. 编写新建按钮的弹窗的保存按钮的保存效果
    1. 在EmployeeService.java中添加一个名为saveEmp的方法,用于保存新增的员工信息。
    	/**
         * 员工保存方法
         * @param employee
         */
        public void saveEmp(Employee employee) {
         
            //因为我们的员工id是自增的,所有使用insertSelective有选择的插入,而不是insert。
            employeeMapper.insertSelective(employee);
        }
    
    1. 在EmployeeController.java中新增一个名为saveEmp的方法,用于保存新增的员工信息。
        /**
         * 保存新增的员工信息
         * Rest风格的URI,我们规定post的请求为保存请求
         */
        @RequestMapping(value = "/emp", method = RequestMethod.POST)
        @ResponseBody
        public Msg saveEmp(Employee employee){
           //接收页面表单传递过来的employee对象信息
            employeeService.saveEmp(employee);
            return Msg.success();
        }
    
    1. 在index.jsp页面中为弹窗的保存按钮添加一个id=“emp_save_btn”。

    2. 在index.jsp页面底部的script中添加一个全局变量var totalRecord;,为保存后的页面跳转做准备,此全局变量在分页信息那赋值。

    
       //定义一个全局变量:总记录数和当前页(在分页信息那赋值)
       var totalRecord, currentNum;
    
    //----------------------------
    
    	function build_page_info(result) {
         
    		...
    		//为全局变量赋值
    		totalRecord = result.extend.pageInfo.total;
    		currentNum = result.extend.pageInfo.pageNum;
    	}
    
    1. 在index.jsp页面底部的script中为保存按钮添加点击保存事件。
    		//弹窗的保存按钮的点击保存事件
            $("#emp_save_btn").click(function () {
         
                //调用JQuery的serialize,系列化表单里的员工信息
                //系列化后的字符串:empName=cat&email=cat%40qq.com&gender=F&dId=3
                // alert($("#empAddModal form").serialize());
    
                //发送ajax请求把保存表单内新增的员工信息提交给服务器
                $.ajax({
         
                    url: "${APP_PATH}/emp",
                    type: "post",
                    data: $("#empAddModal form").serialize(),
                    success: function(result){
         
                        // alert(result.msg);
                        //当保存成功:
                        //1.关闭弹窗
                        $("#empAddModal").modal('hide');
                        //2.跳转到最后一页
                        // (因为我们已经添加了bootstrap的合理化参数,所以当超过总页数将会跳转到最后一页)
                        to_page(totalRecord);
                    }
                });
            });
    
    效果图

    SSM_CRUD练习项目_第32张图片
    SSM_CRUD练习项目_第33张图片

    3. 问弹窗表单增加校验功能

    提交的数据需要满足才可保存:

    • 用户名合法
    • 邮箱合法
    • 员工姓名不重复(只是示例,练习,可把员工姓名看成用户名就不会觉得逻辑有问题了)
    校验员工姓名和邮箱
    1. 在弹窗的保存按钮的点击保存事件的中最上面添加,先进行数据的校验。
    	//对提交的数据进行校验
        if(!validate_add_form()){
         
             return false;
         }
    
    1. 在script标签中新建一个validate_add_form的方法,用于数据的校验。
            //校验表单数据
            function validate_add_form(){
         
                //拿到数据,用jQuery的正则表达式进行校验
                //校验员工姓名
                var empName = $("#empName_add_input").val();
                //正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文)
                var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
                if(!regName.test(empName)){
         
                    alert("用户名可以是2-5位中文或6-16个英文和数字的组合!");
                    return false;
                }
    
                //校验邮箱
                var email = $("#email_add_input").val();
                var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
                if(!regEmail.test(email)){
         
                    alert("邮箱格式不正确!");
                    return false;
                }
    
                //校验通过
                return true;
            }
    

    效果:
    SSM_CRUD练习项目_第34张图片

    1. 使用bootstrap官网全局css样式美化错误提醒。
      SSM_CRUD练习项目_第35张图片

      1. 在body标签中,弹窗代码内的表单的empName和email位置的下添加,用于错误时显示的提示信息。
      2. 新建一个show_validate_msg方法,用于校验的提示信息。
      //校验的提示信息
          //ele校验的元素,status校验状态,msg提示信息
          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);
              }
          }
      
      1. 修改js中校验表单数据方法
      //校验表单数据
          function validate_add_form(){
             
              //拿到数据,用jQuery的正则表达式进行校验
              //校验员工姓名
              var empName = $("#empName_add_input").val();
              //正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文)
              var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
              if(!regName.test(empName)){
             
                  // alert("用户名可以是2-5位中文或6-16个英文和数字的组合!");
                  //显示校验的信息
                  show_validate_msg("#empName_add_input", "error", "用户名可以是2-5位中文或6-16个英文和数字的组合!");
      
                  return false;
              }else{
             
                  show_validate_msg("#empName_add_input", "success", "");
              }
      
              //校验邮箱
              var email = $("#email_add_input").val();
              var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
              if(!regEmail.test(email)){
             
                  // alert("邮箱格式不正确!");
                  //显示校验的信息
                  show_validate_msg("#email_add_input", "error", "邮箱格式不正确!");
      
                  return false;
              }else{
             
                  show_validate_msg("#email_add_input", "success", "");
              }
      
              //校验通过
              return true;
          }
      
    2. 为了给用户更好的体验效果,我们再给输入文本框增加一个失去焦点事件,让用户输入完文本后,就发起校验,而不用等到去点击保存才提示,顺便解决了用户名和邮箱都不合法,只有用户名提示错误信息。(当然保存的校验也要保留)

      1. 把validate_add_form方法拆为validate_add_form_empName和validate_add_form_email两个方法。
      //校验表单员工名
          function validate_add_form_empName(ele){
             
              //拿到数据,用jQuery的正则表达式进行校验
              //校验员工姓名
              var empName = $(ele).val();
              //正则:允许(6到16位,允许a-z A-Z 0-9 _ - 2到5个中文)
              var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
              if(!regName.test(empName)){
             
                  // alert("用户名可以是2-5位中文或6-16个英文和数字的组合!");
                  //显示校验的信息
                  show_validate_msg(ele, "error", "用户名可以是2-5位中文或6-16个英文和数字的组合!");
      
                  return false;
              }else{
             
                  show_validate_msg(ele, "success", "");
              }
              //校验通过
              return true;
          }
          //校验表单邮箱
          function validate_add_form_email(ele) {
             
              //校验邮箱
              var email = $(ele).val();
              var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
              if(!regEmail.test(email)){
             
                  // alert("邮箱格式不正确!");
                  //显示校验的信息
                  show_validate_msg(ele, "error", "邮箱格式不正确!");
      
                  return false;
              }else{
             
                  show_validate_msg(ele, "success", "");
              }
              //校验通过
              return true;
          }
      
      1. 把弹窗的保存按钮的点击保存事件中的判断稍做修改。
      //弹窗的保存按钮的点击保存事件
      $("#emp_save_btn").click(function () {
             
            //对提交的数据进行校验
            if(!validate_add_form_empName("#empName_add_input") || !validate_add_form_email("#email_add_input")){
             
          		alert("请正确输入信息!");
                return false;
            }
      
      1. 在js中新建两个文本框的失去焦点事件。
          //员工名输入框失去焦点校验事件(弹窗)
          $("#empName_add_input").blur(function () {
             
              validate_add_form_empName("#empName_add_input");
          });
          //邮箱输入框失去焦点校验事件(弹窗)
          $("#email_add_input").blur(function () {
             
              validate_add_form_email("#email_add_input");
          });
      
      1. 在新增按钮的点击弹窗事件中增加表单重置功能,每次打开都是初始状态。
      //清除表单数据(表单重置)
      //清空文本框内容
      $("#empAddModal form")[0].reset();
      //去除表单样式
      $("#empAddModal form").find("*").removeClass("has-success has-error");
      //清空有带有help-block类的内容(即错误信息)
      $("#empAddModal form").find(".help-block").text("");
      
    校验员工姓名是否重复
    1. 在DepartmentExample.java中新建一个查询用户名是否可用的方法。
    	/**
         * 查询用户名是否已存在
         * @param empName
         * @return true为可用(输入的用户名不存在)
         */
        public boolean checkUser(String empName) {
         
    
            //查询条件
            EmployeeExample example = new EmployeeExample();
            EmployeeExample.Criteria criteria = example.createCriteria();
            //查询数据库中emp_name和传参empName相同的记录数
            criteria.andEmpNameEqualTo(empName);
    
            //countByExample方法返回符合条件的记录数
            long count = employeeMapper.countByExample(example);
            return count == 0;
        }
    
    1. 在EmployeeController.java中新建方法。
    	/**
         * 校验用户名是否已存在
         */
        @RequestMapping("/checkuser")
        @ResponseBody
        public Msg checkuser(@RequestParam("empName")String empName){
         
            boolean b = employeeService.checkUser(empName);
            if(b){
         
                //用户名可用
                return Msg.success();
            }else{
         
                //用户名不可用
                return Msg.fail();
            }
        }
    
    1. 在index.jsp的js中新建一个方法。
    		//检验用户名是否可用
            function validate_usable_empName(ele) {
         
                //获取输入框的内容
                var empName = $(ele).val();
                //发送ajax请求校验用户名是否存在
                $.ajax({
         
                    url: "${APP_PATH}/checkuser",
                    data: "empName=" + empName,
                    type: "get",
                    success: function (result) {
         
                        //判断是否成功(100为成功,200为失败)
                        if(100 == result.code){
         
                            show_validate_msg(ele, "success", "用户名可用");
                            //并给保存按钮添加一个自定义属性,success代表用户名可用
                            $("#emp_save_btn").attr("ajax-va", "success");
                        }else{
         
                            show_validate_msg(ele, "error", "用户名已存在!");
                            //并给保存按钮添加一个自定义属性,fail代表用户名不可用
                            $("#emp_save_btn").attr("ajax-va", "error");
                        }
                    }
                });
            }
    
    1. 在js的validate_add_form_empName方法中的else里中调用validate_usable_empName方法,实现用户名输入框失去焦点后先校验格式,格式符合再校验用户名是否可用。

    2. 因为用户名通过格式校验后,用户名是否可用保存按钮不知道,所以需要在保存按钮的点击事件里数据校验判断之下再加一个判断。

    	 //判断用户名是否通过可用性校验
    	 if($(this).attr("ajax-va") == "error"){
         
    	      //没通过,不保存
    	      alert("请正确输入信息!");
    	      return false;
    	  }
    
    后端校验数据
    1. 对用户名进行校验

      1. 在EmployeeController.java的checkuser中也进行用户名的校验。
         /**
           * 校验用户名是否已存在
           */
          @RequestMapping("/checkuser")
          @ResponseBody
          public Msg checkuser(@RequestParam("empName")String empName){
             
              //后端判断用户名的合法性
              String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
              //如果匹配失败,直接返回
              if(!empName.matches(regx)){
             
                  return Msg.fail().add("va_msg", "用户名必须是6-16个英文和数字或2-5位中文的组合!");
              }
      
              //数据库用户名重复校验
              boolean b = employeeService.checkUser(empName);
              if(b){
             
                  //用户名可用
                  return Msg.success();
              }else{
             
                  //用户名不可用
                  return Msg.fail().add("va_msg", "用户名已存在!");
              }
          }
      
      1. index.jsp里的validate_usable_empName方法中,ajax请求的success的else中show_validate_msg的错误信息就改为result.extend.va_msg,从后端拿到的错误信息。
      function validate_usable_empName(ele) {
             
      	...
      	}else{
             
      		//错误信息从后端返回的数据中获取
           	show_validate_msg(ele, "error", result.extend.va_msg);
      	...
      }
      
    2. JSR303校验

      1. 导入依赖
        
        
        <dependency>
            <groupId>org.hibernate.validatorgroupId>
            <artifactId>hibernate-validatorartifactId>
            <version>6.1.2.Finalversion>
        dependency>
      
      1. 在Employee.java类的empName和email属性上加上校验注解。
      //@Pattern(regexp = "", message 错误信息) 自定义校验注解
      @Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",
                  message = "用户名必须是6-16个英文和数字或2-5位中文的组合!")
      private String empName;
      
      //@Email  //邮箱校验注解
      @Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",
                  message = "邮箱格式不正确!")
      private String email;
      
      1. 修改EmployeeController.java中的saveEmp方法。
      /**
       * 保存新增的员工信息
       * Rest风格的URI,我们规定post的请求为保存请求
       * @param employee  页面表单传递过来的employee对象信息
       * @param result    封装校验的结果
       * @return
       */
      @RequestMapping(value = "/emp", method = RequestMethod.POST)
      @ResponseBody   //加上@Valid注解的参数需要校验
      public Msg saveEmp(@Valid Employee employee, BindingResult result){
             
          //进行校验
          if(result.hasErrors()){
             
              //校验失败
              Map<String, Object> map = new HashMap<>();
              List<FieldError> errors = result.getFieldErrors();
              for (FieldError fieldError : errors) {
             
                  //获取错误的字段名
                  System.out.println("错误的字段名:" + fieldError.getField());
                  //获取错误的信息
                  System.out.println("错误信息:" + fieldError.getDefaultMessage());
                  //把错误信息保存到map中
                  map.put(fieldError.getField(), fieldError.getDefaultMessage());
              }
      
              return Msg.fail().add("errorFields", map);
          }else{
             
              //校验成功
              employeeService.saveEmp(employee);
              System.out.println(employee);
              return Msg.success();
          }
      }
      
      1. 修改index.jsp中弹窗的保存按钮点击事件中ajax请求的success方法。
      success: function(result){
             
      
           if(100 == result.code){
             
               //当保存成功:
               //1.关闭弹窗
               $("#empAddModal").modal('hide');
               //2.跳转到最后一页
               // (因为我们已经添加了bootstrap的合理化参数,所以当超过总页数将会跳转到最后一页)
               to_page(totalRecord);
      
           }else{
             
               //显示失败信息,哪个错误就显示哪个
               if(undefined != result.extend.errorFields.empName){
             
                   //显示员工名字的错误信息
                   show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                   alert(result.extend.errorFields.empName);
               }
               if(undefined != result.extend.errorFields.email){
             
                   //显示邮箱的错误信息
                   show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                   alert(result.extend.errorFields.email);
               }
      
           }
       }
      

    CRUD-修改


    步骤

    1、点击编辑
    2、弹出用户修改的模态框(显示用户信息)
    3、点击更新,完成用户修改


    1. 实现点击编辑弹出员工信息模态框
    1. 在index.jsp中再添加一个模态框。
        <%--   员工修改的模态框   --%>
        <div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×span>button>
                        <%--       弹窗标题             --%>
                        <h4 class="modal-title">员工修改h4>
                    div>
                    <%--   弹窗内容     --%>
                    <div class="modal-body">
                        <%--      表单    --%>
                        <%--      empName    --%>
                        <form class="form-horizontal">
                            <div class="form-group">
                                <label class="col-sm-2 control-label">empNamelabel>
                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="empName" id="empName_update_input" placeholder="empName">
                                    <span class="help-block">span>
                                div>
                            div>
                            <%--      email    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">emaillabel>
                                <div class="col-sm-10">
                                    <input type="text" class="form-control" name="email" id="email_update_input" placeholder="[email protected]">
                                    <span class="help-block">span>
                                div>
                            div>
                            <%--      gender    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">emaillabel>
                                <div class="col-sm-10">
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender1_update_input" value="M" checked>label>
                                    <label class="radio-inline">
                                        <input type="radio" name="gender" id="gender2_update_input" value="F">label>
                                div>
                            div>
                            <%--      deptName    --%>
                            <div class="form-group">
                                <label class="col-sm-2 control-label">deptNamelabel>
                                <div class="col-sm-4">
                                    <%--      提交部门id即可    --%>
                                    <select class="form-control" name="dId">select>
                                div>
                            div>
                        form>
                    div>
                    <div class="modal-footer">
                        <%--        弹窗关闭按钮            --%>
                        <button type="button" class="btn btn-default" data-dismiss="modal">关闭button>
                        <%--        弹窗保存按钮            --%>
                        <button type="button" class="btn btn-primary" id="emp_update_btn">更新button>
                    div>
                div>
            div>
        div>
    
    1. 把getDepts修改为有参函数。
      SSM_CRUD练习项目_第36张图片

    2. 在EmployeeService.java中新建一个名为getEmp的方法,用于根据id查询员工信息。

    	/**
         * 根据id查询员工信息
         * @param id
         * @return
         */
        public Employee getEmp(Integer id) {
         
            Employee employee = employeeMapper.selectByPrimaryKey(id);
            return employee;
        }
    
    1. 在EmployeeController.java新建一个名为getEmp的方法,用于查询员工信息。
    	/**
         * 查询员工信息
         * 查询指定是get请求
         * @param id
         * @return
         */
        @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
        @ResponseBody
        public Msg getEmp(@PathVariable("id")Integer id){
         
            //查询指定的员工信息
            Employee employeee = employeeService.getEmp(id);
            return Msg.success().add("emp", employeee);
        }
    
    1. 解析显示员工信息的方法build_emps_table中的循环里,为修改增加一个自定义属性,就能让每个按钮和对应的员工绑定起来,同理,在这里先把删除按钮也一起设置。
    function build_emps_table(result) {
         
    	...
    	$.each(){
         
    		...
    			//修改删除按钮,在同一个单元格内
    			var editBtn = $("<butt..
    			//为编辑按钮添加一个自定义属性,表示当前员工id
    			editBtn.attr("edit-id", item.empId);
    			var delBtn...
    			//同理,也为删除按钮添加一个自定义属性
    			delBtn.attr("del-id", item.empId);
    		...
    	}
    	...
    }
    
    1. 为修改按钮添加点击事件。
    	//因为在按钮创建之前就绑定click,所以绑定不了
        //解决:在创建按钮后在绑定 或 绑定点击.live()
        //jquery新版用on代替了live
        //为修改按钮添加点击事件
        $(document).on("click", ".edit_btn", function () {
         
            //查出并显示部门信息
            getDepts("#empUpdateModal select");
            //查出并显示员工信息,$(this)当前被点击的编辑按钮
            getEmp($(this).attr("edit-id"));
    
    		//把员工的id传递给模态框的更新按钮
            $("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
            
            //调用模态框
            $("#empUpdateModal").modal({
         
                backdrop: "static"
            });
        });
    
    1. js中新建一个查询员工信息的方法。
    	//查询员工信息
        function getEmp(id){
         
            $.ajax({
         
                url: "${APP_PATH}/emp/" + id,
                type: "get",
                success: function (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]);
                }
         });
    

    完成员工对应信息在模态框显示。

    2. 实现点击弹窗内更新按钮修改员工信息
    1. js中为修改模态框邮箱输入框新建失去焦点校验事件,用于在用户修改邮箱后校验邮箱的合法性。
    //修改模态框邮箱输入框失去焦点校验事件(弹窗)
    $("#email_add_input").blur(function () {
         
        validate_add_form_email("#email_update_input");
    });
    
    1. 并在修改按钮事件里添加清空前一次校验样式。
    	$(document).on("click", ".edit_btn", function () {
         
                //清除当前元素的校验状态
                $("#email_update_input").parent().removeClass("has-success has-error");
                $("#email_update_input").next("span").text("");
           		...
         }
    
    1. 在EmployeeService.java中新建一个updateEmp方法,用于根据主键有选择的更新员工信息。
        /**
         * 根据主键有选择的更新员工信息
         * @param employee
         */
        public void updateEmp(Employee employee) {
         
            employeeMapper.updateByPrimaryKeySelective(employee);
        }	
    
    1. 在EmployeeController.java中新建一个saveEmp方法,用于员工的更新。
        /**
         * 员工更新
         * 更新指定put请求
         * @param employee
         * @return
         */
        @RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
        @ResponseBody
        public Msg saveEmp(Employee employee){
         
            //更新员工信息
            employeeService.updateEmp(employee);
            return Msg.success();
        }
    
    1. 然后为模态框的更新按钮添加点击事件。
     //更新按钮的点击事件
     $("#emp_update_btn").click(function () {
         
         //校验邮箱信息
         if (!validate_add_form_email("#email_update_input")){
         
             alert("邮箱格式不正确,请输入正确的邮箱");
             return false;
         }
    
         //发送ajax请求更新员工信息
         $.ajax({
         
             url: "${APP_PATH}/emp/" + $(this).attr("edit-id"),
             //第一种方法:
             // 如果ajax直接发put请求,请求体中的数据,request.getgetParameter("empName")拿不到
             // tomcat发现是put请求,就不会封装数据为map,只有post形式的请求才会封装请求体为map
             // 所以要在web.xml中注册FormContentFilter过滤器,支持put和delete请求
             //第二种方法:
             // ajax发送post请求,并在发送的data加上 "_method=put"
             // HiddenHttpMethodFilter把post转为put
             type: "put",
             data: $("#empUpdateModal form").serialize(),
             success: function (result) {
         
                 //关闭对话框
                 $("#empUpdateModal").modal("hide");
                 //回到本页面(刷新)
                 to_page(currentPage);
             }
         });
    
     });
    

    CRUD-删除


    步骤

    1、单个删除
    2、多个删除


    1. 实现单个删除
    1. 在EmployeeService.java中新建deleteEmp方法,用于根据id删除指定员工信息。
    	/**
         * 根据id删除指定员工信息
         * @param id
         */
        public void deleteEmp(Integer id) {
         
            employeeMapper.deleteByPrimaryKey(id);
        }
    
    1. 在EmployeeController.java中新建deleteEmp方法,用于删除单个员工信息。
        /**
         * 删除单个员工信息
         * 删除指定delete请求
         * @param id
         * @return
         */
        @RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE)
        public Msg deleteEmpById(@PathVariable("id")Integer id){
         
            //按照id删除指定员工信息
            employeeService.deleteEmp(id);
            return Msg.success();
        }
    
    1. 在js中为员工对应的删除按钮添加点击事件(单个删除)。
    //为员工对应的删除按钮添加点击事件(单个删除)
            $(document).on("click", ".delete_btn", function () {
         
                //获取删除的员工姓名
                var empName = $(this).parents("tr").find("td:eq(1)").text();
                //获取删除的员工id
                var empId = $(this).attr("del-id");
    
                //弹出是否确认删除提示
                if(confirm("确定要删除【" + empName + "】吗?")){
         
                    //确认,发送ajax请求删除员工
                    $.ajax({
         
                        url: "${APP_PATH}/emp/" + empId,
                        type: "delete",
                        success: function (result) {
         
                            //回到本页(刷新页面)
                            to_page(currentPage);
                        }
                    });
                }else {
         
                    //取消
                    return false;
                }
            });
    
    2. 多选删除
    1. 为行首添加checkbox全选选项。
         ...
    	 <thead>
    	     <tr>
    	         <th>
    	             <input type="checkbox" id="check_all">
    	         th>
    	         <th>empIdth>
    	         <th>empNameth>
    	         <th>genderth>
            ...
    
    1. 在build_emps_table函数中为员工行也添加上checkbox选项。
    	...
    	$.each(emps, function (index, item) {
         
    	     var checkBoxTd = $("");
    	     //员工信息单元格
    	     ...
    	     //把相同员工的单元格添加到同一行
    	     $("")
    	         .append(checkBoxTd)
    	         .append(empIdTd)
    	         .append(empNameTd)
    	         .append(genderTd)
    	         .append(emailTd)
    	         ...
    

    SSM_CRUD练习项目_第37张图片

    1. 为th行首的全选按钮添加点击全选/全不选事件。
            $("#check_all").click(function () {
         
                //attr获取checked是undefined;
                //attr获取自定义属性的值;
                //prop修改和读取dom原生属性的值
                //check_item应跟随全选按钮,一同选中或不选中
                $(".check_item").prop("checked", $(this).prop("checked"));
            });
    
    1. 因为我们多加了一列,所以之前单个员工删除按钮事件中获取员工姓名需要改为2。
      SSM_CRUD练习项目_第38张图片

    2. 为td行首的按钮添加点击事件。

            //check_item的点击事件
            $(document).on("click", ".check_item", function () {
         
                //是否满足选中的个数和当前页员工的个数相同
                var flag = $(".check_item:checked").length == $(".check_item").length;
                //check_all全选按钮要和判断的结果相同,如果相同就选中,不同不选中
                $("#check_all").prop("checked", flag);
            });
    
    1. 在EmployeeService.java中新建一个deleteBatch方法,用于批量删除。
        /**
         * 批量删除员工信息
         * @param ids
         */
        public void deleteBatch(List<Integer> ids) {
         
            //自定义条件
            EmployeeExample example = new EmployeeExample();
            EmployeeExample.Criteria criteria = example.createCriteria();
            //删除语句将变成:delete from xxx where emd_id in (1, 2, 4 ...)
            criteria.andEmpIdIn(ids);
            employeeMapper.deleteByExample(example);
        }
    
    1. 修改EmployeeController.java中的deleteEmpById改为deleteEmp,并修改内容实现单个多选二合一删除。
        /**
         * 单个多选二合一删除员工信息
         * 多个删除:id中间用-分隔,如 1-2-4
         * 单个删除:如3
         * 删除指定delete请求
         * @param ids
         * @return
         */
        @RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
        @ResponseBody
        public Msg deleteEmp(@PathVariable("ids")String ids){
         
            //判断是否是多个删除
            if(ids.contains("-")){
         
                //多个删除
                //分隔成数组
                String[] str_ids = ids.split("-");
                List<Integer> del_ids = new ArrayList<>();
                for (String id : str_ids) {
         
                    del_ids.add(Integer.parseInt(id));
                }
                //批量删除
                employeeService.deleteBatch(del_ids);
    
            }else{
         
                //单个删除
                //按照id删除指定员工信息
                Integer id = Integer.parseInt(ids);
                employeeService.deleteEmp(id);
            }
            return Msg.success();
        }
    
    1. 为上方删除按钮添加点击删除选中员工信息事件。
            //为上方删除按钮添加点击删除选中员工信息事件
            $("#emp_delete_modal_btn").click(function () {
         
                var empName = "";
                var del_idstr = "";
                //遍历当前页被选中的员工
                $.each($(".check_item:checked"), function () {
         
                    //获取被选中的员工姓名
                    empName += $(this).parents("tr").find("td:eq(2)").text() + ",";
                    //组装员工id字符串
                    del_idstr += $(this).parents("tr").find("td:eq(1)").text() + "-";;
                });
                //去除多余 ,
                empName = empName.substring(0, empName.length - 1);
                //去除多余 -
                del_idstr = del_idstr.substring(0, del_idstr.length - 1);
    
                if(confirm("确定要删除【" + empName + "】吗?")){
         
                    //确认,发送ajax请求删除指定员工
                    $.ajax({
         
                        url: "${APP_PATH}/emp/" + del_idstr,
                        type: "delete",
                        success: function (result) {
         
                            //提示删除成功
                            alert(result.msg);
                            //回到当前页
                            to_page(currentPage);
                        }
                    });
                }else{
         
                    //取消
                    return false;
                }
            });
    

    磕磕碰碰的跟着老师做完了这个项目,第一次用ssm做项目,还是有很多知识点不够扎实,也学到了很多东西,学后端,前端的知识也需要了解,接下来继续练习,然后学习springboot。

    学习视频:https://www.bilibili.com/video/BV17W411g7zP?p=1

    你可能感兴趣的:(练习项目,java,spring,mybatis,ajax,jquery)