SSM整合实战(Spring、SpringMVC、MyBatis)

五、SSM整合实战

目录

  • 一、SSM整合理解
    • 1. 什么是SSM整合?
    • 2. SSM整合核心理解五连问!
      • 2.1 SSM整合涉及几个IoC容器?
      • 2.2 每个IoC容器盛放哪些组件?
      • 2.3 IoC容器之间是什么关系?
      • 2.4 需要几个配置文件和对应IoC容器关系?
      • 2.5 IoC容器初始化方式?
  • 二、SSM整合配置实战
    • 1. 依赖添加
    • 2. 控制层配置编写(SpringMVC整合)
    • 3. 业务层配置编写(AOP / TX整合)
    • 4. 持久层配置编写(MyBatis整合)
    • 5. 容器初始化配置web.xml
    • 6. 整合测试
  • 三、前端程序搭建和运行
    • 1. 案例功能和接口分析
      • 1.1 案例功能预览
      • 1.2 接口分析
    • 2. 前端工程导入
    • 3. 启动测试
  • 四、后端程序实现和测试
    • 1. 准备工作
    • 2. 功能实现
    • 3. 前后联调
  • 五、SSM技术栈总结
    • 1. Spring框架总结
      • 1.1 技术点总结
      • 1.2 配置总结
      • 1.3 注解总结
    • 2. Spring MVC 框架总结
      • 2.1 技术点总结
      • 2.2 配置总结
      • 2.3 注解总结
    • 3. MyBatis框架总结
      • 3.1 技术点总结
      • 3.2 配置总结
      • 3.3 注解总结

一、SSM整合理解

1. 什么是SSM整合?

本质:Spring接管一切(将框架核心组件交给Spring进行IoC管理),代码更加简洁。

  • SpringMVC管理web相关组件
  • Spring管理业务层、持久层、以及数据库相关(DataSource,MyBatis)的组件
  • SSM整合最终就是编写IoC配置文件

2. SSM整合核心理解五连问!

2.1 SSM整合涉及几个IoC容器?

我们提到过SpringMVC/DispatcherServlet 加载 spring-mvc.xml,此时整个 Web 应用中只创建一个 IoC 容器。如果将Mybatis、配置声明式事务,全部在 spring-mvc.xml 配置文件中配置也是可以的。可是这样会导致配置文件太长,不容易维护。

通常情况下,SSM整合我们会创建两个IoC容器,分开管理SSM下的核心组件!

2.2 每个IoC容器盛放哪些组件?
容器名 创建类 盛放组件
web容器 DispatcherServlet web相关组件(controller,springmvc核心组件)
root容器 ContextLoaderListener 业务和持久层相关组件(service,aop,tx,dataSource,mybatis,mapper等)
2.3 IoC容器之间是什么关系?

结论:两个组件分别创建的 IOC 容器是父子关系。

  • 父容器:ContextLoaderListener 创建的 IOC 容器(root容器)
  • 子容器:DispatcherServlet 创建的 IOC 容器(web容器)

源码部分:

ContextLoaderListener将实例化root容器,存储到ServletContext:

  /**
   * Initialize Spring's web application context for the given servlet context,
   * using the application context provided at construction time, or creating a new one
   * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
   * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
   * @param servletContext current servlet context
   * @return the new WebApplicationContext
   * @see #ContextLoader(WebApplicationContext)
   * @see #CONTEXT_CLASS_PARAM
   * @see #CONFIG_LOCATION_PARAM
   */
  public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
      throw new IllegalStateException(
          "Cannot initialize context because there is already a root application context present - " +
          "check whether you have multiple ContextLoader* definitions in your web.xml!");
    }
    servletContext.log("Initializing Spring root WebApplicationContext");
    Log logger = LogFactory.getLog(ContextLoader.class);
    if (logger.isInfoEnabled()) {
      logger.info("Root WebApplicationContext: initialization started");
    }
    long startTime = System.currentTimeMillis();
    try {
      // Store context in local instance variable, to guarantee that
      // it is available on ServletContext shutdown.
      if (this.context == null) {
        this.context = createWebApplicationContext(servletContext);
      }
      if (this.context instanceof ConfigurableWebApplicationContext cwac && !cwac.isActive()) {
        // The context has not yet been refreshed -> provide services such as
        // setting the parent context, setting the application context id, etc
        if (cwac.getParent() == null) {
          // The context instance was injected without an explicit parent ->
          // determine parent for root web application context, if any.
          ApplicationContext parent = loadParentContext(servletContext);
          cwac.setParent(parent);
        }
        configureAndRefreshWebApplicationContext(cwac, servletContext);
      }
      //将root容器存储到servletContext中
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
      if (ccl == ContextLoader.class.getClassLoader()) {
        currentContext = this.context;
      }
      else if (ccl != null) {
        currentContextPerThread.put(ccl, this.context);
      }

      if (logger.isInfoEnabled()) {
        long elapsedTime = System.currentTimeMillis() - startTime;
        logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
      }

      return this.context;
    }
    catch (RuntimeException | Error ex) {
      logger.error("Context initialization failed", ex);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
      throw ex;
    }
  }

DispatcherServlet读取root容器,并且设置为web容器的父容器:

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
      throw new ApplicationContextException(
          "Fatal initialization error in servlet with name '" + getServletName() +
          "': custom WebApplicationContext class [" + contextClass.getName() +
          "] is not of type ConfigurableWebApplicationContext");
    }
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    //将root容器取出,并设置为父容器
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
      wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);

    return wac;
  }

容器访问流程:

SSM整合实战(Spring、SpringMVC、MyBatis)_第1张图片
SSM整合实战(Spring、SpringMVC、MyBatis)_第2张图片

2.4 需要几个配置文件和对应IoC容器关系?

文件的数量不是固定的,但是至少要两个,为了方便编写,我们可以三层架构每层对应一个配置文件,分别指定两个容器加载即可!

建议配置文件:

配置名 对应内容 对应容器
spring-mvc.xml controller,springmvc相关 web容器
spring-service.xml service,aop,tx相关 root容器
spring-mapper.xml mapper,datasource,mybatis相关 root容器
2.5 IoC容器初始化方式?

在一个 Web 应用中就会出现两个 IOC 容器

  • DispatcherServlet 创建一个 IOC 容器
  • ContextLoaderListener 创建一个 IOC 容器

配置方式:


<context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:spring-service.xml,classpath:spring-mapper.xmlparam-value>
context-param>
 
<listener>
    
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>



<servlet>
  <servlet-name>DispatcherServletservlet-name>
  
  <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
  
  <init-param>
    
    <param-name>contextConfigLocationparam-name>
    
    <param-value>classpath:spring-mvc.xmlparam-value>
  init-param>
  
  
  <load-on-startup>1load-on-startup>

servlet>

<servlet-mapping>
  <servlet-name>DispatcherServletservlet-name>
  
  
  
  <url-pattern>/url-pattern>
servlet-mapping>

二、SSM整合配置实战

1. 依赖添加

  1. 数据库准备

    依然沿用mybatis数据库测试脚本!

    CREATE DATABASE `mybatis-example`;
    
    USE `mybatis-example`;
    
    CREATE TABLE `t_emp`(
      emp_id INT AUTO_INCREMENT,
      emp_name CHAR(100),
      emp_salary DOUBLE(10,5),
      PRIMARY KEY(emp_id)
    );
    
    INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("tom",200.33);
    INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("jerry",666.66);
    INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("andy",777.77);
    
  2. 准备项目

    part04-ssm-integration

    转成web项目

  3. 依赖导入

    pom.xml

    
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
      <modelVersion>4.0.0modelVersion>  
      <groupId>com.atguigugroupId>  
      <artifactId>part04-ssm-integrationartifactId>  
      <version>1.0-SNAPSHOTversion>  
      <packaging>warpackaging>
      <properties>
        <spring.version>6.0.6spring.version>
        <jakarta.annotation-api.version>2.1.1jakarta.annotation-api.version>
        <jakarta.jakartaee-web-api.version>9.1.0jakarta.jakartaee-web-api.version>
        <jackson-databind.version>2.15.0jackson-databind.version>
        <hibernate-validator.version>8.0.0.Finalhibernate-validator.version>
        <commons-fileupload.version>1.3.1commons-fileupload.version>
        <mybatis.version>3.5.11mybatis.version>
        <mysql.version>8.0.25mysql.version>
        <pagehelper.version>5.1.11pagehelper.version>
        <druid.version>1.2.8druid.version>
        <mybatis-spring.version>3.0.2mybatis-spring.version>
        <jakarta.servlet.jsp.jstl-api.version>3.0.0jakarta.servlet.jsp.jstl-api.version>
        <logback.version>1.2.3logback.version>
        <lombok.version>1.18.26lombok.version>
    
        <maven.compiler.source>17maven.compiler.source>
        <maven.compiler.target>17maven.compiler.target>  
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 
      properties>
      
    
      <dependencies>
        
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-contextartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>jakarta.annotationgroupId>
          <artifactId>jakarta.annotation-apiartifactId>
          <version>${jakarta.annotation-api.version}version>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-aopartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-aspectsartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-txartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-jdbcartifactId>
          <version>${spring.version}version>
        dependency>
        
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-webmvcartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>jakarta.platformgroupId>
          <artifactId>jakarta.jakartaee-web-apiartifactId>
          <version>${jakarta.jakartaee-web-api.version}version>
          <scope>providedscope>
        dependency>
    
        
        <dependency>
          <groupId>jakarta.servlet.jsp.jstlgroupId>
          <artifactId>jakarta.servlet.jsp.jstl-apiartifactId>
          <version>${jakarta.servlet.jsp.jstl-api.version}version>
        dependency>
         
        <dependency>
          <groupId>commons-fileuploadgroupId>
          <artifactId>commons-fileuploadartifactId>
          <version>${commons-fileupload.version}version>
        dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.coregroupId>
          <artifactId>jackson-databindartifactId>
          <version>${jackson-databind.version}version>
        dependency>
         
        <dependency>
          <groupId>org.hibernate.validatorgroupId>
          <artifactId>hibernate-validatorartifactId>
          <version>${hibernate-validator.version}version>
        dependency>
        
        <dependency>
          <groupId>org.hibernate.validatorgroupId>
          <artifactId>hibernate-validator-annotation-processorartifactId>
          <version>${hibernate-validator.version}version>
        dependency>
        
        
        <dependency>
          <groupId>org.mybatisgroupId>
          <artifactId>mybatisartifactId>
          <version>${mybatis.version}version>
        dependency>
    
        
        <dependency>
          <groupId>mysqlgroupId>
          <artifactId>mysql-connector-javaartifactId>
          <version>${mysql.version}version>
        dependency>
    
        <dependency>
          <groupId>com.github.pagehelpergroupId>
          <artifactId>pagehelperartifactId>
          <version>${pagehelper.version}version>
        dependency>
    
        
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-webartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>org.mybatisgroupId>
          <artifactId>mybatis-springartifactId>
          <version>${mybatis-spring.version}version>
        dependency>
    
        
        <dependency>
          <groupId>ch.qos.logbackgroupId>
          <artifactId>logback-classicartifactId>
          <version>${logback.version}version>
        dependency>
    
        <dependency>
          <groupId>org.projectlombokgroupId>
          <artifactId>lombokartifactId>
          <version>${lombok.version}version>
        dependency>
        
        <dependency>
          <groupId>com.alibabagroupId>
          <artifactId>druidartifactId>
          <version>${druid.version}version>
        dependency>
        
      dependencies>
    
    project> 
    
  4. 实体类添加

    com.atguigu.pojo

    @Data
    public class Employee {
    
        private Integer empId;
        private String empName;
        private Double empSalary;
    }
    
  5. logback配置

    位置:resources/logback.xml

    
    <configuration debug="true">
        
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                
                
                <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%npattern>
                <charset>UTF-8charset>
            encoder>
        appender>
    
        
        
        <root level="DEBUG">
            
            <appender-ref ref="STDOUT" />
        root>
    
        
        <logger name="com.atguigu.mybatis" level="DEBUG" />
    
    configuration>
    

2. 控制层配置编写(SpringMVC整合)

主要配置controller,springmvc相关! 本次先不配置文件上传!

位置:resources/spring-mvc.xml(命名随意)


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


    
    <context:component-scan base-package="com.atguigu.controller" />

    
    <mvc:annotation-driven />
     

    
    
    <mvc:default-servlet-handler/>

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

3. 业务层配置编写(AOP / TX整合)

主要配置service,注解aop和声明事务相关!

位置:resources/spring-service.xml(命名随意)


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

       
       <context:component-scan base-package="com.atguigu.service,com.atguigu.advice,com.atguigu.pointcut" />
    
       
       <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
           <property name="dataSource" ref="dataSource" />
       bean>
    
       <tx:annotation-driven transaction-manager="transactionManager" /> 
beans>

4. 持久层配置编写(MyBatis整合)

jdbc外部配置

位置:resources/jdbc.properties

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql:///mybatis-example
jdbc.driver=com.mysql.cj.jdbc.Driver

持久层配置

位置:resources/spring-mapper.xml(命名随意)


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

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

    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
    bean>
    
beans>

配置mybatis方式1:保留mybaits全局配置

准备mybatis-config.xml文件:去掉数据库信息,去掉mapper包映射(xml中配置)


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"/>
        
        <setting name="logImpl" value="SLF4J"/>
        
        <setting name="autoMappingBehavior" value="FULL"/>
    settings>

    <typeAliases>
        
        <package name="com.atguigu.pojo"/>
    typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            
            <property name="helperDialect" value="mysql"/>
        plugin>
    plugins>
    
configuration>

修改spring-mapper.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

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

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

    
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        
        <property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/>
        
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.mapper"/>
    bean>
    
    
beans>

配置mybatis方式2:完全配置文件实现

修改spring-mapper.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

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

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

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

        
        <property name="configuration">
            <bean class="org.apache.ibatis.session.Configuration">
                <property name="mapUnderscoreToCamelCase" value="true"/>
            bean>
        property>

        
        <property name="typeAliasesPackage" value="com.atguigu.pojo"/>

        
        <property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/>

        
        <property name="dataSource" ref="dataSource"/>
        
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            
                            <prop key="reasonable">trueprop>
                            <prop key="pageHelperDialect">mysqlprop>
                        props>
                    property>
                bean>
            array>
        property>

    bean>

    
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.mapper"/>
    bean>
    
    <mybatis-spring:scan base-package="com.atguigu.mapper"/>
    
beans>

5. 容器初始化配置web.xml


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0">

  
  
  <context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:spring-service.xml,classpath:spring-mapper.xmlparam-value>
  context-param>

  
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
  listener>

  
  <servlet>
    <servlet-name>dispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath:spring-mvc.xmlparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
  servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServletservlet-name>
    <url-pattern>/url-pattern>
  servlet-mapping>
web-app>

6. 整合测试

  1. 需求

    查询所有员工信息,返回对应json数据!

  2. controller

    @Slf4j
    @RestController
    @RequestMapping("/employee")
    public class EmployeeController {
    
        @Autowired
        private EmployeeService employeeService;
    
        @GetMapping("list")
        public List<Employee> retList(){
            List<Employee> employees = employeeService.findAll();
            log.info("员工数据:{}",employees);
            return employees;
        }
    }
    
    
  3. service

    @Service
    public class EmployeeServiceImpl implements EmployeeService {
    
        @Autowired
        private EmployeeMapper employeeMapper;
    
        /**
         * 查询所有员工信息
         */
        @Override
        public List<Employee> findAll() {
            List<Employee> employeeList =  employeeMapper.queryAll();
            return employeeList;
        }
    }
    
    
  4. mapper

    mapper接口 包:com.atguigu.mapper

    public interface EmployeeMapper {
    
         List<Employee> queryAll();
    }
    
    

    mapper XML 文件位置: resources/mappers

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.atguigu.mapper.EmployeeMapper">
    
        <select id="queryAll" resultType="employee">
            
            select emp_id empId,emp_name empName, emp_salary empSalary from t_emp
        select>
    
    mapper>
    

三、前端程序搭建和运行

1. 案例功能和接口分析

1.1 案例功能预览

SSM整合实战(Spring、SpringMVC、MyBatis)_第3张图片

1.2 接口分析
  1. 学习计划分页查询
    /* 
    需求说明
        查询全部数据页数据
    请求uri
        schedule/{pageSize}/{currentPage}
    请求方式 
        get   
    响应的json
        {
            "code":200,
            "flag":true,
            "data":{
                //本页数据
                data:
                [
                {id:1,title:'学习java',completed:true},
                {id:2,title:'学习html',completed:true},
                {id:3,title:'学习css',completed:true},
                {id:4,title:'学习js',completed:true},
                {id:5,title:'学习vue',completed:true}
                ], 
                //分页参数
                pageSize:5, // 每页数据条数 页大小
                total:0 ,   // 总记录数
                currentPage:1 // 当前页码
            }
        }
    */
    
  2. 学习计划删除
    /* 
    需求说明
        根据id删除日程
    请求uri
        schedule/{id}
    请求方式 
        delete
    响应的json
        {
            "code":200,
            "flag":true,
            "data":null
        }
    */
    
  3. 学习计划保存
    /* 
    需求说明
        增加日程
    请求uri
        schedule
    请求方式 
        post
    请求体中的JSON
        {
            title: '',
            completed: false
        }
    响应的json
        {
            "code":200,
            "flag":true,
            "data":null
        }
    */
    
  4. 学习计划修改
    /* 
    需求说明
        根据id修改数据
    请求uri
        schedule
    请求方式 
        put
    请求体中的JSON
        {
            id: 1,
            title: '',
            completed: false
        }
    响应的json
        {
            "code":200,
            "flag":true,
            "data":null
        }
    */
    

2. 前端工程导入

3. 启动测试

npm i //安装依赖
npm run dev //运行测试

四、后端程序实现和测试

1. 准备工作

  1. 准备数据库脚本

    CREATE TABLE schedule (
      id INT NOT NULL AUTO_INCREMENT,
      title VARCHAR(255) NOT NULL,
      completed BOOLEAN NOT NULL,
      PRIMARY KEY (id)
    );
    
    INSERT INTO schedule (title, completed)
    VALUES
        ('学习java', true),
        ('学习Python', false),
        ('学习C++', true),
        ('学习JavaScript', false),
        ('学习HTML5', true),
        ('学习CSS3', false),
        ('学习Vue.js', true),
        ('学习React', false),
        ('学习Angular', true),
        ('学习Node.js', false),
        ('学习Express', true),
        ('学习Koa', false),
        ('学习MongoDB', true),
        ('学习MySQL', false),
        ('学习Redis', true),
        ('学习Git', false),
        ('学习Docker', true),
        ('学习Kubernetes', false),
        ('学习AWS', true),
        ('学习Azure', false);
    
    
  2. 准备pojo

    包:com.atguigu.pojo

    /**
     * projectName: com.atguigu.pojo
     *
     * description: 任务实体类
     */
    @Data
    public class Schedule {
    
        private Integer id;
        private String title;
        private Boolean completed;
    }
    
    
  3. 准备 R

    包:com.atguigu.utils

    **
     * projectName: com.atguigu.utils
     *
     * description: 返回结果类
     */
    public class R {
    
        private int code = 200; //200成功状态码
    
        private boolean flag = true; //返回状态
    
        private Object data;  //返回具体数据
    
        public  static R ok(Object data){
            R r = new R();
            r.data = data;
            return r;
        }
    
        public static R  fail(Object data){
            R r = new R();
            r.code = 500; //错误码
            r.flag = false; //错误状态
            r.data = data;
            return r;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public boolean isFlag() {
            return flag;
        }
    
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    
        public Object getData() {
            return data;
        }
    
        public void setData(Object data) {
            this.data = data;
        }
    }
    
  4. 准备 PageBean

    包:com.atguigu.utils

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class PageBean<T> {
        private int currentPage;   // 当前页码
        private int pageSize;      // 每页显示的数据量
        private long total;    // 总数据条数
        private List<T> data;      // 当前页的数据集合
    }
    
    

2. 功能实现

  1. 分页查询
    1. controller

      /*
          @CrossOrigin 注释在带注释的控制器方法上启用跨源请求
       */
      @CrossOrigin
      @RequestMapping("schedule")
      @RestController
      public class ScheduleController
      {
      
          @Autowired
          private ScheduleService scheduleService;
      
          @GetMapping("/{pageSize}/{currentPage}")
          public R showList(@PathVariable(name = "pageSize") int pageSize, @PathVariable(name = "currentPage") int currentPage){
              PageBean<Schedule> pageBean = scheduleService.findByPage(pageSize,currentPage);
              return  R.ok(pageBean);
          }
      }    
      
    2. service

      @Slf4j
      @Service
      public class ScheduleServiceImpl  implements ScheduleService {
      
          @Autowired
          private ScheduleMapper scheduleMapper;
      
          /**
           * 分页数据查询,返回分页pageBean
           *
           * @param pageSize
           * @param currentPage
           * @return
           */
          @Override
          public PageBean<Schedule> findByPage(int pageSize, int currentPage) {
              //1.设置分页参数
              PageHelper.startPage(currentPage,pageSize);
              //2.数据库查询
              List<Schedule> list = scheduleMapper.queryPage();
              //3.结果获取
              PageInfo<Schedule> pageInfo = new PageInfo<>(list);
              //4.pageBean封装
              PageBean<Schedule> pageBean = new PageBean<>(pageInfo.getPageNum(),pageInfo.getPageSize(),pageInfo.getTotal(),pageInfo.getList());
      
              log.info("分页查询结果:{}",pageBean);
      
              return pageBean;
          }
      
      }
      
    3. mapper

      mapper接口

      public interface ScheduleMapper {
      
          List<Schedule> queryPage();
      }    
      

      mapperxml文件

      
      DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.atguigu.mapper.ScheduleMapper">
      
          <select id="queryPage" resultType="schedule">
              select * from schedule
          select>
      mapper>    
      
  2. 计划添加
    1. controller

      @PostMapping
      public R saveSchedule(@RequestBody Schedule schedule){
          scheduleService.saveSchedule(schedule);
          return R.ok(null);
      }
      
    2. service

      /**
       * 保存学习计划
       *
       * @param schedule
       */
      @Override
      public void saveSchedule(Schedule schedule) {
          scheduleMapper.insert(schedule);
      }
      
    3. mapper

      mapper接口

      void insert(Schedule schedule);
      

      mapperxml文件

      <insert id="insert">
          insert into schedule (title, completed)
          values
          (#{title}, #{completed});
      insert>
      
  3. 计划删除
    1. controller
      @DeleteMapping("/{id}")
      public R removeSchedule(@PathVariable Integer id){
          scheduleService.removeById(id);
          return R.ok(null);
      }
      
    2. service
      /**
       * 移除学习计划
       *
       * @param id
       */
      @Override
      public void removeById(Integer id) {
          scheduleMapper.delete(id);
      }
      
    3. mapper
      mapper接口
      void delete(Integer id);
      
      mapperxml文件
      <delete id="delete">
          delete from schedule where id = #{id}
      delete>
      
  4. 计划修改
    1. controller
      @PutMapping
          public R changeSchedule(@RequestBody Schedule schedule){
          scheduleService.updateSchedule(schedule);
          return R.ok(null);
      }
      
    2. service
      /**
       * 更新学习计划
       *
       * @param schedule
       */
      @Override
      public void updateSchedule(Schedule schedule) {
          scheduleMapper.update(schedule);
      }
      
    3. mapper
      mapper接口
      void update(Schedule schedule);
      
      mapperxml文件
      <update id="update">
          update schedule set title = #{title} , completed = #{completed}
               where id = #{id}
      update>
      

3. 前后联调

  1. 后台项目根路径设计
    SSM整合实战(Spring、SpringMVC、MyBatis)_第4张图片

  2. 启动测试即可

五、SSM技术栈总结

1. Spring框架总结

1.1 技术点总结
  • 控制反转(IoC,Inversion of Control)和依赖注入(DI,Dependency Injection)
  • Spring AOP(Aspect-Oriented Programming)面向切面编程
  • Spring TX声明式事务实现
1.2 配置总结
  • IoC/DI配置
    • xml

      <bean id="petStore" class="org.springframework.samples.
                                  jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        
      bean>
      
      
    • 注解

      注解 说明
      @Component 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。
      @Repository 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
      @Service 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
      @Controller 该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
      
      <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"
             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">
          
          
          <context:component-scan base-package="com.atguigu.components"/>
        
      beans>
      
    • 配置类

      SSM整合实战(Spring、SpringMVC、MyBatis)_第5张图片

      //标注当前类是配置类,替代application.xml    
      @Configuration
      //引入jdbc.properties文件
      @PropertySource({"classpath:application.properties","classpath:jdbc.properties"})
      @ComponentScan(basePackages = {"com.atguigu.components"})
      @Import(其他的配置类.class)
      public class MyConfiguration {
      
          //如果第三方类进行IoC管理,无法直接使用@Component相关注解
          //解决方案: xml方式可以使用
          //解决方案: 配置类方式,可以使用方法返回值+@Bean注解
          @Bean
          public DataSource createDataSource(@Value("${jdbc.user:default}") String username,
                                             @Value("${jdbc.password}")String password,
                                             @Value("${jdbc.url}")String url,
                                             @Value("${jdbc.driver}")String driverClassName){
              //使用Java代码实例化
              DruidDataSource dataSource = new DruidDataSource();
              dataSource.setUsername(username);
              dataSource.setPassword(password);
              dataSource.setUrl(url);
              dataSource.setDriverClassName(driverClassName);
              //返回结果即可
              return dataSource;
          }
          
          
          @Bean
          public XxxMapper createMapper(DataSource createDataSource){
            
          }
          
      }
      
  • AOP配置
    • 注解
      
      <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"
             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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          
          <context:component-scan base-package="com.atguigu" />
          
          <aop:aspectj-autoproxy />
      beans>
      
      @Aspect
      @Order 值越小优先级越高  
      @Before
      @After
      @AfterReturning
      @AfterThrowing
      @Around
      @Pointcut
      
    • xml(了解)
      
      <bean id="calculatorPure" class="com.atguigu.aop.imp.CalculatorPureImpl"/>
          
      
      <bean id="logAspect" class="com.atguigu.aop.aspect.LogAspect"/>
          
      
      <aop:config>
          
          
          <aop:pointcut id="logPointCut" expression="execution(* *..*.*(..))"/>
          
          
          
          <aop:aspect ref="logAspect">
              
              
              
              <aop:before method="printLogBeforeCore" pointcut-ref="logPointCut"/>
          
              
              
              <aop:after-returning
                      method="printLogAfterCoreSuccess"
                      pointcut-ref="logPointCut"
                      returning="targetMethodReturnValue"/>
          
              
              
              <aop:after-throwing
                      method="printLogAfterCoreException"
                      pointcut-ref="logPointCut"
                      throwing="targetMethodException"/>
          
              
              <aop:after method="printLogCoreFinallyEnd" pointcut-ref="logPointCut"/>
          
              
              
          aop:aspect>
          
      aop:config>
      
      
  • TX配置
    • 注解

      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             
          
          <property name="dataSource" ref="druidDataSource"/>
      bean>
      
      
      
      <tx:annotation-driven transaction-manager="transactionManager"/>
      

      @Transactional

    • xml(了解)

      
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:tx="http://www.springframework.org/schema/tx"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          
          <context:component-scan base-package="com.atguigu" />
      
          
          <context:property-placeholder location="classpath:jdbc.properties" />
      
          
          <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="url" value="${atguigu.url}"/>
              <property name="driverClassName" value="${atguigu.driver}"/>
              <property name="username" value="${atguigu.username}"/>
              <property name="password" value="${atguigu.password}"/>
          bean>
      
          
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
              
              <property name="dataSource" ref="druidDataSource"/>
      
          bean>
      
          
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              
              <property name="dataSource" ref="druidDataSource"/>
          bean>
          
              
              
              <tx:advice id="txAdvice" transaction-manager="transactionManager">
                  <tx:attributes>
      
                      
                      
                      <tx:method name="get*" read-only="true"/>
                      <tx:method name="query*" read-only="true"/>
                      <tx:method name="find*" read-only="true"/>
      
                      
                      
                      
                      
                      
                      
                      <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
                      <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
                      <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
                      
                      <tx:method name="*" />
                  tx:attributes>
              tx:advice>
      
              <aop:config>
                  
                  <aop:pointcut id="txPoincut" expression="execution(* *..*Service.*(..))"/>
      
                  
                  <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoincut"/>
              aop:config>
      beans>  
      
1.3 注解总结
  • ioc/di注解:

    @Autowired:自动装配 Bean,可用于构造方法、属性和方法上,配合 @Qualifier 使用实现按名称注入。

    @Qualifier:指定需要注入的 Bean 的名称,通常和 @Autowired 一起使用。

    @Resource:和 @Autowired 类似,可以实现按名称注入,不过是 JSR-250 规范的注解。

    @Value:注入 properties 文件中的属性值,还可以注入 SpEL 表达式的值。

    @Component:通用的组件注解,通常用于标记 Spring 管理的 Bean。

    @Controller:标记 Spring MVC 控制器,也是 @Component 的一种。

    @Service:标记 Service 层组件,也是 @Component 的一种。

    @Repository:标记数据访问层组件,是 @Component 的一种。

  • aop注解:

    @Aspect:声明一个切面类。

    @Pointcut:定义切入点表达式。

    @Before:前置通知,在目标方法执行之前执行。

    @AfterReturning:后置通知,在目标方法执行之后执行,返回结果时执行。

    @AfterThrowing:异常通知,在目标方法抛出异常时执行。

    @After:最终通知,在目标方法执行之后执行,无论是否发生异常都执行。

    @Around:环绕通知,在目标方法执行前后执行,可以控制目标方法的执行。

  • tx注解:

    @Transactional:声明一个事务方法,可以配置事务的属性,如传播行为、隔离级别、超时时间等。

2. Spring MVC 框架总结

2.1 技术点总结
  • 简化参数接收

    接收param / json / 文件 / 原生api / 共享域

  • 简化数据响应

    响应 页面 / 转发和重定向 / json / 文件

2.2 配置总结

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


    
    <context:component-scan base-package="com.atguigu.controller" />

    
    <mvc:annotation-driven />
     

    
    
    <mvc:default-servlet-handler/>

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

beans>
2.3 注解总结
  • 控制器相关

    @Controller:用于定义控制器类;

    @RestController:与 @Controller 类似,但返回值都会被转换为 JSON 格式;

    @RequestMapping:用于定义请求 URI 与控制器方法的映射关系;

    @CrossOrigin:用于标注在 Controller 类或处理请求的方法上,表示允许跨域请求;

  • 接收参数相关

    @RequestParam:用于获取请求参数的值;

    @RequestBody:用于获取 POST 请求的请求体(Request Body);

    @RequestHeader:用于获取请求头信息;

    @CookieValue:用于获取 Cookie 中的值。

    @PathVariable:用于获取 URI 中的参数值;

  • 响应数据相关

    @ResponseBody:用于将 Controller 中方法返回的对象转换成指定格式(通常是 JSON 或 XML)的对象,并将其作为响应正文返回;

  • 校验注解相关

    @Validate:用于开启对象的数据校验;

    @NotNull:用于检验是否为 null;

    @NotBlank:用于检验是否为 null 或空字符串;

    @Size:用于检验字符串、数组、集合的长度范围;

    @Min:用于检验数字的最小值;

    @Max:用于检验数字的最大值;

    @DecimalMin:用于检验 BigDecimal 和 BigInteger 的最小值;

    @DecimalMax:用于检验 BigDecimal 和 BigInteger 的最大值;

    @Pattern:用于检验正则表达式。

3. MyBatis框架总结

3.1 技术点总结
  • 映射文件及 SQL 语句编写
  • MyBatis 动态 SQL
  • MyBatis 多表映射
  • MyBatis 逆向工程
3.2 配置总结
  • mapper配置
    MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。
    如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
    
    SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):
    
        resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
        sql – 可被其它语句引用的可重用语句块。
        insert – 映射插入语句。
        update – 映射更新语句。
        delete – 映射删除语句。
        select – 映射查询语句。
    
    
  • mybatis配置
    MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
        configuration(配置)
            properties(属性)
            settings(设置)
            typeAliases(类型别名)
            typeHandlers(类型处理器) String []  ,  varchar()
            objectFactory(对象工厂)
            plugins(插件)
            environments(环境配置)
                environment(环境变量)
                    transactionManager(事务管理器)
                    dataSource(数据源)
            databaseIdProvider(数据库厂商标识)
            mappers(映射器)
    
    
3.3 注解总结

@Param:在 MyBatis 中,@Param 注解主要用于解决在调用映射器方法时传递多个参数的问题。当你在映射器接口中定义的方法有多个参数时,你需要使用 @Param 注解来明确指出每个参数的名称,以便在 SQL 映射文件中引用它们。

例如,假设你有以下映射器接口方法:

void updateUser(@Param("id") int id, @Param("name") String name, @Param("age") int age);

在这个例子中,你定义了一个名为 updateUser 的方法,它接受三个参数:id、name 和 age。每个参数都使用了 @Param 注解,并给出了一个名称。

然后,在相应的 SQL 映射文件中,你可以使用这些名称来引用这些参数。例如:

<update id="updateUser">  
    UPDATE user  
    SET name = #{name}, age = #{age}  
    WHERE id = #{id}  
update>

在这个例子中,#{name}、#{age} 和 #{id} 分别引用了传递给 updateUser 方法的 name、age 和 id 参数。

总的来说,@Param 注解在 MyBatis 中用于明确指出方法的参数名称,以便在 SQL 映射文件中引用它们。

你可能感兴趣的:(SSM整合实战,spring,springmvc,mybatis,spring框架总结,springmvc框架总结,mybatis框架总结,ssm整合理解)