ssm项目整合CRUD

一、基础环境搭建

1. 创建一个maven工程

导入jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

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

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--spring mvcweb-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.6</version>
        </dependency>
        <!--spring jdbc-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.6</version>
        </dependency>
        <!--spring aspects-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.6</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--mybatis与spring整合适配包-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>


        <!-- MySQL驱动 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!--c3p0数据库连接池-->
        <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--jstl-->
        <!-- https://mvnrepository.com/artifact/jstl/jstl -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!--servletapi-->
        <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
</project>

2. 引入bootstrap前端框架

  1. 下载bootstrap文档解压放在static文件目录下
  2. 引入
<%--
  Created by IntelliJ IDEA.
  User: long
  Date: 2022/9/21
  Time: 8:27
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
    <%--jquery--%>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <%--bootstrap--%>
    <link  rel="stylesheet"  href="static/bootstrap-3.4.1-dist/css/bootstrap.min.css">
    <script src="static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
</body>
</html>

3. 编写配置文件

1. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--启动spring容器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!--配置编码过滤器,一定要放在所有过滤器之前-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--配置隐藏请求过滤器-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--springmvc的前端拦截器,拦截除jsp外的所有请求-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

2. springMVC

文件名:dispatcherServlet-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu.crud" use-default-filters="false">
        <!--禁用默认规则,只扫描控制器-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

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

    <!--两个标准配置-->
    <!--springmvc不能处理的东西交给tomcat-->
    <mvc:default-servlet-handler />
    <!--能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax,映射动态请求-->
    <mvc:annotation-driven/>
</beans>

3. spring

文件名:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--Spring配置文件,这里主要配置和业务逻辑有关的
        核心关注点:数据源、与mybatis的整合、事务控制
    -->
    <!--开启组件扫描。除了Controller其他都扫描-->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--引入资源文件-->
    <context:property-placeholder location="classpath:daconfig.properties"></context:property-placeholder>
    <!--===============================数据源===============================-->
    <bean id="poolDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property  name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--===============================配置和Mybatis的整合===============================-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--指定mybatis全局配置文件的位置-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!--配置数据源-->
        <property name="dataSource" ref="poolDataSource"></property>
        <!--指定mybatis中mapper文件的位置-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>
    
    <!--配置一个可以执行批量的sqlSession-->
    <bean class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <constructor-arg name="executorType" value="BATCH"/>
    </bean>

    <!--配置扫描器,将mybatis接口的实现加入到ioc容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--扫描所有的dao接口-->
        <property name="basePackage" value="com.atguigu.crud.dao"></property>
    </bean>

    <!--===============================事务控制的配置===============================-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--控制数据源-->
        <property name="dataSource" ref="poolDataSource"></property>
    </bean>
    <!--开启基于注解的事务,使用xml配置文件形式的事务(重要的事务用品味至文件)-->
    <aop:config>
        <!--切入点表达式
        *(任意权限修饰符) com.atguigu.crud.service..(service下以及子包内的所有类)*(..)(任意方法的任意参数))
        -->
        <aop:pointcut id="txPoint" expression="execution(* com.atguigu.crud.service..*(..))"/>
        <!--配置事务增强-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
    </aop:config>
    <!--配置事务增强,事务如何切入-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--切入的所有方法都是事务方法-->
            <tx:method name="*"/>
            <!--以get开头的所有方法设置只读-->
            <tx:method name="get*" read-only="true"></tx:method>
        </tx:attributes>
    </tx:advice>
</beans>

4. mybatis

文件名:mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--转驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <typeAliases>
        <!--取别名-->
        <package name="com.atguigu.crud.bean"/>
    </typeAliases>
    <plugins>
        <!--设置分页插件-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--指定页面在1-最后一页之间,如果出现超过的情况会当最后一页处理,如果出现0和负数当做第一页处理-->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
</configuration>

5. mybatis逆向工程

导入依赖:

<!--mybaits逆向工程-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.7</version>
</dependency>

创建generatorConfig.xml配置文件

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC
        "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版) -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=UTC"
                        userId="root" password="root"></jdbcConnection>
        <!-- javaBean的生成位置-->
        <javaModelGenerator targetPackage="com.atguigu.crud.bean" targetProject=".\src\main\java">
            <!--是否使用子包,开启时com.atguigu.mybatis.pojo会变成一层一层的目录
                            不开启则默认com.atguigu.mybatis.pojo就是目录名字,不会创建多层目录-->
            <property name="enableSubPackages" value="true"/>
            <!--去除字段名两边的空格-->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.crud.dao"
                             targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 逆向分析每个表的生成策略 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="tbl_emp" domainObjectName="Emp"/>
        <table tableName="tbl_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

通过java运行逆向工程:

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

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class MBGTest {
    public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
        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);
    }
}

二、测试功能

package com.atguigu.crud.testMapper;

import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import com.atguigu.crud.dao.DeptMapper;
import com.atguigu.crud.dao.EmpMapper;
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.List;
import java.util.UUID;

/**
 * 1、导入springtest单元测试,可以注入我们需要的组件
 * 2、@ContextConfiguration指定Spring配置文件所在的位置
 * 3、直接Autowired要使用的组件即可
 */
@RunWith(SpringJUnit4ClassRunner.class)//使用Spring提供的单元测试模块
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestDeptMapper {
    @Autowired
    DeptMapper deptMapper;
    @Autowired
    EmpMapper empMapper;
    @Autowired
    SqlSession sqlSession;

    /**
     * 测试插入
     */
    @Test
    public void testSelectByExampleWithDept() {
//        Emp emp = new Emp();
//        emp.setDid(1);
//        emp.setEmail("123@qq.com");
//        emp.setEmpName("李四");
//        emp.setGender("男");
//        empMapper.insertSelective(emp);

        //实现批量插入
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        for (int i = 0; i < 1000; i++) {
            String uuid = UUID.randomUUID().toString().substring(0, 5) + String.valueOf(i);
            Emp emp1 = new Emp();
            emp1.setGender("男");
            emp1.setEmpName(uuid);
            emp1.setEmail(uuid+"@qq.com");
            emp1.setDid(2);
            mapper.insertSelective(emp1);
        }
    }

    /**
     * 测试插入
     */
    @Test
    public void testInsertDept(){
        Dept dept = new Dept();
        dept.setDeptName("开发部");
        deptMapper.insertSelective(dept);
    }

    /**
     * 测试查询
     */
    @Test
    public void testSelectEmp(){
        EmpExample empExample = new EmpExample();
        empExample.createCriteria().andEmpNameEqualTo("张三");
//        Emp emp = empMapper.selectByPrimaryKey(2);
//        System.out.println(emp);
        List<Emp> emps = empMapper.selectByExampleWithDept(empExample);
        emps.forEach(System.out::println);
    }
}

三、实现功能

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

1. 接口功能实现

1.1 EmpController

package com.atguigu.crud.controller;

import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
public class EmpController {
    @Autowired
    EmpService empService;

    /**
     * 查询所有员工信息
     *
     * @return
     */
    @RequestMapping("/emps")
    public ModelAndView getEmps(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
        ModelAndView modelAndView = new ModelAndView();

        //开启分页查询
        PageHelper.startPage(pageNumber, 4);
        List<Emp> emps = empService.getAll();
        //navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
        //封装了分页信息与查询结果
        PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);

        modelAndView.addObject("pageInfo", empPageInfo);
        modelAndView.setViewName("list");
        return modelAndView;
    }
}

1.2 EmpService

package com.atguigu.crud.service;

import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.dao.EmpMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmpService {
    @Autowired
    EmpMapper empMapper;

    /**
     * 查询所有员工信息
     * @return
     */
    public List<Emp> getAll() {
        return empMapper.selectByExampleWithDept(null);
    }
}

1.3 EmpMapper

package com.atguigu.crud.dao;

import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface EmpMapper {
    /**
     * 带上部门的员工信息
     * @param empId
     * @return
     */
    Emp selectByPrimaryKeyWithDept(Integer empId);
    /**
     * 带上部门信息的员工信息
     * @param example
     * @return
     */
    List<Emp> selectByExampleWithDept(EmpExample example);
    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    long countByExample(EmpExample example);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int deleteByExample(EmpExample example);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int deleteByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int insert(Emp record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int insertSelective(Emp record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    List<Emp> selectByExample(EmpExample example);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    Emp selectByPrimaryKey(Integer empId);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int updateByExampleSelective(@Param("record") Emp record, @Param("example") EmpExample example);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int updateByExample(@Param("record") Emp record, @Param("example") EmpExample example);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int updateByPrimaryKeySelective(Emp record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table tbl_emp
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    int updateByPrimaryKey(Emp record);
}

2. 前端功能实现(抛弃)

因为这样做每次需要返回大量数据,导致访问速度变慢,实现基本展示后使用ajax请求访问后台,实现异步显示。

2.1 index.jsp跳转list.jsp

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

2.2 list实现数据展示

<%@ page isELIgnored="false" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
    <!-- web路径:
    不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
    以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
            http://localhost:3306/crud
     -->
    <script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
    <link
            href="${APP_PATH }/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"
            rel="stylesheet">
    <script
            src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<div class="container">
    <!-- 标题 -->
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD BY PL</h1>
        </div>
    </div>
    <!-- 按钮 -->
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary">新增</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>
    <!-- 显示表格数据 -->
    <div class="row">
        <div class="col-md-12">
            <table class="table table-hover">
                <tr>
                    <th>#</th>
                    <th>empName</th>
                    <th>gender</th>
                    <th>email</th>
                    <th>deptName</th>
                    <th>操作</th>
                </tr>
                <c:forEach items="${pageInfo.list}" var="emp">
                    <tr>
                        <td>${emp.empId}</td>
                        <td>${emp.empName}</td>
                        <td>${emp.gender=="男"?"male":"female"}</td>
                        <td>${emp.email}</td>
                        <td>${emp.dept.deptName}</td>
                        <td>
                            <button class="btn btn-primary btn-sm">
                                <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
                                编辑
                            </button>

                            <button class="btn btn-danger btn-sm">
                                <span class="glyphicon glyphicon-remove" 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?pageNumber=1">首页</a></li>
                    <%--如果有上一页才显示上一页--%>
                    <c:if test="${pageInfo.hasPreviousPage}">
                        <li class="disabled">
                            <a href="${APP_PATH}/emps?pageNumber=${pageInfo.prePage}" aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                    </c:if>

                    <c:forEach items="${pageInfo.navigatepageNums}" var="page_Num">
                        <%--判断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?pageNumber=${page_Num}">${page_Num}</a></li>
                        </c:if>
                    </c:forEach>
                    <%--如果有上一页才显示上一页--%>
                    <c:if test="${pageInfo.hasNextPage}">
                        <li>
                            <a href="${APP_PATH}/emps?pageNumber=${pageInfo.nextPage}" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                    </c:if>
                    <li><a href="${APP_PATH}/emps?pageNumber=${pageInfo.pages}">末页</a></li>
                </ul>
            </nav>
        </div>
    </div>
</div>
</body>
</html>

3. 用ajax进行交互(推荐)

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

3.1 index.jsp用ajax请求展示数据

<%@ page isELIgnored="false" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
    <!-- web路径:
    不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
    以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
            http://localhost:3306/crud
     -->
    <script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
    <link
            href="${APP_PATH }/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"
            rel="stylesheet">
    <script
            src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<div class="container">
    <!-- 标题 -->
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <!-- 按钮 -->
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary">新增</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>
    <!-- 显示表格数据 -->
    <div class="row">
        <div class="col-md-12">
            <table class="table table-hover" id="emps_tables">
                <thead>
                <tr>
                    <th>#</th>
                    <th>empName</th>
                    <th>gender</th>
                    <th>email</th>
                    <th>deptName</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
    </div>
    <%--显示分页信息--%>
    <div class="row">
        <%--分页信息--%>
        <div class="col-md-6" id="page_info_area">
        </div>
        <%--分页条信息--%>
        <div class="col-md-6" id="page_nav_area">
        </div>
    </div>
</div>
<script type="text/javascript">
    //页面加载完以后,直接发送一个ajax请求,要到分页数据
    $(function () {
        //去第一页
       to_page(4);
    });

    function build_emps_table(result) {
        //清空div中的数据
        $("#emps_tables tbody").empty();
        //拿到所有的员工数据
        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            // alert(item.empName);
            var empId = $("<td></td>").append(item.empId);//员工id的td
            var empName = $("<td></td>").append(item.empName);//员工姓名的td
            var gender = $("<td></td>").append(item.gender);//员工性别的td
            var email = $("<td></td>").append(item.email);//员工邮箱的td
            var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
            //编辑按钮
            var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil").append("编辑");
            //删除按钮
            var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove").append("删除");
            //将两个按钮放到一个单元格中
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
            //将单元格加入到tr中,且将tr加入到表格体中
            $("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
        });
    }

    /*
    {"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
    pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
    "nextPage":2,"isFirstPage":true,"isLastPage":false,
    "hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
    "navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
    "navigateLastPage":5}}}
     */
    //解析并显示分页信息
    function build_page_info(result) {
        //清空分页信息数据
        $("#page_info_area").empty();
        //拿到分页数据
        var page_number = result.extend.pageInfo.pageNum;//当前页
        var pages = result.extend.pageInfo.pages;//总页数
        var total = result.extend.pageInfo.total;//总数据条数
        $("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
    }

    //解析并显示分页条信息
    function build_page_nav(result) {
        //page_nav_area
        $("#page_nav_area").empty();
        var ul = $("<ul></ul>").addClass("pagination");
        //构建元素
        var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));
        var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;"));
        //如果有是第一页则添加禁用样式
        if (result.extend.pageInfo.isFirstPage == true) {
            firstPageLi.addClass("disabled");
            prePageLi.addClass("disabled");
        }else {
            //点击时跳转到上一页或前一页
            firstPageLi.click(function (){
                to_page(1);
            });
            prePageLi.click(function (){
                to_page(result.extend.pageInfo.prePage);
            });
        }
        var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
        var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
        //如果有是第最后一页则添加禁用样式
        if (result.extend.pageInfo.isLastPage == true) {
            nextPageLi.addClass("disabled");
            lastPageLi.addClass("disabled");
        }else {
            //点击时跳转到下一页或最后一页
            nextPageLi.click(function (){
                to_page(result.extend.pageInfo.nextPage);
            });
            lastPageLi.click(function (){
                to_page(result.extend.pageInfo.pages);
            });
        }
        //添加首页和前一页 的提示
        ul.append(firstPageLi).append(prePageLi);
        //1,2,3遍历给ul中添加页码提示
        $.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
            var numLi = $("<li></li>").append($("<a></a>").append(item));
            if (result.extend.pageInfo.pageNum == item) {
                numLi.addClass("active");
            }
            numLi.click(function(){
                to_page(item);
            });
            ul.append(numLi);
        });
        //添加下一页和末页 的提示
        ul.append(nextPageLi).append(lastPageLi);
        //把ul加入到nav
        var navEle = $("<nav></nav>").append(ul);
        navEle.appendTo("#page_nav_area");
    }

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

3.2 后台发送返回json数据

3.2.1 新增Msg类专门用于存储数据用于返回
package com.atguigu.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<String, Object>();

    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;
    }
}
3.2.2 导入jackson包
<!--返回json字符串的支持-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
</dependency>
3.2.3 返回json数据的方法

返回json数据的前提条件:

  1. 导入了jackson
  2. 开启了mvc注解驱动<mvc:annotation-driven />
  3. 加入了@ResponseBody注解
  4. 直接返回对象即可,将自动转换成json字符串
@RequestMapping("/emps")
@ResponseBody//直接返回json字符串
public Msg getEmpsWithJson(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
    //开启分页查询
    PageHelper.startPage(pageNumber, 4);
    List<Emp> emps = empService.getAll();
    //navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
    //封装了分页信息与查询结果
    PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
    return Msg.success().add("pageInfo",empPageInfo);
}

4. 实现新增功能

  1. 在index.jsp页面点击"新增”

  2. 弹出新增对话框

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

  4. 用户输入数据进行校验

  5. 完成保存

URI:

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

前端:

<%@ page isELIgnored="false" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
    <!-- web路径:
    不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
    以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
            http://localhost:3306/crud
     -->
    <script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
    <link
            href="${APP_PATH }/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"
            rel="stylesheet">
    <script
            src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<%--员工添加的模态框--%>
<!-- Modal -->
<div class="modal fade" id="empAndModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">员工添加</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">员工姓名</label>
                        <div class="col-sm-10">
                            <input type="text" name="empName" class="form-control" id="empName_add_input"
                                   placeholder="empName">
                            <span id="empName_span" class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" name="email" class="form-control" id="email_add_input"
                                   placeholder="123456@qq.com">
                            <span id="email_span" class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">性别</label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" id="male" value="" checked="checked"></label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" id="remale" value=""></label>
                    </div>
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">所属部门</label>
                        <div class="col-sm-4">
                            <%--部门下拉框--%>
                            <select class="form-control" id="dept_add_select" 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_sava_btn">保存</button>
            </div>
        </div>
    </div>
</div>
<div class="container">
    <!-- 标题 -->
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <!-- 按钮 -->
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>
    <!-- 显示表格数据 -->
    <div class="row">
        <div class="col-md-12">
            <table class="table table-hover" id="emps_tables">
                <thead>
                <tr>
                    <th>#</th>
                    <th>empName</th>
                    <th>gender</th>
                    <th>email</th>
                    <th>deptName</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
    </div>
    <%--显示分页信息--%>
    <div class="row">
        <%--分页信息--%>
        <div class="col-md-6" id="page_info_area">
        </div>
        <%--分页条信息--%>
        <div class="col-md-6" id="page_nav_area">
        </div>
    </div>
</div>
<script type="text/javascript">
    var totalPage;//总记录数
    //页面加载完以后,直接发送一个ajax请求,要到分页数据
    $(function () {
        //去第一页
        to_page(1);
    });

    function build_emps_table(result) {
        //清空div中的数据
        $("#emps_tables tbody").empty();
        //拿到所有的员工数据
        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            // alert(item.empName);
            var empId = $("<td></td>").append(item.empId);//员工id的td
            var empName = $("<td></td>").append(item.empName);//员工姓名的td
            var gender = $("<td></td>").append(item.gender);//员工性别的td
            var email = $("<td></td>").append(item.email);//员工邮箱的td
            var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
            //编辑按钮
            var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil").append("编辑");
            //删除按钮
            var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove").append("删除");
            //将两个按钮放到一个单元格中
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
            //将单元格加入到tr中,且将tr加入到表格体中
            $("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
        });
    }

    /*
    {"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
    pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
    "nextPage":2,"isFirstPage":true,"isLastPage":false,
    "hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
    "navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
    "navigateLastPage":5}}}
     */
    //解析并显示分页信息
    function build_page_info(result) {
        //清空分页信息数据
        $("#page_info_area").empty();
        //拿到分页数据
        var page_number = result.extend.pageInfo.pageNum;//当前页
        var pages = result.extend.pageInfo.pages;//总页数
        var total = result.extend.pageInfo.total;//总数据条数
        totalPage = result.extend.pageInfo.total;
        $("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
    }

    //解析并显示分页条信息
    function build_page_nav(result) {
        //page_nav_area
        $("#page_nav_area").empty();
        var ul = $("<ul></ul>").addClass("pagination");
        //构建元素
        var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));
        var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;"));
        //如果有是第一页则添加禁用样式
        if (result.extend.pageInfo.isFirstPage == true) {
            firstPageLi.addClass("disabled");
            prePageLi.addClass("disabled");
        } else {
            //点击时跳转到上一页或前一页
            firstPageLi.click(function () {
                to_page(1);
            });
            prePageLi.click(function () {
                to_page(result.extend.pageInfo.prePage);
            });
        }
        var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
        var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
        //如果有是第最后一页则添加禁用样式
        if (result.extend.pageInfo.isLastPage == true) {
            nextPageLi.addClass("disabled");
            lastPageLi.addClass("disabled");
        } else {
            //点击时跳转到下一页或最后一页
            nextPageLi.click(function () {
                to_page(result.extend.pageInfo.nextPage);
            });
            lastPageLi.click(function () {
                to_page(result.extend.pageInfo.pages);
            });
        }
        //添加首页和前一页 的提示
        ul.append(firstPageLi).append(prePageLi);
        //1,2,3遍历给ul中添加页码提示
        $.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
            var numLi = $("<li></li>").append($("<a></a>").append(item));
            if (result.extend.pageInfo.pageNum == item) {
                numLi.addClass("active");
            }
            numLi.click(function () {
                to_page(item);
            });
            ul.append(numLi);
        });
        //添加下一页和末页 的提示
        ul.append(nextPageLi).append(lastPageLi);
        //把ul加入到nav
        var navEle = $("<nav></nav>").append(ul);
        navEle.appendTo("#page_nav_area");
    }

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

    //表单重置
    function reset_form(ele){
        //清空表单内容
        $(ele)[0].reset();
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        //清空提示内容
        $(ele).find(".help-block").text("");
    }

    //点击新增按钮弹出模态框
    $("#emp_add_modal_btn").click(function () {
        //清除表单数据(表单重置以及表单样式重置)
        reset_form("#empAndModal form");

        //查出部门信息,显示在下拉框中
        getDepts();
        //弹出模态框
        $("#empAndModal").modal({
            backdrop: "static"
        });
    });

    //查出所有部门信息,并显示在下拉框中
    function getDepts() {
        $.ajax({
            url: "${APP_PATH}/depts",
            type: "GET",
            success: function (result) {
                //清除本来的数据
                $("#dept_add_select").empty();
                //拿到dept的信息并显示在下拉框中
                $.each(result.extend.depts, function (index, item) {
                    $("<option></option>").append(item.deptName).attr("value", item.deptId).appendTo("#dept_add_select");
                });
            }
        });
    }

    //对表单的数据进行校验
    function validate_add_from() {
        //拿到要校验的数据,使用正则表达式
        //校验姓名
        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", "用户名必须是6-16位数字和字母的组合或者2-5位中文");
            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-error").removeClass("has-success");
        if ("error" == status) {
            $(ele).parent().addClass("has-error");
            $(ele).next("span").text(msg);
        } else if ("success" == status) {
            $(ele).parent().addClass("has-success");
            $(ele).next("span").text(msg);
        }

    }

    //发送ajax请求校验用户是否可用
    $("#empName_add_input").change(function () {
        //拿到用户名中的值
        var empName = $("#empName_add_input").val();
        $.ajax({
            url: "${APP_PATH}/checkNmpName",
            type: "GET",
            data: "empName=" + empName,
            success: function (result) {
                //数据库中没有这个人时提示可以使用
                if ("100" == result.code) {
                    show_validate_msg("#empName_add_input", "success", "该用户名可用");
                    $("#emp_sava_btn").attr("ajax-va", "success");
                } else if ("200" == result.code) {//数据库中有这个人时提示不可以使用
                    show_validate_msg("#empName_add_input", "error",
                    result.extend.va_msg);
                    $("#emp_sava_btn").attr("ajax-va", "error");
                }
            }
        });
    });


    //点击保存时保存员工信息
    $("#emp_sava_btn").click(function () {
        //1、模态框中填写的表单数据提交给服务器进行保存
        //校验数据合法性
        if (!validate_add_from()) {
            return false;
        }
        //发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
        if ("error" == $(this).attr("ajax-va")) {
            return false;
        }
        var data = $("#empAndModal form").serialize();//获取到表单中的数据
        //2、发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: data,
            success: function (result) {
                //打印处理成功信息
                alert(result.msg);
                //1、关闭模态框
                $("#empAndModal").modal('hide');
                //2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
                // 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
                to_page(totalPage);
            }
        });
    });
</script>
</body>
</html>

EmpController:

package com.atguigu.crud.controller;

import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
public class EmpController {
    @Autowired
    private EmpService empService;

    /**
     * 分页查询员工信息,正常使用ResponseBody需要导入jackson包才可以转为json字符串的支持
     *
     * @param pageNumber
     * @return
     */
    @RequestMapping("/emps")
    @ResponseBody//直接返回json字符串
    public Msg getEmpsWithJson(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
        //开启分页查询
        PageHelper.startPage(pageNumber, 4);
        List<Emp> emps = empService.getAll();
        //navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
        //封装了分页信息与查询结果
        PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);
        return Msg.success().add("pageInfo", empPageInfo);
    }

    /**
     * 插入员工信息
     *
     * @return
     */
    @RequestMapping(value = "/emp", method = RequestMethod.POST)
    @ResponseBody
    public Msg saveEmp(Emp emp) {
        System.out.println(emp);
        empService.savaEmp(emp);
        return Msg.success();
    }

    /**
     * 检查用户名是否可用,可用返回ture,不可用返回false
     *
     * @param empName
     * @return
     */
    @RequestMapping(value = "/checkNmpName")
    @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位中文");
        }
        //数据库用户名重复校验
        //可用则返回状态码100
        if (empService.checkNotHasNmpName(empName)) {
            return Msg.success();
        } else {//不可用则返回状态码200
            return Msg.fail().add("va_msg","用户名被占用");
        }
    }


    /**
     * 分页查询所有员工信息
     *
     * @return
     */
//    @RequestMapping("/emps")
    public ModelAndView getEmps(@RequestParam(value = "pageNumber", defaultValue = "1") Integer pageNumber) {
        ModelAndView modelAndView = new ModelAndView();

        //开启分页查询
        PageHelper.startPage(pageNumber, 4);
        List<Emp> emps = empService.getAll();
        //navigate为展示的页码数量,比如5个就是 能看到1 2 3 4 5页
        //封装了分页信息与查询结果
        PageInfo<Emp> empPageInfo = new PageInfo<>(emps, 5);

        modelAndView.addObject("pageInfo", empPageInfo);
        modelAndView.setViewName("list");
        return modelAndView;
    }
}

EmpService:

package com.atguigu.crud.service;

import com.atguigu.crud.bean.Emp;
import com.atguigu.crud.bean.EmpExample;
import com.atguigu.crud.dao.EmpMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmpService {
    @Autowired
    private EmpMapper empMapper;

    /**
     * 查询所有员工信息
     * @return
     */
    public List<Emp> getAll() {
        return empMapper.selectByExampleWithDept(null);
    }

    /**
     * 保存员工
     */
    public void savaEmp(Emp emp) {
        empMapper.insertSelective(emp);
    }

    /**
     * 检查数据库中是否已经有了empName,如果有则返回false,没有则返回true
     * @param empName
     */
    public boolean checkNotHasNmpName(String empName) {
        EmpExample example = new EmpExample();
        example.createCriteria().andEmpNameEqualTo(empName);
        long count = empMapper.countByExample(example);
        return count == 0;
    }
}

DeptController:

package com.atguigu.crud.controller;

import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.bean.Msg;
import com.atguigu.crud.service.DeptService;
import com.atguigu.crud.service.EmpService;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
public class DeptController {
    @Autowired
    private DeptService deptService;

    /**
     * 查询所有员工数据
     * @param pageNumber
     * @return
     */
    @RequestMapping("/depts")
    @ResponseBody
    public Msg getDepts(@RequestParam(value="pageNumber",defaultValue = "1") Integer pageNumber){
        List<Dept> depts = deptService.getDepts();
        Msg msg = Msg.success().add("depts", depts);
        return msg;
    }
}

DeptService:

package com.atguigu.crud.service;

import com.atguigu.crud.bean.Dept;
import com.atguigu.crud.dao.DeptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptService {
    @Autowired
    private DeptMapper deptMapper;

    public List<Dept> getDepts() {
        return deptMapper.selectByExample(null);
    }
}

4.1 加入后端校验(JSR303)

虽然前端做了数据校验,但是前端的数据可以更改,所以需要加上后端重要数据校验,(后端校验(SR303),唯一约束)。

  1. 导入Hibernate-Validator的jar包

  2. 给javabean的要校验的属性加上@Pattern注解

package com.atguigu.crud.bean;

import javax.validation.constraints.Pattern;

public class Emp {
    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column tbl_emp.emp_id
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    private Integer empId;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column tbl_emp.emp_name
     *
     * @mbg.generated Wed Sep 21 17:24:14 CST 2022
     */
    @Pattern(regexp = "([a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})", message = "用户名必须是6-16位数字和字母的组合或者2-5位中文")
    private String empName;
}
  1. 在方法中添加注解@Valid进行校验,用BindingResult来接收校验后的结果
/**
 * 插入员工信息
 *
 * @return
 */
@RequestMapping(value = "/emp", method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(@Valid Emp emp, BindingResult result) {
    if (result.hasErrors()) {
        //校验失败,应该返回失败,在模态框中显示校验失败的错误信息
        List<FieldError> fieldErrors = result.getFieldErrors();
        HashMap<String, Object> map = new HashMap<>();
        for (FieldError fieldError : fieldErrors) {
            System.out.println("错误的字段名:" + fieldError.getField());
            System.out.println("错误信息:" + fieldError.getDefaultMessage());
            //将错误字段和信息存储在map中
            map.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        return Msg.fail().add("errorFields", map);
    } else {
        empService.savaEmp(emp);
        return Msg.success();
    }
}
  1. 前端对后端返回的错误信息进行展示,或将成功信息展示
 //点击保存时保存员工信息
    $("#emp_sava_btn").click(function () {
        //1、模态框中填写的表单数据提交给服务器进行保存
        //校验数据合法性
        if (!validate_add_from()) {
            return false;
        }
        //发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
        if ("error" == $(this).attr("ajax-va")) {
            return false;
        }
        var data = $("#empAndModal form").serialize();//获取到表单中的数据
        //2、发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: data,
            success: function (result) {
                //code=100说明后台校验没问题
                if (result.code == 100) {
                    //打印处理成功信息
                    // alert(result.msg);
                    //1、关闭模态框
                    $("#empAndModal").modal('hide');
                    //2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
                    // 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
                    to_page(totalPage);
                } else {
                    //当后台校验出现问题的时候,显示失败信息
                    //有哪个字段的错误信息就显示哪个
                    if (undefined != result.extend.errorFields.email) {//邮箱不是未定义,则说明有错误返回
                        show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                    } else if (undefined != result.extend.errorFields.empName) {
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        });
    });

5. 实现编辑功能

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

前端:

<%@ page isELIgnored="false" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>员工列表</title>
    <%
        pageContext.setAttribute("APP_PATH", request.getContextPath());
    %>
    <!-- web路径:
    不以/开始的相对路径,找资源,以当前资源的路径为基准,经常容易出问题。
    以/开始的相对路径,找资源,以服务器的路径为标准(http://localhost:3306);需要加上项目名
            http://localhost:3306/crud
     -->
    <script src="${APP_PATH}/static/js/jquery-3.6.0.min.js"></script>
    <link
            href="${APP_PATH }/static/bootstrap-3.4.1-dist/css/bootstrap.min.css"
            rel="stylesheet">
    <script
            src="${APP_PATH }/static/bootstrap-3.4.1-dist/js/bootstrap.min.js"></script>
</head>
<body>
<!-- 搭建显示页面 -->
<%--员工添加的模态框--%>
<!-- Modal -->
<div class="modal fade" id="empAndModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">员工添加</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_add_input" class="col-sm-2 control-label">员工姓名</label>
                        <div class="col-sm-10">
                            <input type="text" name="empName" class="form-control" id="empName_add_input"
                                   placeholder="empName">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_add_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" name="email" class="form-control" id="email_add_input"
                                   placeholder="123456@qq.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">性别</label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" id="male" value="" checked="checked"></label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" id="remale" value=""></label>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">部门</label>
                        <div class="col-sm-4">
                            <%--部门下拉框--%>
                            <select class="form-control" id="dept_add_select" 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_sava_btn">保存</button>
            </div>
        </div>
    </div>
</div>
<%--员工编辑的模态框--%>
<div class="modal fade" id="empUpdateModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">员工编辑</h4>
            </div>
            <div class="modal-body">
                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="empName_update_static" class="col-sm-2 control-label">员工姓名</label>
                        <div class="col-sm-10">
                            <p class="form-control-static" id="empName_update_static"></p>
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="email_update_input" class="col-sm-2 control-label">email</label>
                        <div class="col-sm-10">
                            <input type="email" name="email" class="form-control" id="email_update_input"
                                   placeholder="123456@qq.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">性别</label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" value="" checked="checked"></label>
                        <label class="radio-inline">
                            <input type="radio" name="gender" value=""></label>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">部门</label>
                        <div class="col-sm-4">
                            <%--部门下拉框--%>
                            <select class="form-control" id="dept_update_select" name="did">
                            </select>
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                <button type="button" class="btn btn-primary" id="emp_update_btn">更新</button>
            </div>
        </div>
    </div>
</div>

<div class="container">
    <!-- 标题 -->
    <div class="row">
        <div class="col-md-12">
            <h1>SSM-CRUD</h1>
        </div>
    </div>
    <!-- 按钮 -->
    <div class="row">
        <div class="col-md-4 col-md-offset-8">
            <button class="btn btn-primary" id="emp_add_modal_btn">新增</button>
            <button class="btn btn-danger">删除</button>
        </div>
    </div>
    <!-- 显示表格数据 -->
    <div class="row">
        <div class="col-md-12">
            <table class="table table-hover" id="emps_tables">
                <thead>
                <tr>
                    <th>id</th>
                    <th>empName</th>
                    <th>gender</th>
                    <th>email</th>
                    <th>deptName</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                </tbody>
            </table>
        </div>
    </div>
    <%--显示分页信息--%>
    <div class="row">
        <%--分页信息--%>
        <div class="col-md-6" id="page_info_area">
        </div>
        <%--分页条信息--%>
        <div class="col-md-6" id="page_nav_area">
        </div>
    </div>
</div>
<script type="text/javascript">
    var totalRecord;//总记录数
    var currentNum;//当前页码
    //页面加载完以后,直接发送一个ajax请求,要到分页数据
    $(function () {
        //去第一页
        to_page(1);
    });

    function build_emps_table(result) {
        //清空div中的数据
        $("#emps_tables tbody").empty();
        //拿到所有的员工数据
        var emps = result.extend.pageInfo.list;
        $.each(emps, function (index, item) {
            // alert(item.empName);
            var empId = $("<td></td>").append(item.empId);//员工id的td
            var empName = $("<td></td>").append(item.empName);//员工姓名的td
            var gender = $("<td></td>").append(item.gender);//员工性别的td
            var email = $("<td></td>").append(item.email);//员工邮箱的td
            var deptName = $("<td></td>").append(item.dept.deptName);//员工所属部门名称的td
            //编辑按钮
            var editBtn = $("<button></button>").addClass("btn btn-primary btn-sm").append("<span></span>").addClass("glyphicon glyphicon-pencil edit_btn").append("编辑");
            //为编辑按钮添加一个自定义的属性,来表示当前员工id
            editBtn.attr("edit-id", item.empId);
            //删除按钮
            var deleteBtn = $("<button></button>").addClass("btn btn-danger btn-sm").append("<span></span>").addClass("glyphicon glyphicon-remove delete_btn").append("删除");
            //为删除按钮添加一个自定义的属性,来表示当前员工id
            deleteBtn.attr("delete-id", item.empId);
            //将两个按钮放到一个单元格中
            var btnTd = $("<td></td>").append(editBtn).append(" ").append(deleteBtn);
            //将单元格加入到tr中,且将tr加入到表格体中
            $("<tr></tr>").append(empId).append(empName).append(gender).append(email).append(deptName).append(btnTd).appendTo("#emps_tables tbody");
        });
    }

    /*
    {"code":100,"msg":"处理成功!","extend":{"pageInfo":{"total":1002,
    pageNum":1,"pageSize":4,"size":4,"startRow":1,"endRow":4,"pages":251,"prePage":0,
    "nextPage":2,"isFirstPage":true,"isLastPage":false,
    "hasPreviousPage":false,"hasNextPage":true,"navigatePages":5,
    "navigatepageNums":[1,2,3,4,5],"navigateFirstPage":1,
    "navigateLastPage":5}}}
     */
    //解析并显示分页信息
    function build_page_info(result) {
        //清空分页信息数据
        $("#page_info_area").empty();
        //拿到分页数据
        var page_number = result.extend.pageInfo.pageNum;//当前页
        currentNum = page_number;
        var pages = result.extend.pageInfo.pages;//总页数
        var total = result.extend.pageInfo.total;//总数据条数
        totalRecord = total;
        $("#page_info_area").append("当前是第 " + page_number + " 页,总 " + pages + " 页,总 " + total + " 条数据")
    }

    //解析并显示分页条信息
    function build_page_nav(result) {
        //page_nav_area
        $("#page_nav_area").empty();
        var ul = $("<ul></ul>").addClass("pagination");
        //构建元素
        var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href", "#"));
        var prePageLi = $("<li></li>").append($("<a></a>").append("&laquo;"));
        //如果有是第一页则添加禁用样式
        if (result.extend.pageInfo.isFirstPage == true) {
            firstPageLi.addClass("disabled");
            prePageLi.addClass("disabled");
        } else {
            //点击时跳转到上一页或前一页
            firstPageLi.click(function () {
                to_page(1);
            });
            prePageLi.click(function () {
                to_page(result.extend.pageInfo.prePage);
            });
        }
        var nextPageLi = $("<li></li>").append($("<a></a>").append("&raquo;"));
        var lastPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href", "#"));
        //如果有是第最后一页则添加禁用样式
        if (result.extend.pageInfo.isLastPage == true) {
            nextPageLi.addClass("disabled");
            lastPageLi.addClass("disabled");
        } else {
            //点击时跳转到下一页或最后一页
            nextPageLi.click(function () {
                to_page(result.extend.pageInfo.nextPage);
            });
            lastPageLi.click(function () {
                to_page(result.extend.pageInfo.pages);
            });
        }
        //添加首页和前一页 的提示
        ul.append(firstPageLi).append(prePageLi);
        //1,2,3遍历给ul中添加页码提示
        $.each(result.extend.pageInfo.navigatepageNums, function (index, item) {
            var numLi = $("<li></li>").append($("<a></a>").append(item));
            if (result.extend.pageInfo.pageNum == item) {
                numLi.addClass("active");
            }
            numLi.click(function () {
                to_page(item);
            });
            ul.append(numLi);
        });
        //添加下一页和末页 的提示
        ul.append(nextPageLi).append(lastPageLi);
        //把ul加入到nav
        var navEle = $("<nav></nav>").append(ul);
        navEle.appendTo("#page_nav_area");
    }

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

    //表单重置
    function reset_form(ele) {
        //清空表单内容
        $(ele)[0].reset();
        //清空表单样式
        $(ele).find("*").removeClass("has-error has-success");
        //清空提示内容
        $(ele).find(".help-block").text("");
    }

    //点击新增按钮弹出模态框
    $("#emp_add_modal_btn").click(function () {
        //清除表单数据(表单重置以及表单样式重置)
        reset_form("#empAndModal form");
        //查出部门信息,显示在下拉框中
        getDepts("#dept_add_select");
        //弹出模态框
        $("#empAndModal").modal({
            backdrop: "static"
        });
    });

    //点击更新按钮,更新员工信息
    $("#emp_update_btn").click(function () {
        //验证邮箱是否合法
        //验证邮箱信息
        var email = $("#email_update_input").val();
        var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
        if (!regEmail.test(email)) {
            show_validate_msg("#email_update_input", "error", "邮箱格式不正确")
            return false;
        } else {
            show_validate_msg("#email_update_input", "success", "");
        }
        //发送ajax请求保存更新的员工数据
        $.ajax({
            url: "${APP_PATH}/emp/" + $(this).attr("edit-id"),
            type: "PUT",
            data: $("#empUpdateModal form").serialize(),
            success: function (result) {
                //关闭对话框
                $("#empUpdateModal").modal('hide');
                //回到编辑的那一个页面
                to_page(currentNum);
            }
        });
    });

    //我们是按钮创建之前就绑定了click,所以绑定不上
    //方式一:可以在创建按钮的时候绑定事件
    //方式二:live()可以为后来的元素绑定事件,但是新版本已经删除了,现在用on()
    //点击编辑按钮弹出模态框
    $(document).on("click", ".edit_btn", function () {
        //清除表单数据(表单重置以及表单样式重置)
        reset_form("#empUpdateModal form");
        //1、查出部门列表
        getDepts("#dept_update_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;//获取到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]);
            }
        });
    }

    //查出所有部门信息,并显示在下拉框中
    function getDepts(ele) {
        $.ajax({
            url: "${APP_PATH}/depts",
            type: "GET",
            success: function (result) {
                //清除本来的数据
                $(ele).empty();
                //拿到dept的信息并显示在下拉框中
                $.each(result.extend.depts, function (index, item) {
                    $("<option></option>").append(item.deptName).attr("value", item.deptId).appendTo(ele);
                });
            }
        });
    }

    //对表单的数据进行校验
    function validate_add_from() {
        //拿到要校验的数据,使用正则表达式
        //校验姓名
        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", "用户名必须是6-16位数字和字母的组合或者2-5位中文");
            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-error").removeClass("has-success");
        if ("error" == status) {
            $(ele).parent().addClass("has-error");
            $(ele).next("span").text(msg);
        } else if ("success" == status) {
            $(ele).parent().addClass("has-success");
            $(ele).next("span").text(msg);
        }

    }

    //发送ajax请求校验用户是否可用
    $("#empName_add_input").change(function () {
        //拿到用户名中的值
        var empName = $("#empName_add_input").val();
        $.ajax({
            url: "${APP_PATH}/checkNmpName",
            type: "GET",
            data: "empName=" + empName,
            success: function (result) {
                //数据库中没有这个人时提示可以使用
                if ("100" == result.code) {
                    show_validate_msg("#empName_add_input", "success", "该用户名可用");
                    $("#emp_sava_btn").attr("ajax-va", "success");
                } else if ("200" == result.code) {//数据库中有这个人时提示不可以使用
                    show_validate_msg("#empName_add_input", "error",
                        result.extend.va_msg);
                    $("#emp_sava_btn").attr("ajax-va", "error");
                }
            }
        });
    });


    //点击保存时保存员工信息
    $("#emp_sava_btn").click(function () {
        //1、模态框中填写的表单数据提交给服务器进行保存
        //校验数据合法性
        if (!validate_add_from()) {
            return false;
        }
        //发送ajax请求前看看用户名是否校验成功,如果成功则往下走,不成功则不允许添加
        if ("error" == $(this).attr("ajax-va")) {
            return false;
        }
        var data = $("#empAndModal form").serialize();//获取到表单中的数据
        //2、发送ajax请求保存员工
        $.ajax({
            url: "${APP_PATH}/emp",
            type: "POST",
            data: data,
            success: function (result) {
                //code=100说明后台校验没问题
                if (result.code == 100) {
                    //打印处理成功信息
                    // alert(result.msg);
                    //1、关闭模态框
                    $("#empAndModal").modal('hide');
                    //2、跳转到最后一页查看数据,传一个大于总页码的数据即可,
                    // 因为后端配置了大于总页码的时候会变成最后一页,可以用总记录数
                    to_page(totalRecord);
                } else {
                    //当后台校验出现问题的时候,显示失败信息
                    //有哪个字段的错误信息就显示哪个
                    if (undefined != result.extend.errorFields.email) {//邮箱不是未定义,则说明有错误返回
                        show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
                    } else if (undefined != result.extend.errorFields.empName) {
                        show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
                    }
                }
            }
        });
    });
</script>
</body>
</html>

后端:

EmpController:

/**
 * 如果直接用ajax发送put请求,会遇到一个问题:请求体中有数据,但是Emp对象封装不上
 * 原因:这是tomcat的问题
 * 1、请求体中的数据,会封装成一个map
 * 2、reqeust.getParameter("empName")就会从这个map中取值
 * 3、SpringMVC封装POJO对象的时候,会把POJO中的每个属性的值都用request.getParameter("属性名取出")
 * 4、但是request.getParameter()拿不到数据,因为tomcat看到是put请求,就不会去封装数据为map,只有post请求才封装请求体。
 * 5、解决方法:需要在web.xml中添加一个过滤器:HttpPutFormContentFilter,它的作用是将请求体中的数据解析包装成一个map,
 * request被重新包装,request.getParameter()被重写,就会从自己封装的map中获取数据
 *
 * @param emp
 * @return
 */
@PutMapping("/emp/{empId}")//这个{}中的名字需要跟Emp类中的属性名一致,否则注入不进去
@ResponseBody
public Msg updateEmp(Emp emp){
    empService.updateEmp(emp);
    return Msg.success();
}

EmpService:

/**
 * 员工更新
 * @param emp
 */
public void updateEmp(Emp emp) {
    empMapper.updateByPrimaryKeySelective(emp);
}

6. 实现删除功能

前端新增逻辑:

//点击删除按钮,单个删除
    $(document).on("click", ".delete_btn", function () {
        //弹出确认删除对话框
        var empName = $(this).parents("tr").find("td:eq(2)").text();
        var deleteId = $(this).attr("delete-id");//获取要删除的员工id
        if (confirm("确认删除【" + empName + "】吗?")) {
            //确认,发送ajax请求删除
            $.ajax({
                url: "${APP_PATH}/emp/" + deleteId,
                type: "delete",
                success: function (result) {
                    alert(result.msg);
                    to_page(currentNum);//跳转到当前页
                }
            });
        }
    });


    //完成全选、全不选功能
    $("#checkall").click(function () {
        //dom原生的属性用prop,attr可以用来获取自定义属性的值
        var checked = $("#checkall").prop("checked");//选中返回true,没有选中返回false
        $(".check_item").prop("checked", checked);//将下面的单选框状态变得跟checkall一样
    });
    //勾选全部单选框时自动选中全选框
    $(document).on("click", ".check_item", function () {
        //判断当前选中的元素是不是选满了
        var flag = $(".check_item:checked").length == $(".check_item").length;//判断选中的个数是否是总个数
        $("#checkall").prop("checked", flag);//如果flag为true则赋值,否则不复赋值
    });
    //完成全部删除
    $("#delete_all").click(function () {
        //找到被选中的单选框
        var delete_emp_name = "";
        var deleteIds = "";
        $.each($(".check_item:checked"), function () {
            delete_emp_name += $(this).parents("tr").find("td:eq(2)").text() + ",";//组装员工名字的字符串
            deleteIds += $(this).parents("tr").find("td:eq(1)").text()+"-";//组装员工id字符串 1-2-3
        });
        //去除最后多余的符号
        delete_emp_name = delete_emp_name.substring(0,delete_emp_name.length-1);
        deleteIds = deleteIds.substring(0,deleteIds.length-1);
        if (confirm("确认删除" + delete_emp_name + "吗?")) {
            //确认,发送ajax请求删除
            $.ajax({
                url: "${APP_PATH}/emp/" + deleteIds,
                type: "DELETE",
                success: function (result) {
                    alert(result.msg);
                    to_page(currentNum);//跳转到当前页
                }
            });
        }
    });

后端删除方法:

EmpControlelr:

/**
     * 单个或批量删除
     * 批量删除:1-2-3
     * 单个删除:1
     *
     * @param ids
     * @return
     */
    @RequestMapping(value = "/emp/{ids}", method = RequestMethod.DELETE)
    @ResponseBody
    public Msg deleteEmp(@PathVariable("ids") String ids) {
        if (ids.contains("-")) {
            String[] split = ids.split("-");//分割id
            //转换成list
            ArrayList<Integer> ints = new ArrayList<>();
            for (String s : split) {
                ints.add(Integer.parseInt(s));
            }

            empService.deleteBatchEmp(ints);//批量删除
            return Msg.success();
        } else {
            empService.deleteEmp(Integer.parseInt(ids));
            return Msg.success();
        }
    }

EmpService:

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

    /**
     * 批量删除
     * @param ids
     */
    public void deleteBatchEmp(List<Integer> ids) {
        EmpExample empExample = new EmpExample();
        //delete from table_name where id = {1,2,3}
        empExample.createCriteria().andEmpIdIn(ids);
        empMapper.deleteByExample(empExample);
    }

四、遇到的问题

记录错误无法自动装配。未找到 ‘xxxService‘ 类型的 Bean

记录错误 Method com/mchange/v2/c3p0/impl/NewProxyResultSet.isClosed()Z is abstract

put请求无法自动注入的问题:

/**
 * 如果直接用ajax发送put请求,会遇到一个问题:请求体中有数据,但是Emp对象封装不上
 * 原因:这是tomcat的问题
 * 1、请求体中的数据,会封装成一个map
 * 2、reqeust.getParameter("empName")就会从这个map中取值
 * 3、SpringMVC封装POJO对象的时候,会把POJO中的每个属性的值都用request.getParameter("属性名取出")
 * 4、但是request.getParameter()拿不到数据,因为tomcat看到是put请求,就不会去封装数据为map,只有post请求才封装请求体。
 * 5、解决方法:需要在web.xml中添加一个过滤器:HttpPutFormContentFilter,它的作用是将请求体中的数据解析包装成一个map,
 * request被重新包装,request.getParameter()被重写,就会从自己封装的map中获取数据
 *
 * @param emp
 * @return
 */
@PutMapping("/emp/{empId}")//这个{}中的名字需要跟Emp类中的属性名一致,否则注入不进去
@ResponseBody
public Msg updateEmp(Emp emp){
    empService.updateEmp(emp);
    return Msg.success();
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SSM项目整合Shiro的步骤如下: 1. 引入Shiro的依赖,可以在pom.xml文件中添加以下代码: ```xml <!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.0</version> </dependency> ``` 2. 在Spring配置文件中配置Shiro的相关信息,例如Shiro的安全管理器、Shiro的过滤器链等。可以在applicationContext.xml文件中添加以下代码: ```xml <!-- 配置Shiro的安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="myRealm"/> </bean> <!-- 配置Shiro的自定义Realm --> <bean id="myRealm" class="com.example.shirodemo.realm.MyRealm"> <property name="credentialsMatcher" ref="hashedCredentialsMatcher"/> </bean> <!-- 配置Shiro的密码匹配器 --> <bean id="hashedCredentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> </bean> <!-- 配置Shiro的过滤器链 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login"/> <property name="successUrl" value="/index"/> <property name="unauthorizedUrl" value="/unauthorized"/> <property name="filterChainDefinitions"> <value> /login = anon /logout = logout /** = authc </value> </property> </bean> ``` 3. 创建自定义Realm,继承org.apache.shiro.realm.Realm接口,并实现其中的方法。可以创建一个MyRealm类,代码如下: ```java public class MyRealm implements Realm { @Autowired private UserService userService; @Override public String getName() { return "myRealm"; } @Override public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); User user = userService.getUserByUsername(username); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ``` 4. 在Controller中使用Shiro进行权限控制。可以在UserController中添加以下代码: ```java @Controller public class UserController { @RequestMapping("/user/list") @RequiresPermissions("user:list") public String list() { return "user/list"; } @RequestMapping("/user/add") @RequiresPermissions("user:add") public String add() { return "user/add"; } @RequestMapping("/user/edit") @RequiresPermissions("user:edit") public String edit() { return "user/edit"; } @RequestMapping("/user/delete") @RequiresPermissions("user:delete") public String delete() { return "user/delete"; } } ``` 以上是SSM项目整合Shiro的基本步骤,可以根据具体需求进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值