SSM整合

SSM整合

ContextLoaderListener

  • 整合Spring和SpringMVC:各自管理自己的组件

  • SpringMVC的IOC容器在DispatchederServlet初始化时创建

  • 由于SpringMVC的Controller依赖于Spring的Service(内部的Service需要提前装配,因此需要获得Service的bean),因此创建SpringMVC的IOC容器前,需要先创建Spring的IOC容器

  • Spring提供监听器ContextLoaderListener,实现ServletContextListener接口,可监听 ServletContext 的状态(启动与关闭)

    • public void contextInitialize
  • 监听器在Servlet创建之前创建,并且只执行一次初始化,可以利用这一特点,在Web服务器的启动时读取 Spring 的配置文件,创建Spring的IOC容器——web 应用中必须在web.xml中配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!--配置Spring的监听器,在服务器启动时加载Spring的配置文件-->
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--设置Spring配置文件自定义的位置和名称-->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:Spring.xml</param-value>
    </context-param>
  • 这里,SpringMVC的IOC容器,能够访问Spring的IOC容器内容——Spring是父容器,子容器可以访问父容器的bean

配置

  • 依赖(pom.xml):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>

    <spring.version>5.2.14.RELEASE</spring.version>
    </properties>
    <packaging>war</packaging>

    <dependencies>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <!--springmvc-->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    </dependency>
    <!-- Mybatis核心 -->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
    </dependency>
    <!--mybatis和spring的整合包-->
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.4</version>
    </dependency>
    <!-- 连接池 -->
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.23</version>
    </dependency>
    <!-- junit测试 -->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.3</version>
    </dependency>
    <!-- log4j日志 -->
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
    <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
    </dependency>
    <!-- 日志 -->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>
    <!-- ServletAPI -->
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
    </dependency>
    <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
    </dependency>
    <!-- Spring5和Thymeleaf整合包 -->
    <dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.12.RELEASE</version>
    </dependency>
    </dependencies>
  • 创建表格:

    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE `t_emp` (
    `emp_id` int(11) NOT NULL AUTO_INCREMENT,
    `emp_name` varchar(20) DEFAULT NULL,
    `age` int(11) DEFAULT NULL,
    `sex` char(1) DEFAULT NULL,
    `email` varchar(50) DEFAULT NULL,
    PRIMARY KEY (`emp_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • web.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    <!--配置Spring的编码过滤器-->
    <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>forceEncoding</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的前端控制器DispatcherServlet-->
    <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--设置SpringMVC配置文件自定义的位置和名称-->
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <!--将DispatcherServlet的初始化时间提前到服务器启动时-->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--配置Spring的监听器,在服务器启动时加载Spring的配置文件-->
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--设置Spring配置文件自定义的位置和名称-->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:Spring.xml</param-value>
    </context-param>
  • SpringMVC.xml:

  • MyBatis环境:

    • 属性文件(jdbc.properties):

      1
      2
      3
      4
      jdbc.user=root
      jdbc.password=123456
      jdbc.url=jdbc:mysql://localhost:3306/testssm?useUnicode=true&characterEncoding=utf8
      jdbc.driver=com.mysql.jdbc.Driver
    • 核心配置文件(mybatis-config.xml):

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      <configuration>

      <!--
      MyBatis核心配置文件中的标签必须要按照指定的顺序配置:
      properties?,settings?,typeAliases?,typeHandlers?,
      objectFactory?,objectWrapperFactory?,reflectorFactory?,
      plugins?,environments?,databaseIdProvider?,mappers?
      -->

      <settings>
      <!--将下划线映射为驼峰-->
      <setting name="mapUnderscoreToCamelCase" value="true"/>
      </settings>

      <plugins>
      <!--配置分页插件-->
      <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
      </plugins>

      </configuration>
    • 日志配置(log4j.xml)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

      <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

      <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
      <param name="Encoding" value="UTF-8" />
      <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
      </layout>
      </appender>
      <logger name="java.sql">
      <level value="debug" />
      </logger>
      <logger name="org.apache.ibatis">
      <level value="info" />
      </logger>
      <root>
      <level value="debug" />
      <appender-ref ref="STDOUT" />
      </root>
      </log4j:configuration>
  • Spring配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--扫描组件(除控制层),控制层的组件由SpringMVC.xml负责扫描-->
    <context:component-scan base-package="Service">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--引入jdbc.properties-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--
    开启事务的注解驱动,使用注解@Transactional标识方法或类中所有的方法进行事务管理
    -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!--配置SqlSessionFactoryBean,可以直接在Spring的IOC中获取SqlSessionFactory-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--设置MyBatis的核心配置文件的路径-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <!--设置数据源-->
    <property name="dataSource" ref="dataSource"/>
    <!--设置类型别名所对应的包-->
    <property name="typeAliasesPackage" value="Pojo"/>
    <!--设置映射文件的路径,只有映射文件的包和mapper接口的包不一致时需要设置-->
    <property name="mapperLocations" value="classpath:mappers/*.xml"/>
    </bean>

    <!--
    配置mapper接口的扫描,可以将指定包下所有的mapper接口
    通过SqlSession创建代理实现类对象,并将这些对象交给IOC容器管理
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="Mapper"/>
    </bean>

    </beans>
  • Dao层:

    • 实体类:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      package Pojo;

      public class Employee {
      private Integer empId;
      private String empName;
      private Integer age;
      private String gender;
      private String email;
      public Employee() {
      }
      public Employee(Integer empId, String empName, Integer age, String gender, String email) {
      this.empId = empId;
      this.empName = empName;
      this.age = age;
      this.gender = gender;
      this.email = email;
      }
      public Integer getEmpId() {
      return empId;
      }
      public void setEmpId(Integer empId) {
      this.empId = empId;
      }
      public String getEmpName() {
      return empName;
      }
      public void setEmpName(String empName) {
      this.empName = empName;
      }
      public Integer getAge() {
      return age;
      }
      public void setAge(Integer age) {
      this.age = age;
      }
      public String getGender() {
      return gender;
      }
      public void setGender(String gender) {
      this.gender = gender;
      }
      public String getEmail() {
      return email;
      }
      public void setEmail(String email) {
      this.email = email;
      }
      @Override
      public String toString() {
      return "Employee{" +
      "empId=" + empId +
      ", empName='" + empName + '\'' +
      ", age=" + age +
      ", gender='" + gender + '\'' +
      ", email='" + email + '\'' +
      '}';
      }
      }
    • mapper:

      • 映射接口:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        package Mapper;

        import Pojo.Employee;

        import java.util.List;

        public interface EmployeeMapper {

        /**
        * 查询所有的员工信息
        * @return
        */
        List<Employee> getAllEmployee();
        }
      • 映射文件:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

        <mapper namespace="Mapper.EmployeeMapper">

        <!--List<Employee> getAllEmployee();-->
        <select id="getAllEmployee" resultType="Employee">
        select * from t_emp
        </select>

        </mapper>
  • Service层:

    • Service接口:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      package Service;

      import Pojo.Employee;
      import com.github.pagehelper.PageInfo;

      import java.util.List;


      public interface EmployeeService {

      /**
      * 查询所有的员工信息
      * @return
      */
      List<Employee> getAllEmployee();

      /**
      * 获取员工的分页信息
      * @param pageNum
      * @return
      */
      PageInfo<Employee> getEmployeePage(Integer pageNum);
      }
    • Service实现类:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      package Service.Imp;

      import Mapper.EmployeeMapper;
      import Pojo.Employee;
      import Service.EmployeeService;
      import com.github.pagehelper.PageHelper;
      import com.github.pagehelper.PageInfo;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;

      import java.util.List;

      @Service
      @Transactional
      public class EmployeeServiceImpl implements EmployeeService {

      @Autowired
      private EmployeeMapper employeeMapper;

      @Override
      public List<Employee> getAllEmployee() {
      return employeeMapper.getAllEmployee();
      }

      @Override
      public PageInfo<Employee> getEmployeePage(Integer pageNum) {
      //开启分页功能
      PageHelper.startPage(pageNum, 4);
      //查询所有的员工信息
      List<Employee> list = employeeMapper.getAllEmployee();
      //获取分页相关数据
      return new PageInfo<>(list, 5);
      }
      }
  • Controller层:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package Controller;

    import Pojo.Employee;
    import Service.EmployeeService;
    import com.github.pagehelper.PageInfo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;

    import java.util.List;

    @Controller
    public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @RequestMapping(value = "/employee/page/{pageNum}", method = RequestMethod.GET)
    public String getEmployeePage(@PathVariable("pageNum") Integer pageNum, Model model){
    //获取员工的分页信息
    PageInfo<Employee> page = employeeService.getEmployeePage(pageNum);
    //将分页数据共享到请求域中
    model.addAttribute("page", page);
    //跳转到employee_list.html
    return "employee_list";
    }

    @RequestMapping(value = "/employee", method = RequestMethod.GET)
    public String getAllEmployee(Model model){
    //查询所有的员工信息
    List<Employee> list = employeeService.getAllEmployee();
    //将员工信息在请求域中共享
    model.addAttribute("list", list);
    //跳转到employee_list.html
    return "employee_list";
    }

    }
  • 视图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>员工列表</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    </head>
    <body>
    <table>
    <tr>
    <th colspan="6">员工列表</th>
    </tr>
    <tr>
    <th>流水号</th>
    <th>员工姓名</th>
    <th>年龄</th>
    <th>性别</th>
    <th>邮箱</th>
    <th>操作</th>
    </tr>
    <tr th:each="employee,status : ${page.list}">
    <td th:text="${status.count}"></td>
    <td th:text="${employee.empName}"></td>
    <td th:text="${employee.age}"></td>
    <td th:text="${employee.gender}"></td>
    <td th:text="${employee.email}"></td>
    <td>
    <a href="">删除</a>
    <a href="">修改</a>
    </td>
    </tr>
    </table>
    <div style="text-align: center;">
    <a th:if="${page.hasPreviousPage}" th:href="@{/employee/page/1}">首页</a>
    <a th:if="${page.hasPreviousPage}" th:href="@{'/employee/page/'+${page.prePage}}">上一页</a>
    <span th:each="num : ${page.navigatepageNums}">
    <a th:if="${page.pageNum == num}" style="color: red;" th:href="@{'/employee/page/'+${num}}" th:text="'['+${num}+']'"></a>
    <a th:if="${page.pageNum != num}" th:href="@{'/employee/page/'+${num}}" th:text="${num}"></a>
    </span>
    <a th:if="${page.hasNextPage}" th:href="@{'/employee/page/'+${page.nextPage}}">下一页</a>
    <a th:if="${page.hasNextPage}" th:href="@{'/employee/page/'+${page.pages}}">末页</a>
    </div>
    </body>
    </html>
    1
    <a th:href="@{/employee/page/1}">查询员工的分页信息</a>
  • 结构:

    image-20220916132823204