SSM-员工管理项目实战-CRUD-增删改查

SSM-CRUD

一、项目简介

主界面演示

SSM-员工管理项目实战-CRUD-增删改查_第1张图片

功能点

  • 分页
  • 数据校验
  • ajax
  • Rest 风格的 URI

技术点

  • 基础框架 - ssmSpring + SpringMVC + MyBatis
  • 数据库 - MySQL
  • 前端框架 - bootstrap (快速简洁美观的界面)
  • 项目的依赖管理 - Maven
  • 分页 - pagehelper
  • 逆向工程 - MyBatis Generator

二、基础环境搭建

1、创建 Maven 工程 ssm_crud_study

SSM-员工管理项目实战-CRUD-增删改查_第2张图片

3、添加 web 框架

(1)右键工程,点击 Add Framework Suppor

SSM-员工管理项目实战-CRUD-增删改查_第3张图片

(2)选择 Web Application

SSM-员工管理项目实战-CRUD-增删改查_第4张图片

3、在 pom.xml 中引入项目依赖

  • Spring
  • SpringMVC
  • MyBatis
  • 数据库连接池,驱动包
  • 其他(jstl,servlet-api,junit)

pom.xml


<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.0modelVersion>

    <groupId>com.chengroupId>
    <artifactId>ssm-crudartifactId>
    <version>1.0-SNAPSHOTversion>

    <dependencies>
        
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>5.0.0version>
        dependency>

        
        <dependency>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-coreartifactId>
            <version>1.3.5version>
        dependency>
        
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

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

        
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-validatorartifactId>
            <version>5.4.1.Finalversion>
        dependency>
        
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>4.3.7.RELEASEversion>
            <scope>testscope>
        dependency>

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

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

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

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

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

        
        <dependency>
            <groupId>jstlgroupId>
            <artifactId>jstlartifactId>
            <version>1.2version>
        dependency>

        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.0.1version>
            <scope>providedscope>
        dependency>
        
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>jsp-apiartifactId>
            <version>2.0version>
            <scope>providedscope>
        dependency>
        
    dependencies>
    
project>

4、引入 bootstrap 前端框架

(1)前往 bootstrap 官网下载

下载地址: https://v3.bootcss.com,选择用于生产环境的 Bootstrap

(2)解压后将文件夹添加到工程中 /static

SSM-员工管理项目实战-CRUD-增删改查_第5张图片

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

  • **web.xml,主要用于配置 Filter、Listener、Servlet **

  • springmvc 配置文件,主要控制网站逻辑的跳转

  • spring 配置文件,主要配置与业务逻辑相关的文件

  • mybatis 配置文件,主要用于配置 MyBatis

(1)配置 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_4_0.xsd"
         version="4.0">

    
    <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>
    <filter>
        <filter-name>httpPutFormContentFilterfilter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilterfilter-class>
    filter>
    <filter-mapping>
        <filter-name>httpPutFormContentFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
web-app>

在 src/main/resources/ 下加入 applicationContext.xml, 防止 idea 报错

SSM-员工管理项目实战-CRUD-增删改查_第6张图片

(2)配置 springmvc 配置文件

WEB-INF 下加入 dispatcherServlet-servlet.xml

SSM-员工管理项目实战-CRUD-增删改查_第7张图片

src/main/java 创建包结构

SSM-员工管理项目实战-CRUD-增删改查_第8张图片

**配置 dispatcherServlet-servlet.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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    <context:component-scan base-package="com.study" 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/views/"/>
        <property name="suffix" value=".jsp"/>
    bean>

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

(3) 配置 spring 配置文件

配置 dbconfig.properties ,配置数据库连接信息

src/main/resources 下加入 dbconfig.properties

SSM-员工管理项目实战-CRUD-增删改查_第9张图片

dbconfig.properties

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ssm_crud_study?useUnicode=true&characterEncoding=utf8
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=root

src/main/resources 下创建 mybatis-config.xml、mapper文件夹

SSM-员工管理项目实战-CRUD-增删改查_第10张图片

配置 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.chen">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>
    
    
    
    <context:property-placeholder location="classpath:dbconfig.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="sqlSessionFactoryBean"  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 id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
        <constructor-arg name="executorType" value="BATCH"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        
        <property name="sqlSessionTemplateBeanName" value="sessionTemplate"/>
        <property name="basePackage" value="com.study"/>
    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.chen.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>

此处目前会报错,是因为此时 mapper 文件夹目录下没有 .xml 文件,目前可忽略

SSM-员工管理项目实战-CRUD-增删改查_第11张图片

(4)配置 mybatis 文件

mybatis-config.xml



<configuration>

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

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

    
    <plugins>
        
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>
configuration>

6、创建数据库

CREATE DATABASE ssm_crud_study;

CREATE TABLE `ssm_crud_study`.`tbl_emp` (
  `emp_id` INT NOT NULL AUTO_INCREMENT,
  `emp_name` VARCHAR(255) NOT NULL,
  `gender` CHAR(1) NULL,
  `email` VARCHAR(255) NULL,
  `d_id` INT NULL,
  PRIMARY KEY (`emp_id`));
  
CREATE TABLE `ssm_crud_study`.`tbl_dept` (
  `dept_id` INT NOT NULL,
  `dept_name` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`dept_id`));

ALTER TABLE `ssm_crud_study`.`tbl_emp` 
ADD INDEX `dept_id_idx` (`d_id` ASC) VISIBLE;
;
ALTER TABLE `ssm_crud_study`.`tbl_emp` 
ADD CONSTRAINT `dept_id`
  FOREIGN KEY (`d_id`)
  REFERENCES `ssm_crud_study`.`tbl_dept` (`dept_id`)
  ON DELETE NO ACTION
  ON UPDATE NO ACTION;
SSM-员工管理项目实战-CRUD-增删改查_第12张图片

7、使用 mapper 的逆向工程生成 bean、mapper

在工程中添加 mbg.xml

SSM-员工管理项目实战-CRUD-增删改查_第13张图片

配置 mbg.xml




<generatorConfiguration>

    <context id="DB2Tables" targetRuntime="MyBatis3">
        <commentGenerator>
            
            <property name="suppressAllComments" value="true" />
        commentGenerator>

        
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_crud_study?useUnicode=true&characterEncoding=utf8"
                        userId="root"
                        password="root">
        jdbcConnection>

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

        
        <javaModelGenerator targetPackage="com.study.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.study.crud.dao"  targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>

        
        <table tableName="tbl_emp" domainObjectName="Employee">

        table>
        <table tableName="tbl_dept" domainObjectName="Department">table>

    context>
generatorConfiguration>

src/test/java 中创建 MBGTest 用于生成 bean、mapper

SSM-员工管理项目实战-CRUD-增删改查_第14张图片
public class MBGTest {

    public static void main(String[] args) 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);
    }
}

运行结果:自动生成 bean、mapper

SSM-员工管理项目实战-CRUD-增删改查_第15张图片

8、测试 mapper

在数据库中添加数据

INSERT INTO `ssm_crud_study`.`tbl_dept` (`dept_id`, `dept_name`) VALUES ('1', '开发部');
INSERT INTO `ssm_crud_study`.`tbl_dept` (`dept_id`, `dept_name`) VALUES ('2', '测试部');

INSERT INTO `ssm_crud_study`.`tbl_emp` (`emp_id`, `emp_name`, `gender`, `email`, `d_id`) VALUES ('1', 'Jerry', 'M', '[email protected]', '1');
SSM-员工管理项目实战-CRUD-增删改查_第16张图片

src/test/java 创建 MapperTest

首先测验能否连接到获得 mapper 实例

SSM-员工管理项目实战-CRUD-增删改查_第17张图片

测试能否获取数据库中信息

SSM-员工管理项目实战-CRUD-增删改查_第18张图片

向数据库中插入 1000 条数据

// 使用 Spring Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MapperTest {

    @Autowired
    DepartmentMapper departmentMapper;

    // 可以执行批量操作的 sqlSession
    @Autowired
    SqlSession sqlSession;

    @Test
    public void testCRUD() {
//        System.out.println(departmentMapper);
//        Department department = departmentMapper.selectByPrimaryKey(1);
//        System.out.println("dept_id=" + department.getDeptId() + ",dept_name=" + department.getDeptName());

        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 1000; i++) {
            // 使用 UUID 工具类,随机生成用户名
            String empName = UUID.randomUUID().toString().substring(0, 5);
            // 需要在 Employee 中添加有参构造,!!!添加有参构造后必须添加无参构造 !!!
            mapper.insertSelective(new Employee(null, empName, "M", empName + "@qq.com", 1));
        }
    }
}
SSM-员工管理项目实战-CRUD-增删改查_第19张图片

三、CRUD开发

1、index.jsp

流程

  • 访问 index.jsp 页面
  • index.jsp 页面发送出查询员工列表请求
  • EmployeeController 来接收请求,查处员工数据
  • 来到 list.jsp 页面进行展示
  • pageHelper 分页插件完成分页查询功能

index.jsp 添加标签 jsp:forward 跳转到 /emps

SSM-员工管理项目实战-CRUD-增删改查_第20张图片

com.study.crud.controller 中添加 EmployeeController,并编写映射请求

SSM-员工管理项目实战-CRUD-增删改查_第21张图片

/WEB-INF/viwes/ 下添加 list.jsp

SSM-员工管理项目实战-CRUD-增删改查_第22张图片

启动服务器,查看是否跳转成功

SSM-员工管理项目实战-CRUD-增删改查_第23张图片

我们查询员工时,希望能够查询出部门的信息,所以需要在 EmployeeMapper 中添加新的查询方法,并在 Employee 中添加 Department 属性,和 get、set 方法

SSM-员工管理项目实战-CRUD-增删改查_第24张图片 SSM-员工管理项目实战-CRUD-增删改查_第25张图片

EmployeeMapper.xml 中添加 SQL

<resultMap id="WithDeptResultMap" type="com.study.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.study.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" 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" 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>

EmployeeService 中添加 getAll() 方法

SSM-员工管理项目实战-CRUD-增删改查_第26张图片

EmployeeController.getEmps() 中引入分页插件

SSM-员工管理项目实战-CRUD-增删改查_第27张图片

src/test/ 下添加测试,测试分页插件

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:applicationContext.xml", "file:web/WEB-INF/dispatcherServlet-servlet.xml"})
public class MVCTest {

    // 传入  Spring MVC 的 ioc
    @Autowired
    WebApplicationContext context;

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

    @Before
    public void initMockMvc() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testPage() throws Exception {
        // 模拟请求拿到返回值
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps").param("pn", "5")).andReturn();

        // 请求成功以后,请求域中会有 pageInfo
        MockHttpServletRequest request = result.getRequest();
        PageInfo page = (PageInfo) request.getAttribute("pageInfo");
        System.out.println("当前页码:" + page.getPageNum());
        System.out.println("总页码:" + page.getPages());
        System.out.println("总记录数:" + page.getTotal());
        System.out.println("在页面需要连续显示的页码");
        int[] nums = page.getNavigatepageNums();
        for (int num : nums)
            System.out.print(" " + num);
        System.out.println();

        List<Employee> emps = page.getList();
        for (Employee emp : emps)
            System.out.println("ID:" + emp.getEmpId() + "==>Name:" + emp.getEmpName());
    }
}

测试结果

SSM-员工管理项目实战-CRUD-增删改查_第28张图片

2、list.jsp

/static 下加入 jquery

SSM-员工管理项目实战-CRUD-增删改查_第29张图片

list.jsp 中引入 bootstrap、jquery

SSM-员工管理项目实战-CRUD-增删改查_第30张图片

前往 Bootstrap 官网,查看文档

SSM-员工管理项目实战-CRUD-增删改查_第31张图片

SSM-员工管理项目实战-CRUD-增删改查_第32张图片 SSM-员工管理项目实战-CRUD-增删改查_第33张图片

根据文档创建 新建 删除 按钮

SSM-员工管理项目实战-CRUD-增删改查_第34张图片

查看效果

SSM-员工管理项目实战-CRUD-增删改查_第35张图片

给按钮添加样式

SSM-员工管理项目实战-CRUD-增删改查_第36张图片 SSM-员工管理项目实战-CRUD-增删改查_第37张图片

查看样式

SSM-员工管理项目实战-CRUD-增删改查_第38张图片

根据文档可以写出表格界面

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


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

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

    <%--  引入 jquery  --%>
    
    <%--  引入样式  --%>
    
    


    

SSM-CRUD

# lastName email gender deptName 操作
${emp.empId} ${emp.empName} ${emp.email} ${emp.gender == 'M' ? '男' : '女'} ${emp.department.deptName}

查看效果

SSM-员工管理项目实战-CRUD-增删改查_第39张图片

编写分页条


当前第 ${pageInfo.pageNum} 页,共有 ${pageInfo.pages} 页,总计 ${pageInfo.total} 条记录

查看效果

SSM-员工管理项目实战-CRUD-增删改查_第40张图片

3、ajax

至此已经完成了基本的界面开发,但是目前的设计有着很大的缺陷,每次换页都需要重新加载整个网页。

由此引入 AJAX

AJAX = 异步 JavaScriptXML

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

基于 ajax 查询员工数据

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

(1)去除 index.jsp 中的 标签,将 list.jsp 中的内容复制到 index.jsp

(2)删除 index.jsp 页面中带有从 EmployeeController.getEmps() 得到的 pageInfo 相关的标签

得到如下

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


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

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

  <%--  引入 jquery  --%>
  
  <%--  引入样式  --%>
  
  


SSM-CRUD

# lastName email gender deptName 操作

(3) EmployeeController 中添加返回 json 的映射请求

SSM-员工管理项目实战-CRUD-增删改查_第41张图片

在浏览器中查看返回的 json 字符串

SSM-员工管理项目实战-CRUD-增删改查_第42张图片

(4) 编写消息类

我们需要将返回的类封装到一个消息类中,以便获取更多的信息

com.study.crud.bean 中创建 Msg

public class Msg {

    public static final int CODE_SUCCESS = 100;
    public static final int CODE_FAIL = 200;
    
    // 状态码
    private int code;
    
    // 提示信息
    private String msg;
    
    // 返回给浏览器的数据
    private Map<String, Object> extend = new HashMap<String, Object>();
    
    public static Msg success() {
        Msg msg = new Msg();
        msg.setCode(CODE_SUCCESS);
        msg.setMsg("处理成功");
        return msg;
    }
    
    public static Msg fail() {
        Msg msg = new Msg();
        msg.setCode(CODE_FAIL);
        msg.setMsg("处理失败");
        return msg;
    }

    // 向 Msg 中添加数据
    public Msg add(String key, Object value) {
        this.extend.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()

SSM-员工管理项目实战-CRUD-增删改查_第43张图片

查看改写后的映射请求返回的数据

SSM-员工管理项目实战-CRUD-增删改查_第44张图片

(4) **编写 js **

添加 id 值

SSM-员工管理项目实战-CRUD-增删改查_第45张图片

添加 js

<script type="text/javascript">
  var lastPage, currentPage, totalRecord;

  // 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;
    $.each(emps, function (index, item) {
      var checkBoxTd = $("");
      var empIdTd = $("").append(item.empId);
      var empNameTd = $("").append(item.empName);
      var gender = item.gender == 'M' ? '男' : '女';
      var genderTd = $("").append(gender);
      var emailTd = $("").append(item.email);
      var deptNameTd = $("").append(item.department.deptName);
      /**
       *  
       */
      var editBtn = $("").addClass("btn btn-primary btn-sm edit_btn")
              .append($("")).addClass("glyphicon glyphicon-pencil").append("编辑");
      editBtn.attr("edit-id", item.empId);
      var deleteBtn = $("").addClass("btn btn-danger btn-sm delete_btn")
              .append($("")).addClass("glyphicon glyphicon-trash").append("删除");
      deleteBtn.attr("del-id", item.empId);
      var btnTd = $("").append(editBtn).append(" ").append(deleteBtn);

      // append 方法执行完成以后还是返回原来的元素 所以可以链式操作
      $("").append(checkBoxTd)
              .append(empIdTd)
              .append(empNameTd)
              .append(genderTd)
              .append(emailTd)
              .append(deptNameTd)
              .append(btnTd)
              .appendTo("#emps_table tbody");
    })
  }

  function build_page_info(result) {
    $("#page_info_area").empty();
    var pageInfo = result.extend.pageInfo;
    $("#page_info_area").append("当前 " + pageInfo.pageNum + " 页,"
            + "总 " + pageInfo.pages + " 页,"
            + "总 " + pageInfo.total + " 条记录"
    );
    lastPage = pageInfo.pages;
    totalRecord= pageInfo.total;
    currentPage = pageInfo.pageNum;
  }

  function build_page_nav(result) {
    $("#page_nav_area").empty();
    var pageInfo = result.extend.pageInfo;
    var ul = $("
    "
    ).addClass("pagination"); var firstPageLi = $("
  • "
    ).append($("").append("首页")); var prePageLi = $("
  • "
    ).append($("").append("«")); if (pageInfo.hasPreviousPage == false) { firstPageLi.addClass("disabled"); prePageLi.addClass("disabled"); } else { firstPageLi.click(function () { to_page(1); }); prePageLi.click(function () { to_page(pageInfo.pageNum - 1); }); } ul.append(firstPageLi).append(prePageLi); $.each(result.extend.pageInfo.navigatepageNums, function (index, item) { var numLi = $("
  • "
    ).append($("").append(item)); if (pageInfo.pageNum == item) { numLi.addClass("active"); } numLi.click(function () { to_page(item); }); ul.append(numLi); }); var nextPageLi = $("
  • "
    ).append($("").append("»")); var lastPageLi = $("
  • "
    ).append($("").append("尾页")); if (pageInfo.hasNextPage == false) { nextPageLi.addClass("disabled"); lastPageLi.addClass("disabled"); } else { nextPageLi.click(function () { to_page(pageInfo.pageNum + 1); }); lastPageLi.click(function () { to_page(pageInfo.pages); }); } ul.append(nextPageLi).append(lastPageLi); var navEle = $("").append(ul); navEle.appendTo("#page_nav_area"); } </script>

    查看结果

    SSM-员工管理项目实战-CRUD-增删改查_第46张图片

    4、业务逻辑

    (1)新增员工信息

    添加 员工添加的模态框

    
    
    

    新建按钮处添加 id

    SSM-员工管理项目实战-CRUD-增删改查_第47张图片

    编写 js

    //清空表单样式及内容
      function reset_form(ele) {
        $(ele)[0].reset();
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        $(ele).find(".help-block").text("");
      }
    
      function getDepts(ele) {
        // 清空之前下拉列表的值
        $(ele).empty();
        $.ajax({
          url: "${APP_PATH}/depts",
          type: "get",
          success:function (result) {
            //{"code":100,"msg":"处理成功!",
            //"extend":{"depts":[{"deptId":1,"deptName":"开发部"},{"deptId":2,"deptName":"测试部"}]}}
            //console.log(result);
            //显示部门信息在下拉列表中
            //$("#empAddModal select").append("")
            $.each(result.extend.depts,function(){
              var optionEle = $("").append(this.deptName).attr("value",this.deptId);
              optionEle.appendTo(ele);
            });
          }
        });
      }
    
      // 点击新增按钮弹出模态框。
      $("#emp_add_modal_btn").click(function () {
        //清除表单数据(表单完整重置(表单的数据,表单的样式))
        reset_form("#empAddModal form");
        //s$("")[0].reset();
        //发送ajax请求,查出部门信息,显示在下拉列表中
        getDepts("#empAddModal select");
        //弹出模态框
        $("#empAddModal").modal({
          backdrop:"static"
        });
      });
    

    查看 添加模态框

    SSM-员工管理项目实战-CRUD-增删改查_第48张图片

    创建 DepartmentController 映射 getDepts 请求

    @Controller
    public class DepartmentController {
    
        @Autowired
        DepartmentService departmentService;
    
        @RequestMapping("/depts")
        @ResponseBody
        public Msg getDeptsWithJson() {
            List<Department> depts = departmentService.getDepts();
            return Msg.success().add("depts", depts);
        }
    }
    
    @Service
    public class DepartmentService {
    
        @Autowired
        DepartmentMapper departmentMapper;
    
        public List<Department> getDepts() {
            return departmentMapper.selectByExample(null);
        }
    }
    

    查看是否显示部门信息

    SSM-员工管理项目实战-CRUD-增删改查_第49张图片

    (2)数据校验

    **js校验 **

    // 检验表单数据
      function validate_add_form() {
        var empName = $("#empName_add_input").val();
        var regName = /(^[a-zA-Z0-9]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
        if (!regName.test(empName)) {
          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)) {
          show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
          return false;
        } else {
          show_validate_msg("#email_add_input", "success", "");
        }
        return true;
      }
    
      // 显示校验结果的提示信息
      function show_validate_msg(ele, status, msg) {
        $(ele).parent().removeClass("has-success has-error");
        $(ele).next("span").text("");
        if ("success" == status) {
          $(ele).parent().addClass("has-success");
          $(ele).next("span").text(msg);
        } else {
          $(ele).parent().addClass("has-error");
          $(ele).next("span").text(msg);
        }
      }
    
      // 校验用户名是否可用
      $("#empName_add_input").change(function () {
        var empName = this.value;
        $.ajax({
          url:"${APP_PATH}/checkuser",
          data:"empName="+empName,
          type:"post",
          success:function (result) {
            if (result.code == 100) {
              show_validate_msg("#empName_add_input", "success", "用户名可用");
              $("emp_save_btn").attr("ajax-va", "success");
            } else {
              show_validate_msg("#empName_add_input", "error", result.extend.va_msg);
              $("emp_save_btn").attr("ajax-va", "error");
            }
          }
        });
      });
    

    EmployeeController 中添加检验用户名映射请求

    // EmployeeController
    @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", "用户名已存在");
        }
    }
    

    EmployeeService 中添加检验方法

    public boolean checkUser(String empName) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpNameEqualTo(empName);
        long count = employeeMapper.countByExample(example);
        return count == 0;
    }
    

    查看校验结果

    SSM-员工管理项目实战-CRUD-增删改查_第50张图片 SSM-员工管理项目实战-CRUD-增删改查_第51张图片

    (3) 保存员工

    添加 js

    // 点击保存,保存员工
      $("#emp_save_btn").click(function () {
        // 1、模态框中填写的数据提交给服务器进行保存
        // 1、先对要提交给服务器的数据进行校验
        if (!validate_add_form()) {
          return false;
        }
        // 1、判断之前的 ajax 用户名校验是否成功
        if ($(this).attr("ajax-va") == "error") {
          return false;
        }
    
        // 2、发送 ajax 请求保存员工
        $.ajax({
          url:"${APP_PATH}/emp",
          type:"post",
          data:$("#empAddModal form").serialize(),
          success:function(result) {
            if (result.code == 100) {
              // 员工保存成功
              // 1、关闭模态框
              $("#empAddModal").modal("hide");
              // 2、来到最后一页,显示刚才保存的数据
              if (totalRecord % 5 == 0) {
                lastPage++;
                currentPage = lastPage;
              }
              totalRecord++;
              to_page(lastPage);
            } else {
              // 显示失败信息
              if (undefined != result.extend.errorFields.email) {
                // 显示邮箱错误信息
                show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
              }
              if (undefined != result.extend.errorFields.empName) {
                // 显示员工名字的错误信息
                show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
              }
            }
          }
        });
      });
    

    Employee 中使用JSR303 数据校验

    SSM-员工管理项目实战-CRUD-增删改查_第52张图片

    EmployeeController 中添加保存员工的映射请求

    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    @ResponseBody
    public Msg saveEmp(@Valid Employee employee, BindingResult result) {
        if (result.hasErrors()) {
            Map<String, Object> map = new HashMap<String, Object>();
            List<FieldError> errors = result.getFieldErrors();
            for (FieldError fieldError : errors) {
                System.out.println("错误的字段名:" + fieldError.getField());
                System.out.println("错误信息:" + fieldError.getDefaultMessage());
                map.put(fieldError.getField(), fieldError.getDefaultMessage());
            }
            return Msg.fail().add("errorFields", map);
        } else {
            employeeService.saveEmp(employee);
            return Msg.success();
        }
    }
    

    EmployeeService 中添加保存员工的方法

    public void saveEmp(Employee employee) {
        employeeMapper.insertSelective(employee);
    }
    
    SSM-员工管理项目实战-CRUD-增删改查_第53张图片 SSM-员工管理项目实战-CRUD-增删改查_第54张图片

    (4) 修改员工信息

    添加员工修改模态框

    
    
    

    添加 js

    // 1、如果在编辑和删除按钮创建之前绑定 click 是绑定不上的
      // 1)可以在创建按钮的时候绑定
      // 2)绑定点击 .live()
      $(document).on("click", ".edit_btn", function () {
        // 1、查处部门信息,并显示部门列表
        getDepts("#empUpdateModal select");
        // 2、查处员工信息,显示员工信息
        getEmp($(this).attr("edit-id"));
    
        // 3、把员工的 id 传递给模态框的更新按钮
        $("#emp_update_btn").attr("edit-id", $(this).attr("edit-id"));
        $("#empUpdateModal").modal({
          backdrop: "static"
        });
      });
    
      function getEmp(id) {
        $.ajax({
          url:"${APP_PATH}/emp/" + id,
          type:"get",
          success:function (result) {
            var 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]);
          }
        });
      }
    
      // 点击更新,更新员工信息
      $("#emp_update_btn").click(function () {
        // 验证邮箱是否合法
        // 1、校验邮箱信息
        var email = $("#email_update_input").val();
        var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)) {
          show_validate_msg("#email_update_input", "error", "邮箱格式不正确");
          return false;
        } else {
          show_validate_msg("#email_update_input", "success", "");
        }
    
        // 2、发送 ajax 请求保存更新的员工数据
        $.ajax({
          url:"${APP_PATH}/emp/" + $(this).attr("edit-id"),
          type:"put",
          data:$("#empUpdateModal form").serialize(),
          success:function (result) {
            $("#empUpdateModal").modal("hide");
            to_page(currentPage);
          }
        });
      });
    

    EmployeeController 中添加按 id 获取员工的映射请求 和 更新员工的请求

    @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Msg getEmp(@PathVariable("id") Integer id) {
        Employee employee = employeeService.getEmp(id);
        return Msg.success().add("emp", employee);
    }
    
    @RequestMapping(value = "/emp/{empId}", method = RequestMethod.PUT)
    @ResponseBody
    public Msg updateEmp(Employee employee, HttpServletRequest request) {
        employeeService.updateEmp(employee);
        return Msg.success();
    }
    

    EmployeeService 中添加 getEmp 方法和 update 方法

    public Employee getEmp(Integer id) {
        return employeeMapper.selectByPrimaryKeyWithDept(id);
    }
    
    public void updateEmp(Employee employee) {
        employeeMapper.updateByPrimaryKeySelective(employee);
    }
    

    查看效果

    SSM-员工管理项目实战-CRUD-增删改查_第55张图片SSM-员工管理项目实战-CRUD-增删改查_第56张图片

    SSM-员工管理项目实战-CRUD-增删改查_第57张图片

    (5) 添加全选功能

    添加全选按钮

    SSM-员工管理项目实战-CRUD-增删改查_第58张图片

    添加 js

      // 完成全选、全不选功能
      $("#check_all").click(function () {
        $(".check_item").prop("checked", $(this).prop("checked"));
      });
    
      $(document).on("click", ".check_item", function () {
        var flag = $(".check_item:checked").length == $(".check_item").length;
        $("#check_all").prop("checked", flag);
      });
    

    添加删除功能

    给删除按键添加 id

    SSM-员工管理项目实战-CRUD-增删改查_第59张图片

    添加 js

      // 单个删除
      $(document).on("click", ".delete_btn", function () {
        var empName = $(this).parents("tr").find("td:eq(2)").text();
        var empId = $(this).attr("del-id");
        // 弹出是否确认删除对话框
        if (confirm("确认删除【" + empName + "】吗?")) {
          $.ajax({
            url:"${APP_PATH}/emp/" + empId,
            type:"delete",
            success:function (result) {
              alert(result.msg);
              to_page(1);
            }
          });
        }
      });
    
      // 点击全部删除、就批量删除
      $("#emp_delete_all_btn").click(function () {
        var empNames = "";
        var del_ids = "";
        $.each($(".check_item:checked"), function () {
          empNames += $(this).parents("tr").find("td:eq(2)").text() + ",";
          del_ids += $(this).parents("tr").find("td:eq(1)").text() + "-";
        });
        empNames = empNames.substring(0, empNames.length - 1);
        del_ids = del_ids.substring(0, del_ids.length - 1);
        if (confirm("确认删除【" + empNames + "】吗?")) {
          $.ajax({
            url:"${APP_PATH}/emp/" + del_ids,
            type:"delete",
            success:function (result) {
              alert(result.msg);
              to_page(1);
            }
          });
        }
      });
    

    EmployeeController 中添加删除方法

    @RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmp(@PathVariable("ids") String ids) {
        // 批量删除
        if (ids.contains("-")) {
            List<Integer> del_ids = new ArrayList<Integer>();
            String[] str_ids = ids.split("-");
            for (String str : str_ids) {
                del_ids.add(Integer.parseInt(str));
            }
            employeeService.deleteBatch(del_ids);
        } else {
            Integer id = Integer.parseInt(ids);
            employeeService.deleteEmp(id);
        }
        return Msg.success();
    }
    

    EmployeeService中添加单个删除和多个删除的方法

    public void deleteBatch(List<Integer> del_ids) {
        EmployeeExample example = new EmployeeExample();
        EmployeeExample.Criteria criteria = example.createCriteria();
        criteria.andEmpIdIn(del_ids);
        employeeMapper.deleteByExample(example);
    }
    
    public void deleteEmp(Integer id) {
        employeeMapper.deleteByPrimaryKey(id);
    }
    

    查看效果

    SSM-员工管理项目实战-CRUD-增删改查_第60张图片 SSM-员工管理项目实战-CRUD-增删改查_第61张图片 SSM-员工管理项目实战-CRUD-增删改查_第62张图片

    四、总结

    SSM-员工管理项目实战-CRUD-增删改查_第63张图片

    你可能感兴趣的:(bootstrap,java,mysql,intellij,idea,json)