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容器DispatcherServletweb相关组件(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;
  }

容器访问流程:

在这里插入图片描述
在这里插入图片描述

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

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

建议配置文件:

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

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

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

配置方式:

<!-- 通过全局初始化参数指定 Spring 配置文件的位置  root ioc容器配置-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-service.xml,classpath:spring-mapper.xml</param-value>
</context-param>
 
<listener>
    <!-- 指定全类名,配置监听器 -->
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- web容器配置-->
<!-- 配置SpringMVC中负责处理请求的核心Servlet,也被称为SpringMVC的前端控制器 -->
<servlet>
  <servlet-name>DispatcherServlet</servlet-name>
  <!-- DispatcherServlet的全类名 -->
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- 通过初始化参数指定SpringMVC配置文件位置 -->
  <init-param>
    <!-- 如果不记得contextConfigLocation配置项的名称,可以到DispatcherServlet的父类FrameworkServlet中查找 -->
    <param-name>contextConfigLocation</param-name>
    <!-- 使用classpath:说明这个路径从类路径的根目录开始才查找 -->
    <param-value>classpath:spring-mvc.xml</param-value>
  </init-param>
  <!-- 作为框架的核心组件,在启动过程中有大量的初始化操作要做,这些操作放在第一次请求时才执行非常不恰当 -->
  <!-- 我们应该将DispatcherServlet设置为随Web应用一起启动 -->
  <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>
  <servlet-name>DispatcherServlet</servlet-name>
  <!-- 对DispatcherServlet来说,url-pattern有两种方式配置 -->
  <!-- 方式一:配置“/”,表示匹配整个Web应用范围内所有请求。这里有一个硬性规定:不能写成“/*”。
    只有这一个地方有这个特殊要求,以后我们再配置Filter还是可以正常写“/*”。 -->
  <!-- 方式二:配置“*.扩展名”,表示匹配整个Web应用范围内部分请求 -->
  <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

    <?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</groupId>  
      <artifactId>part04-ssm-integration</artifactId>  
      <version>1.0-SNAPSHOT</version>  
      <packaging>war</packaging>
      <properties>
        <spring.version>6.0.6</spring.version>
        <jakarta.annotation-api.version>2.1.1</jakarta.annotation-api.version>
        <jakarta.jakartaee-web-api.version>9.1.0</jakarta.jakartaee-web-api.version>
        <jackson-databind.version>2.15.0</jackson-databind.version>
        <hibernate-validator.version>8.0.0.Final</hibernate-validator.version>
        <commons-fileupload.version>1.3.1</commons-fileupload.version>
        <mybatis.version>3.5.11</mybatis.version>
        <mysql.version>8.0.25</mysql.version>
        <pagehelper.version>5.1.11</pagehelper.version>
        <druid.version>1.2.8</druid.version>
        <mybatis-spring.version>3.0.2</mybatis-spring.version>
        <jakarta.servlet.jsp.jstl-api.version>3.0.0</jakarta.servlet.jsp.jstl-api.version>
        <logback.version>1.2.3</logback.version>
        <lombok.version>1.18.26</lombok.version>
    
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>  
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
      </properties>
      <!--
         需要依赖清单分析:
            spring
              ioc/di
                spring-context / 6.0.6
              aop
                spring-aop / 6.0.6
                spring-aspects / 6.0.6
              tx
                spring-tx  / 6.0.6
                spring-jdbc / 6.0.6
              jakarta.annotation-api / 2.1.1
    
            springmvc
               spring-webmvc 6.0.6
               jakarta.jakartaee-web-api 9.1.0
               jackson-databind 2.15.0
               hibernate-validator / hibernate-validator-annotation-processor 8.0.0.Final
               commons-fileupload / 1.3.1
            mybatis
               mybatis  / 3.5.11
               mysql    / 8.0.25
               pagehelper / 5.1.11
    
            整合需要
               加载spring容器 spring-web / 6.0.6
               整合mybatis    mybatis-spring x x
               数据库连接池   druid / x
               lombok        lombok / 1.18.26
               logback       logback/ 1.2.3
      -->
    
      <dependencies>
        <!--spring pom.xml依赖-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
        </dependency>
    
        <dependency>
          <groupId>jakarta.annotation</groupId>
          <artifactId>jakarta.annotation-api</artifactId>
          <version>${jakarta.annotation-api.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</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-tx</artifactId>
          <version>${spring.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>${spring.version}</version>
        </dependency>
        <!--
           springmvc
               spring-webmvc 6.0.6
               jakarta.jakartaee-web-api 9.1.0
               jackson-databind 2.15.0
               hibernate-validator / hibernate-validator-annotation-processor 8.0.0.Final
               commons-fileupload / 1.3.1
        -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
    
        <dependency>
          <groupId>jakarta.platform</groupId>
          <artifactId>jakarta.jakartaee-web-api</artifactId>
          <version>${jakarta.jakartaee-web-api.version}</version>
          <scope>provided</scope>
        </dependency>
    
        <!-- jsp需要依赖! jstl-->
        <dependency>
          <groupId>jakarta.servlet.jsp.jstl</groupId>
          <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
          <version>${jakarta.servlet.jsp.jstl-api.version}</version>
        </dependency>
         <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>${commons-fileupload.version}</version>
        </dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>${jackson-databind.version}</version>
        </dependency>
         <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>${hibernate-validator.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator-annotation-processor</artifactId>
          <version>${hibernate-validator.version}</version>
        </dependency>
        <!--
          mybatis
               mybatis  / 3.5.11
               mysql    / 8.0.25
               pagehelper / 5.1.11
        -->
        <!-- mybatis依赖 -->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>${mybatis.version}</version>
        </dependency>
    
        <!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${mysql.version}</version>
        </dependency>
    
        <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>${pagehelper.version}</version>
        </dependency>
    
        <!-- 整合第三方特殊依赖 -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>${mybatis-spring.version}</version>
        </dependency>
    
        <!-- 日志 , 会自动传递slf4j门面-->
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>${logback.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>${lombok.version}</version>
        </dependency>
        
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <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

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="true">
        <!-- 指定日志输出的位置,ConsoleAppender表示输出到控制台 -->
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <!-- 日志输出的格式 -->
                <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
                <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <!-- 设置全局日志级别。日志级别按顺序分别是:TRACE、DEBUG、INFO、WARN、ERROR -->
        <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
        <root level="DEBUG">
            <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
            <appender-ref ref="STDOUT" />
        </root>
    
        <!-- 根据特殊需求指定局部日志级别,可也是包名或全类名。 -->
        <logger name="com.atguigu.mybatis" level="DEBUG" />
    
    </configuration>
    

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

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

位置:resources/spring-mvc.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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!-- 扫描controller对应的包,将handler加入到ioc-->
    <context:component-scan base-package="com.atguigu.controller" />

    <!--
       注意: 导入mvc命名空间!
       mvc:annotation-driven 是一个整合标签
                             他会导入handlerMapping和handlerAdapter
                             他会导入json数据格式转化器等等
    -->
    <mvc:annotation-driven />
     <!-- viewResolver 不需要配置,因为我们不需要查找逻辑视图!!! -->

    <!-- 加入这个配置,SpringMVC 就会在遇到没有 @RequestMapping 的请求时放它过去 -->
    <!-- 所谓放它过去就是让这个请求去找它原本要访问的资源 -->
    <mvc:default-servlet-handler/>

    <!-- 配置动态页面语言jsp的视图解析器,快速查找jsp-->
    <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(命名随意)

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

       <!-- 业务层bean,增强,切点等都在此层配置 -->
       <context:component-scan base-package="com.atguigu.service,com.atguigu.advice,com.atguigu.pointcut" />
    
       <!-- 事务注解开启 
            注意:数据库配置将在mapper文件中,最终会被加载到同一个容器中,此处爆红运行正常!
       -->
       <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(命名随意)

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

    <!-- 配置数据源 
         注意: dataSource被service配置文件中引用,命名为:dataSource
    -->
    <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中配置)

<?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"/>
        <!-- 开启logback日志输出-->
        <setting name="logImpl" value="SLF4J"/>
        <!--开启resultMap自动映射 -->
        <setting name="autoMappingBehavior" value="FULL"/>
    </settings>

    <typeAliases>
        <!-- 给实体类起别名 -->
        <package name="com.atguigu.pojo"/>
    </typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--
                helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。
                你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
                oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
                (完整内容看 PageAutoDialect) 特别注意:使用 SqlServer2012 数据库时,
                https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md#%E5%A6%82%E4%BD%95%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E6%96%B9%E8%A8%80
             -->
            <property name="helperDialect" value="mysql"/>
        </plugin>
    </plugins>
    
</configuration>

修改spring-mapper.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"
       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"/>

    <!-- 配置数据源 
         注意: dataSource被service配置文件中引用,命名为:dataSource
    -->
    <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>

    <!-- 方式1: 引用外部配置文件 -->
    <!-- 配置 SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定 Mybatis 全局配置文件位置 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 指定 Mapper 配置文件位置 -->
        <property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/>
        <!-- 装配数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置 Mapper接口类型的bean的扫描器 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.mapper"/>
    </bean>
    
    
</beans>

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

修改spring-mapper.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"
       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"/>

    <!-- 配置数据源 
         注意: dataSource被service配置文件中引用,命名为:dataSource
    -->
    <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>

    <!-- 方式2: 彻底舍弃Mybatis全局配置文件 -->
    <!-- 配置 SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!-- 舍弃 Mybatis 全局配置文件,使用 configuration 属性 -->
        <property name="configuration">
            <bean class="org.apache.ibatis.session.Configuration">
                <property name="mapUnderscoreToCamelCase" value="true"/>
            </bean>
        </property>

        <!-- 舍弃 Mybatis 全局配置文件,使用 typeAliasesPackage 属性配置实体类所在包 -->
        <property name="typeAliasesPackage" value="com.atguigu.pojo"/>

        <!-- 指定 Mapper 配置文件位置 -->
        <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>
                            <!-- 启用合理化设置。当页码为负数时,设置为1, 当页码超过最大页时设置为最大页 -->
                            <prop key="reasonable">true</prop>
                            <prop key="pageHelperDialect">mysql</prop>
                        </props>
                    </property>
                </bean>
            </array>
        </property>

    </bean>

    <!-- 配置 Mapper接口类型的bean的扫描器-->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.mapper"/>
    </bean>
    <!-- 也可以使用mybatis-spring名称空间 -->
    <mybatis-spring:scan base-package="com.atguigu.mapper"/>
    
</beans>

5. 容器初始化配置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">

  <!-- ContextLoaderListener -->
  <!-- 通过 context-param 指定 Spring 框架的配置文件位置 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-service.xml,classpath:spring-mapper.xml</param-value>
  </context-param>

  <!-- 配置 ContextLoaderListener -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- DispatcherServlet -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-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

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
    <mapper namespace="com.atguigu.mapper.EmployeeMapper">
    
        <select id="queryAll" resultType="employee">
            <!-- #{empId}代表动态传入的参数,并且进行赋值!后面详细讲解 -->
            select emp_id empId,emp_name empName, emp_salary empSalary from t_emp
        </select>
    
    </mapper>
    

三、前端程序搭建和运行

1. 案例功能和接口分析

1.1 案例功能预览

在这里插入图片描述

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文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
      <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. 后台项目根路径设计
    在这里插入图片描述

  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"/>
        <!-- additional collaborators and configuration for this bean go here -->
      </bean>
      
      
    • 注解

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

      在这里插入图片描述

      //标注当前类是配置类,替代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注解
          @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配置
    • 注解
      <?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"
             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" />
          <!-- 开启aspectj框架注解支持-->
          <aop:aspectj-autoproxy />
      </beans>
      
      @Aspect
      @Order 值越小优先级越高  
      @Before
      @After
      @AfterReturning
      @AfterThrowing
      @Around
      @Pointcut
      
    • xml(了解)
      <!-- 配置目标类的bean -->
      <bean id="calculatorPure" class="com.atguigu.aop.imp.CalculatorPureImpl"/>
          
      <!-- 配置切面类的bean -->
      <bean id="logAspect" class="com.atguigu.aop.aspect.LogAspect"/>
          
      <!-- 配置AOP -->
      <aop:config>
          
          <!-- 配置切入点表达式 -->
          <aop:pointcut id="logPointCut" expression="execution(* *..*.*(..))"/>
          
          <!-- aop:aspect标签:配置切面 -->
          <!-- ref属性:关联切面类的bean -->
          <aop:aspect ref="logAspect">
              <!-- aop:before标签:配置前置通知 -->
              <!-- method属性:指定前置通知的方法名 -->
              <!-- pointcut-ref属性:引用切入点表达式 -->
              <aop:before method="printLogBeforeCore" pointcut-ref="logPointCut"/>
          
              <!-- aop:after-returning标签:配置返回通知 -->
              <!-- returning属性:指定通知方法中用来接收目标方法返回值的参数名 -->
              <aop:after-returning
                      method="printLogAfterCoreSuccess"
                      pointcut-ref="logPointCut"
                      returning="targetMethodReturnValue"/>
          
              <!-- aop:after-throwing标签:配置异常通知 -->
              <!-- throwing属性:指定通知方法中用来接收目标方法抛出异常的异常对象的参数名 -->
              <aop:after-throwing
                      method="printLogAfterCoreException"
                      pointcut-ref="logPointCut"
                      throwing="targetMethodException"/>
          
              <!-- aop:after标签:配置后置通知 -->
              <aop:after method="printLogCoreFinallyEnd" pointcut-ref="logPointCut"/>
          
              <!-- aop:around标签:配置环绕通知 -->
              <!--<aop:around method="……" pointcut-ref="logPointCut"/>-->
          </aop:aspect>
          
      </aop:config>
      
      
  • TX配置
    • 注解

      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             
          <!-- 事务管理器的bean只需要装配数据源,其他属性保持默认值即可 -->
          <property name="dataSource" ref="druidDataSource"/>
      </bean>
      <!-- 开启基于注解的声明式事务功能 -->
      <!-- 使用transaction-manager属性指定当前使用是事务管理器的bean -->
      <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
      <tx:annotation-driven transaction-manager="transactionManager"/>
      

      @Transactional

    • 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: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>
      
          <!-- 配置 JdbcTemplate -->
          <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
              <!-- 装配数据源 -->
              <property name="dataSource" ref="druidDataSource"/>
      
          </bean>
      
          <!-- 配置事务管理器 -->
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <!-- 事务管理器的bean只需要装配数据源,其他属性保持默认值即可 -->
              <property name="dataSource" ref="druidDataSource"/>
          </bean>
          <!-- tx:advice标签:配置事务通知 -->
              <!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
              <!-- transaction-manager属性:关联事务管理器 -->
              <tx:advice id="txAdvice" transaction-manager="transactionManager">
                  <tx:attributes>
      
                      <!-- tx:method标签:配置具体的事务方法 -->
                      <!-- name属性:指定方法名,可以使用星号代表多个字符 -->
                      <tx:method name="get*" read-only="true"/>
                      <tx:method name="query*" read-only="true"/>
                      <tx:method name="find*" read-only="true"/>
      
                      <!-- read-only属性:设置只读属性 -->
                      <!-- rollback-for属性:设置回滚的异常 -->
                      <!-- no-rollback-for属性:设置不回滚的异常 -->
                      <!-- isolation属性:设置事务的隔离级别 -->
                      <!-- timeout属性:设置事务的超时属性 -->
                      <!-- propagation属性:设置事务的传播行为 -->
                      <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 配置总结
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!-- 扫描controller对应的包,将handler加入到ioc  handler-->
    <context:component-scan base-package="com.atguigu.controller" />

    <!--
       注意: 导入mvc命名空间!
       mvc:annotation-driven 是一个整合标签
                             他会导入handlerMapping和handlerAdapter
                             他会导入json数据格式转化器等等
    -->
    <mvc:annotation-driven />
     <!-- viewResolver 不需要配置,因为我们不需要查找逻辑视图!!! -->

    <!-- 加入这个配置,SpringMVC 就会在遇到没有 @RequestMapping 的请求时放它过去 -->
    <!-- 所谓放它过去就是让这个请求去找它原本要访问的资源 -->
    <mvc:default-servlet-handler/>

    <!-- 配置动态页面语言jsp的视图解析器,快速查找jsp-->
    <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 映射文件中引用它们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/259971.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis原理之网络通信协议笔记

目录 1. RESP协议 ​2. 自定义Socket连接Redis 1. RESP协议 2. 自定义Socket连接Redis public class MyRedisClient {static Socket s;static PrintWriter writer;static BufferedReader reader;static Object obj;public static void main(String[] args) {try {// 1.建立连…

uni-app的初使用(附源码学习)

uni-app代码编写&#xff0c;基本语言包括js、vue、css。以及ts、scss等css预编译器。 新建项目等基础指路&#xff1a; 关于uni-app的下载及使用-CSDN博客 1.vue文件 由三个一级节点组成&#xff0c;分别是template、script、style <template> </template><…

设计模式——外观模式(Facade Pattern)

概述 外观模式又称为门面模式&#xff0c;它通过引入一个外观角色来简化客户端与子系统之间的交互&#xff0c;为复杂的子系统调用提供一个统一的入口&#xff0c;降低子系统与客户端的耦合度&#xff0c;且客户端调用非常方便。它是一种对象结构型模式。外观模式结构图如下所示…

ansible的脚本—playbook剧本

目录 一、playbook 1、简介 2、playbook组成部分&#xff1a; 3、如何编写Playbook&#xff1f; 4、语句的横向/纵向写法 二、playbook模版实例&#xff1a; 1、playbook模版&#xff1a; 2、playbook的条件判断&#xff1a; 3、playbook中的循环&#xff1a; 4、循环…

优维科技荣获第二届中国赛宝信息技术应用创新优秀解决方案三等奖

近日&#xff0c;“第二届中国赛宝信息技术应用创新优秀解决方案”评选活动圆满结束。优维科技所提交的《Hyperlnsight超融合持续观测解决方案》、《EasyOps一体化运维平台》从全国近300份申报方案中脱颖而出&#xff0c;荣获2023中国赛宝信息技术应用创新优秀解决方案奖。 本…

【操作系统】什么是进程?

文章目录 进程进程的属性进程的状态挂起 进程 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的执行过程&#xff0c;也是操作系统进行资源分配和保护的基本单位。 进程的属性 结构性&#xff1a; 共享性&#xff1a;同一程序运行于不同数据集合上构成不同的进程…

C++用哈希表封装unordered_set和unordered_map

目录 前言 一、修改kv模型为data模型 1.添加MyUnorderedSet.h和MyUnorderedMap.h 2.修改HashNode 3.修改HashTable 二、普通迭代器 三、const迭代器 四、unordered_map重载operator[] 总结 前言 在上一篇文章中&#xff0c;我们手写了一份哈希表&am…

【图神经网络】在节点分类任务中无特征节点的特征表示

无特征节点的特征表示 节点度数degree pagerank 以pagerank起源的应用场景为例&#xff0c;不是所有的网站都是同等重要的&#xff0c;所以需要根据结构信息对节点进行排序。 直觉上&#xff0c;如果一个网站它有很多链接&#xff0c;它就很重要&#xff0c;举例来说&#…

Java版企业电子招标采购系统源码—鸿鹄电子招投标系统-企业战略布局下的采购寻源

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审…

C# WPF上位机开发(业务主流程才是核心)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】前面我们说了很多的c# wpf编程技术,里面有控件,有绘图,有数据库,有多线程等技术。但是他们都属于实现的部分,没有和具体的行业进行挂钩,相当于是通用技术部分。这个通用部分一般通过书…

【深度学习】序列生成模型(五):评价方法计算实例:计算BLEU-N得分【理论到程序】

文章目录 一、BLEU-N得分&#xff08;Bilingual Evaluation Understudy&#xff09;1. 定义2. 计算N1N2BLEU-N 得分 3. 程序 给定一个生成序列“The cat sat on the mat”和两个参考序列“The cat is on the mat”“The bird sat on the bush”分别计算BLEU-N和ROUGE-N得分(N1或…

Dubbo面试题及答案,持续更新

在准备Dubbo相关的面试题时&#xff0c;我发现网络上的资源往往缺乏深度和全面性。为了帮助广大Java程序员更好地准备面试&#xff0c;我花费了大量时间进行研究和整理&#xff0c;形成了这套Dubbo面试题大全。 这套题库不仅包含了一系列经典的Dubbo面试题及其详尽答案&#x…

语音识别与人机交互:发展历程、挑战与未来前景

导言 语音识别技术作为人机交互领域的重要组成部分&#xff0c;近年来取得了巨大的发展。本文将深入研究语音识别与人机交互的发展历程、遇到的问题、解决过程、未来的可用范围&#xff0c;以及在各国的应用和未来的研究趋势。我们将探讨在这个领域&#xff0c;哪一方能取得竞争…

CCF编程能力等级认证GESP—C++6级—20230923

CCF编程能力等级认证GESP—C6级—20230923 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)小杨买饮料小杨的握手问题 答案及解析单选题判断题编程题1编程题…

微信小程序-选择和分割打开地图选择位置的信息

一、 前言 废话不多说&#xff0c;单刀直入。 本文要实现的功能是微信小程序中打开地图选择位置&#xff0c;以及将返回的位置信息分割。 例如返回的位置信息是&#xff1a;广东省深圳市龙岗区xxxxx小区 分割后变成&#xff1a; {province: "广东省",city: "深…

【蓝桥杯】专题练习

前缀和 3956. 截断数组 - AcWing题库 一看到题目很容易想到的思路是对数组求前缀和&#xff0c;然后枚举两个分段点就好&#xff0c;时间复杂度是On^2&#xff0c;n是1e5会t&#xff0c;需要优化。 朴素的代码&#xff0c;会超时&#xff1a; #include <bits/stdc.h> u…

文件包含 [SWPUCTF 2021 新生赛]include

打开题目 要求我们传入一个file进去&#xff0c;那我们get传入 /?file1 得到源码&#xff0c;并且提示我们flag在flag,php下 在源代码中&#xff0c;我们看见了allow_url_include函数&#xff0c;我们知道这涉及到文件包含。 一般默认allow_url_fopen是on的&#xff0c;那在…

IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Spring的AOP前奏

第一章 AOP前奏 1.1 代理模式 代理模式&#xff1a;我们需要做一件事情&#xff0c;又不期望自己亲力亲为&#xff0c;此时&#xff0c;可以找一个代理【中介】 我们【目标对象】与中介【代理对象】不能相互转换&#xff0c;因为是“兄弟”关系 1.2 为什么需要代理【程序中…

使用C语言实现文件的拷贝——底层内存分析

使用C语言实现文件的拷贝 本文主要涉及sprintf&#xff08;&#xff09;函数的讲解以及系统IO与标准IO的区别和一个实例使用C语言实现文件的拷贝&#xff0c;在最后还深度刨析了文件拷贝的底层原理。 文章目录 使用C语言实现文件的拷贝一、 sprintf()函数1.1 sprintf ()函数的参…

设计测试用例(万能思路 + 六种设计用例方法)(详细 + 图解 + 实例)

一、设计测试用例的万能思路 针对某个物品/功能进行测试。 万能思路&#xff1a;功能测设 界面测试 性能测试 兼容性测试 易用性测试 安全测试。 总结&#xff1a; 功能测试&#xff1a; 水杯&#xff1a;装水、喝水... 注册场景&#xff1a;注册 登录 想象日常使用…