SpringBoot学习笔记

SpringBoot

以前学习SpringBoot时所做的笔记,发在这里是为了方便自己翻阅,不喜勿喷。

一、SpringBoot简介

1.1 SpringBoot的概述

  • 什么是Spring Boot

    • Spring Boot 是所有基于 Spring Framework 5.0 开发的项目。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序,并且尽可能减少你的配置文件。
    • 设计目的:
      • 用来简化 Spring 应用的初始搭建以及开发过程。
    • 从最根本上来讲,Spring Boot 就是一些库的集合,它能够被任意项目所使用,它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置)的理念让你的项目快速运行起来。
    • spring boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架,总结一下及几点:
      • 为所有 Spring 开发提供一个更快更广泛的入门体验。
      • 零配置,无冗余代码生成和XML 强制配置,遵循“约定大于配置” 。
      • 集成了大量常用的第三方库的配置, Spring Boot 应用为这些第三方库提供了几乎可以零配置的开箱即用的能力。
      • 提供一系列大型项目常用的非功能性特征,如嵌入服务器等。
  • SpringBoot的特点

    • 为基于Spring的开发提供更快的入门体验
    • 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
    • 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、外部配置等
    • SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式
  • SpringBoot的核心功能

    • 起步依赖

      • 起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
      • 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
    • 自动配置

      • Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

二、SpringBoot快速入门

2.1 快速入门案例

  1. 创建Maven工程

    • 使用idea工具创建一个maven工程

      在这里插入图片描述

  2. 在该工程下的pom.xml文件中添加SpringBoot的起步依赖

    <?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.ljf</groupId>
        <artifactId>springboot_demo01</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <!-- SpringBoot父工程,里面有很多现成的依赖,所以不需要再自己添加这些依赖了 -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.6.RELEASE</version>
        </parent>
    
        <dependencies>
            <!--web起步包,里面有很多
             	注意:虽然是web工程,但不需要打war包,直接打jar就行
            -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    
  3. 编写SpringBoot引导类

    • SpringBoot引导类需要在所有组件类的上一层。

    • SpringBoot引导类需要使用@SpringBootApplication进行声明

      package com.ljf;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      // 声明该类是一个SpringBoot引导类
      @SpringBootApplication
      public class Application {
          // main是java程序的入口
          public static void main(String[] args) {
              // run()方法表示运行SpringBoot的引导类,run参数就是SpringBoot引导类的字节码对象
              SpringApplication.run(Application.class, args);
          }
      }
      
  4. 编写Controller

    • 必须在引导类Application同级包或者子级包中创建Controller

      package com.ljf.controller;
      
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequestMapping("/hello")
      public class HelloController {
          @RequestMapping("/world")
          public String world(){
              return "springboot 访问成功!";
          }
      }
      
  5. 测试

    • 执行SpringBoot起步类Application的主方法,控制台打印日志如下:

      在这里插入图片描述

    • 通过日志发现,Tomcat started on port(s): 8080 (http) with context path ’’

      • tomcat已经起步,端口监听8080,web应用的虚拟工程名称为空(默认“/”)
    • 打开浏览器访问url地址为:http://localhost:8080/hello/world

      在这里插入图片描述

2.2 SpringBoot工程热部署

  • 我们在以往的开发中,每次修改类、页面等资源后,都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大量的时间。

  • 在使用SpringBoot后,只需在pom.xml文件中添加一个插件就可以实现不重启服务就能生效的功能,对于这样的功能,我们称之为热部署。

    • 热部署依赖

      <!-- 热部署依赖 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-devtools</artifactId>
      </dependency>
      
    • 热部署插件

      <build>
          <plugins>
              <!-- 热部署插件 -->
              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                  <version>2.1.6.RELEASE</version>
              </plugin>
          </plugins>
      </build>
      
  • 开启 Intellij IEDA 自动编译,需要对IDEA进行自动编译的设置,如下:

    在这里插入图片描述

    • 正常情况下就可以进行热部署, 如果还是不行,在加入如下操作,如果已经可以热部署,就不需要看后面的操作

      • 在Idea中, Shift+Ctrl+Alt+/, 选择Registry

        在这里插入图片描述

      • 找到以下选项,然后打勾:

        在这里插入图片描述

2.3 使用idea快速创建SpringBoot项目

  • 可以在Idea中快速创建一个SpringBoot项目
  1. 在选择创建项目时,选择Spring Initializr工程:

    在这里插入图片描述

  2. 进行一些基础配置

    在这里插入图片描述

  3. 选择Spring Web

    在这里插入图片描述

  4. 选择工程路径

    在这里插入图片描述

  • 使用这种方式创建出的工程会自动生成 SpringBoot启动类 和 配置pom.xml文件,虽然很方便,但是由于这样创建的工程会有很多我们不需要的东西,且需要在有网的时候才有用,所以一般我们不这样创建SpringBoot项目,了解即可。

三、SpringBoot原理分析

3.1 起步依赖原理分析

  • 通过查看父类spring-boot-starter-parentpom.xml文件,可以发现其右继承了另一个父工程spring-boot-starter-dependencies,而查看这个工程的pom.xml文件,发现这里有很多依赖。

    • 总结:
      • 从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好
      • 所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了(不会出现版本冲突的问题)。
      • 所以起步依赖的作用就是进行依赖的传递
  • 通过查看web起步包spring-boot-starter-web工程的pom.xml文件:

    • 我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”
    • 这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用
    • 同时加载tomcat,只要启动main方法,就相当于起到tomcat进行开发
    • 同时加载json,支持springmvc的数据请求和响应。

3.2 自动配置原理解析

3.2.1 原web.xml的中配置
  • 问题提出

    • 在以往的web工程开发中,我们都需要配置一个web.xml文件,在其中配置过滤器、dispatcherServlet等。
    • 但在SpringBoot中却不需要配置web.xml文件,那么dispatcherServlet等组件是如何配置的呢?
  • 问题解析

    • 其实web.xml文件中的一些配置其实都已经被SpringBoot自动配置好了

    • 可以在SpringBoot的启动类中,通过 ApplicationContext.getBeanDefinitionNames()方法查看web工程中所有的Bean对象

      package com.ljf;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.ApplicationContext;
      
      // 声明该类是一个SpringBoot引导类
      @SpringBootApplication
      public class Application {
          // main是java程序的入口
          public static void main(String[] args) {
              // run()方法表示运行SpringBoot的引导类,run参数就是SpringBoot引导类的字节码对象,run()方法的返回值是一个ApplicationContext对象
              ApplicationContext act = SpringApplication.run(Application.class, args);
              // ApplicationContext.getBeanDefinitionNames()可以返回整个web工程的所有bean对象
              for (String name : act.getBeanDefinitionNames()) {
                  System.out.println(name);
              }
          }
      }
      
      • 通过搜索其打印内容,可以发现里面有很多之前需要在web.xml中配置的bean对象:

        • dispatcherServlet

          在这里插入图片描述

        • characterEncodingFilter

          在这里插入图片描述

        • hiddenHttpMethodFilter

          在这里插入图片描述

3.2.2 @SpringBootApplication注解
  • SpringBoot的启动类需要使用@SpringBootApplication注解标识

  • 通过查看@SpringBootApplication注解,我们可以发现这是一个复合注解:

    package org.springframework.boot.autoconfigure;
    
    // import...
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan( 
        excludeFilters = {
            @Filter(type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), 
            @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}) 
        }
    )
    public @interface SpringBootApplication {
        // ...
    }
    
  • @SpringBootApplication注解中,最重要的复合注解是后三个:

    @SpringBootConfiguration	// 表示当前类具有配置类的作用,用于代替配置文件
    @EnableAutoConfiguration	// 表示开启自动配置
    @ComponentScan( 			// 表示自动扫描组件,等效于XML文件中的包扫描标签
        excludeFilters = {
            @Filter(type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), 
            @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}) 
        }
    )
    
  • @ComponentScan注解:

    • 作用:

      • 表示自动扫描组件,等效于XML文件中的包扫描标签
    • 注意:

      • 该注解是把当前启动类所在的包作为扫描包的起点,例如启动类所在的包在com.ljf中,则该注解等效于:

        <context:component-scan base-package="com.ljf"></context:component-scan>
        
  • @SpringBootConfiguration注解:

    • 作用:
      • 表示当前类具有配置类的作用,用于代替配置文件
  • @EnableAutoConfiguration注解:

    • 作用:

      • 表示开启自动配置
    • 点击查看@EnableAutoConfiguration注解:

      package org.springframework.boot.autoconfigure;
      
      // import...
      
      @Target({ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Inherited
      @AutoConfigurationPackage
      @Import({AutoConfigurationImportSelector.class})
      public @interface EnableAutoConfiguration {
          String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
      
          Class<?>[] exclude() default {};
      
          String[] excludeName() default {};
      }
      
    • 发现@EnableAutoConfiguration注解引入了一个AutoConfigurationImportSelector类,再查看该类(主要看一下三个方法):

      // selectImports()方法:选择性引入
      public String[] selectImports(AnnotationMetadata annotationMetadata) {
          //...
          AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
          //..
      }
      
      // getAutoConfigurationEntry()方法:获取自动配置项
      protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
          // ...
          List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
          // ...
      }
      
      // getCandidateConfigurations()方法:有条件的获取配置项
      protected List<String> getCandidateConfigurations()方法:有条件的获取配置项(AnnotationMetadata metadata, AnnotationAttributes attributes) {
          List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
          // 在META-INF/spring.factories中找不到自动配置类。需要看看文件是否正确
          Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
          return configurations;
      }
      
      • 其中,SpringFactoriesLoader.loadFactoryNames() 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表。
    • 查看spring-boot-autoconfigure-2.1.6.RELEASE.jar包中的META-INF/spring.factories文件:

      在这里插入图片描述

      • 可以在Auto Configure下面全是以下Configure类的全限定名

      • 通过搜索发现,META-INF/spring.factories文件有标明dispatcherServlet的配置类DispatcherServletAutoConfiguration

        org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
        
      • 查看dispatcherServlet的配置类DispatcherServletAutoConfiguration

        package org.springframework.boot.autoconfigure.web.servlet;
        
        // import
        
        @AutoConfigureOrder(-2147483648)
        @Configuration
        @ConditionalOnWebApplication(
            type = Type.SERVLET
        )
        @ConditionalOnClass({DispatcherServlet.class})
        @AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
        public class DispatcherServletAutoConfiguration {
            // dispatcherServlet bean对象的默认名称
            public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
            public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
        
            // ...
        }
        
3.2.3 举例自动配置
  • 如何在SpringBoot中自动配置自己的类

  • 例:

    • 新建包 com.atguigu.pojo , 创建类 User

      package com.ljf.pojo;
      
      public class User {
      }
      
    • resources文件夹下面 新建 /META-INF/spring.factories 文件

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ljf.pojo.User
      
    • 重启项目,然后查看该项目打印的bean对象:

      在这里插入图片描述

四、SpringBoot的配置文件

4.1 SpringBoot配置文件类型

  • SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application*.properties或者**application*.yml(application*.yaml)**进行配置。

  • SpringBoot默认会从Resources目录下加载application*.properties或application*.yml(application*.yaml)文件

    • 这些设置可以在pom.xml文件中的父工程spring-boot-dependencies中查看到:

      在这里插入图片描述

  • properties配置文件:

    • properties文件是键值对类型的文件,键与值之间使用=号连接

    • 例,在application.properties中对SpringBoot的tomcat的端口号进行修改:

      server.port=80
      
  • 具体可以修改SpringBoot的哪些配置文件,可以在 spring-boot-autoconfigure-2.1.6.RELEASE.jar 包中的 META-INF 目录下的 spring-configuration-metadata.json 文件中查找,

    在这里插入图片描述

    • 以服务器端口号server.port为例:

      在这里插入图片描述

4.2 application*.yml配置文件

  • yml配置文件简介

    • YML文件格式是YAML(YAML Aint Markup Language)编写的文件格式

    • YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。

    • YML文件是以数据为核心的,比传统的xml方式更加简洁。

    • YML文件的扩展名可以使用.yml或者.yaml。

  • yml配置文件的语法

    • 配置普通数据

      • 语法:

        key: value
        
      • 例:

        name: jeff
        
      • 注意:

        • value之前有一个空格
    • 配置对象数据

      • 语法:

        key: 
             key1: value1
             key2: value2
        # 或者:
        key: {key1: value1,key2: value2}
        
      • 例:

        server:
            port: 18082
        user:
            username: jeff
            password: 123
        
      • 注意:

        • yaml文件是按照key前面的空格区分级别的,相同缩进代表同一个级别,一般按一下tab键。
    • 配置Map数据

      • 语法:

        map: 
            key: value1
            key: value2
        
    • 配置数组(List、Set)数据

      • 语法:

        key: 
            - value1
            - value2
        # 或者:
        key: [value1,value2]
        
      • 例:

        # 配置数据集合
        city:
            - beijing
            - tianjin
            - shanghai
            - chongqing
        # 或者行内注入
        city: [beijing,tianjin,shanghai,chongqing]
        
      • 注意:

        • -号与value之间存在一个空格

4.3 配置文件与配置类的属性映射方式

4.3.1 @ConfigurationProperties注解
  • @ConfigurationProperties注解一般标注在组件类上,可以给组件属性赋值,所以其需要与@Component注解(或其衍生注解)使用。

  • 例:

    • 对于组件类User:

      package com.ljf.pojo;
      
      // import...
      
      @Component
      @ConfigurationProperties("user")
      public class User {
          private String username;
          private String password;
          private List<String> nicknames;
          private List<Mobile> mobiles;
          
          // get、set、toString方法
      }
      
      • 注意:
        • @ConfigurationProperties注解需要传入yml配置文件中的key,这里是user
    • application.yml文件中加入以下配置:

      user:
        username: jeff
        password: 123
        nicknames:
          - jj
          - ff
        mobiles:
          - num: 100
            brand: 华为
          - num: 101
            brand: 小米
      
    • 通过在SpringBoot的启动类中打印工程的所有bean对象:

      在这里插入图片描述

    • 再通过ApplicationContext的getBean()方法可以获取到user对象,发现属性的值与我们在配置文件中配置的值一样:

      在这里插入图片描述

4.3.2 使用注解@Value映射
  • 假如我们的组件类不需要使用一整个bean对象为其属性赋值,而只需要为其中的几个属性赋值,那么就可以通过@Value注解将配置文件中的值映射到一个Spring管理的Bean中的属性上

  • 例如:

    • application.yml配置如下:

      person:
        name: jeff
        addr: 南昌
      
    • 组件类HelloController

      package com.ljf.controller;
      
      // import...
      
      @RestController
      @RequestMapping("/hello")
      public class HelloController {
          @Value("${person.name}")
          private String name;
      
          @Value("${person.addr}")
          private String addr;
      
          @RequestMapping("/quick")
          public String quick() {
              return "name:"+name+",addr="+addr;
          }
      }
      
    • 访问http://localhost/hello/quick结果:

      在这里插入图片描述

  • @value注解语法:

    @value("${key1.key2.....key3}")
    // 成员属性
    

五、SpringBoot与整合其他技术

5.1 SpringBoot整合Mybatis

  • pom.xml中添加依赖(只需在原有的依赖上加入以下依赖即可):

    <!--mybatis起步依赖-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>
    
    <!-- MySQL连接驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
  • application.yml配置文件:

    server: # 重新指定服务器端口号
      port: 80
    
    mybatis:
      type-aliases-package: com.ljf.pojo  # 指定mybatis别名包
      mapper-locations: classpath:com/ljf/dao/*.xml # 指定xml映射文件路径
      configuration:
        map-underscore-to-camel-case: true  # 配置下划线命名到驼峰命名的自动转换
    
    logging:
      level:
        com.ljf.dao: debug # 配置日志为debug级
    
    spring:
      datasource: # 配置数据库数据源
        username: root
        password: ljf123
        url: jdbc:mysql://192.168.195.100:3306/meinian
        driver-class-name: com.mysql.cj.jdbc.Driver
    
  • 注意:

    • Bean类、Controller、Service、Dao.xml的写法与Spring的一致
    • 只有 Dao 接口不同,需要在接口上加上 @Mapper 注解,标记该类是一个mybatis的mapper接口,可以被spring boot自动扫描到spring上下文

5.2 SpringBoot整合Junit

  • pom.xml中添加依赖(只需在原有的依赖上加入以下依赖即可):

    <!--SpingBoot集成junit测试的起步依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    
  • 使用**@RunWit和@SpringBootTest注解**标识测试类就可以实现IOC自动注入:

    package com.ljf.test;
    
    // import...
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TestApplication {
        @Autowired
        private OrderService orderService;
    
        @Test
        public void testOrder() {
            List<Order> orders = orderService.findAll();
            for (Order order : orders) {
                System.out.println(order);
            }
        }
    }
    

5.3 SpringBoot整合Spring Data JPA

5.3.1 Spring Data JPA 简介
  • 什么是 JPA
    • JPA 英文名叫Java Persistence API,就是Java持久化API,是SUN公司推出的一套基于ORM的规范。
    • ORM:英文名为Object-Relational Mapping:对象关系映射
      • 简单来说为了不用JDBC那一套原始方法来操作数据库,ORM框架横空出世(等等)。
    • 主流的ORM框架(mybatis、hibernate等)都实现了 JPA规范。
  • **Spring Data JPA **:
    • Spring Data 家族的一部分,可以轻松实现基于JPA的存储库。
    • 此模块处理对基于JPA的数据访问层的增强支持, 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
  • Hibernate
    • JPA默认使用hibernat作为ORM实现,所以,一般使用Spring Data JPA即会使用Hibernate
    • Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装
    • 它将POJO与数据库表建立映射关系,是一个全自动的orm框架
    • hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
  • Mybatis
    • MyBatis是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射
  • Spring Data JPAMybatis 的区别:
    • 由于 Spring Data JPA 默认使用 Hibernate ,所以Spring Data JPA与MyBatis对比,起始也就是Hibernate与MyBatis对比。
    • 从SQL语句的角度看:
      • hibernate是一个自动化更强、更高级的框架
      • MyBatis 在Sql语句编写方面则更灵活自由。
    • 从抽象层次去看:
      • 对于数据的操作,hibernate是面向对象的,而MyBatis是面向关系的
5.3.2 Spring Data JPA 的使用
  • 在pom.xml导入依赖:(在原有的基础上加上这两个即可)

    <!-- springBoot JPA的起步依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!-- MySQL连接驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
  • application.yml中配置数据库和jpa的相关属性

    server: # 重新指定服务器端口号
      port: 80
    
    logging:
      level:
        com.ljf.dao: debug # 配置日志为debug级
    
    spring:
      datasource: # 配置数据库数据源
        username: root
        password: ljf123
        url: jdbc:mysql://192.168.195.100:3306/meinian
        driver-class-name: com.mysql.cj.jdbc.Driver
      jpa: # 配置 Spring Data JPA
        database: mysql
        show-sql: true
        generate-ddl: true
        hibernate:
          ddl-auto: update
          naming:
            # 表示使用 Hibernate 命名规则(即使用 @Table 和 @Column 注解定义的规则)
            physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    
  • 实体类Order

    • 注意这里与以往的实体类不一样

      package com.ljf.pojo;
      
      import javax.persistence.*;
      import java.util.Date;
      
      @Entity  // 表示这是一个实体类
      @Table(name = "t_order")  // 为该实体类指定对应的数据库表的表名
      public class Order {
          @Id  // 用于指定实体类的主键
          @GeneratedValue(strategy = GenerationType.IDENTITY)  // 设置主键为自增长
          @Column(name = "id")  // 改属性对应数据库表中字段名
          private Integer id;
          @Column(name = "member_id")
          private Integer memberId;
          @Column(name = "orderDate")
          private Date orderDate;
          @Column(name = "orderType")
          private String orderType;
          @Column(name = "orderStatus")
          private String orderStatus;
          @Column(name = "setmeal_id")
          private Integer setmealId;
      
          // get、set、toString方法
      }
      
  • Dao接口

    • 注意:需要继承 JpaRepository<T, TD> 接口,其中:

      • 泛型T为对应实体类的类名
      • 泛型TD为该实体类主键的类型
      package com.ljf.dao;
      
      import com.ljf.pojo.Order;
      import org.springframework.data.jpa.repository.JpaRepository;
      
      // 需要继承 JpaRepository<T, TD> 接口,其中泛型T为对应实体类的类名,泛型TD为该实体类主键的类型
      public interface OrderDao extends JpaRepository<Order, Integer> {
      
      }
      
    • 这个接口中虽然没有方法,但是其父类接口(以及祖父接口)中定义了很多基本的方法

  • Service类:(与以往的没区别)

    • OrderService接口:

      package com.ljf.service;
      
      import com.ljf.pojo.Order;
      
      import java.util.List;
      
      public interface OrderService {
          // 查询所有
          List<Order> findListOrder();
          // 根据id进行查询
          Order findOrderById(Integer id);
          // 保存Order
          void saveOrder(Order order);
          // 跟新
          void updateOrder(Order order);
          // 删除
          void deleteOrderById(Integer id);
      }
      
    • OrderServiceImpl

      package com.ljf.service.imp;
      
      // import
      
      @Service
      public class OrderServiceImpl implements OrderService {
          @Autowired
          private OrderDao orderDao;
      
          @Override
          public List<Order> findListOrder() {
              return orderDao.findAll();
          }
      
          @Override
          public Order findOrderById(Integer id) {
              return orderDao.findById(id).get();
          }
      
          @Override
          public void saveOrder(Order order) {
              orderDao.save(order);
          }
      
          @Override
          public void updateOrder(Order order) {
              orderDao.save(order);
          }
      
          @Override
          public void deleteOrderById(Integer id) {
              orderDao.deleteById(id);
          }
      }
      
  • SpringBoot启动类别忘了

  • 测试类:

    package com.ljf.test;
    
    // import...
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TestService {
        @Autowired
        private OrderService orderService;
    
        @Test
        public void testFindListOrder() {
            List<Order> orders = orderService.findListOrder();
            for (Order order : orders) {
                System.out.println(order);
            }
        }
        // 其他方法略...
    }
    
  • 注意:

    • 问题:

      • 当数据库表中的字段名不是按下划线格式命名时,会出无法找到字段的问题
    • 原因:

      • 原因是 SpringBoot Data JPA 默认会把所有的名称转为小写,而不是使用Hibernate@Table@Column 注解定义的规则,并且在大写字母前加上横线,比如 IsActive 翻译成 is_active。
    • 解决:

      • 我们应该使用 Hibernate 的命名规则,按照规则会使用 @Table@Column 中的名字。

      • 而使用 Hibernate 的命名规则需要在 springBoot 配置文件中加入如下规则:

        spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        

5.4 SpringBoot整合Redis

  • 找到上面的 springboot_mybatis 项目,在1pom.xml文件中添加Redis起步依赖

    <!-- 配置使用redis启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  • application.yml文件中添加 redis 的配置信息

    server: # 重新指定服务器端口号
      port: 80
    
    mybatis:
      type-aliases-package: com.ljf.pojo  # 指定mybatis别名包
      mapper-locations: classpath:com/ljf/dao/*.xml # 指定xml映射文件路径
    
    logging:
      level:
        com.ljf.dao: debug # 配置日志为debug级
    
    spring:
      datasource: # 配置数据库数据源
        username: root
        password: ljf123
        url: jdbc:mysql://192.168.195.100:3306/meinian
        driver-class-name: com.mysql.cj.jdbc.Driver
      redis:  # 配置Redis
        host: 192.168.195.100
        port: 6379
    
  • 注入RedisTemplate测试redis操作

    package com.ljf.service.impl;
    
    // import...
    
    @Service
    public class OrderServiceImpl implements OrderService {
        @Autowired
        private OrderDao orderDao;
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Override
        public List<Order> findAll() {
            // redis的key
            String key = "alluser";
            // 先查询redis中是否有数据,如果有直接返回redis的数据
            List<Order> orders = (List<Order>) redisTemplate.boundValueOps(key).get();
            if (orders!=null) {
                return orders;
            }
    
            // 如果没有,查询数据库
            orders = orderDao.findAll();
            // 将数据库数据存入到redis中
            if (orders != null && orders.size()>0) {
                redisTemplate.boundValueOps(key).set(orders);
            }
    
            return orders;
        }
    }
    

5.5 SpringBoot整合定时任务

5.5.1 SpringBoot整合定时任务
  • 创建工程 springboot_task

  • pom.xml文件中添加Scheduled依赖(基本SpringBoot依赖省略)

    <!-- 添加 Scheduled 依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.0.5.RELEASE</version>
    </dependency>
    
  • 创建SpringBoot启动类:

    • 注意,使用定时任务需要使用 @EnableScheduling 注解标注启动类

      package com.ljf;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.scheduling.annotation.EnableScheduling;
      
      @SpringBootApplication
      @EnableScheduling   // 定时任务需要加上这个注解
      public class TaskApplication {
          public static void main(String[] args) {
              SpringApplication.run(TaskApplication.class, args);
          }
      }
      
  • 创建定时任务类:

    • 任务类需要被Spring扫描到,所以需要使用@Component等注解标注。

    • 定时任务方法需要使用@Scheduled注解标注,在该注解中设定定时规则,可选的规则有三个:

      1. cron:cron表达式
      2. fixedDelay:在上一次定时任务执行完毕后N毫秒再次执行,
      3. fixedRate:执行周期,执行频率,定时任务执行开始,在过N毫秒后执行,例:
        * 执行A任务花了2秒,比如参数是3000,A任务执行完成之后,在过1秒后执行,
        * 执行A任务花了15秒,比如参数是3000,A任务执行完成之后,立即执行。
      package com.ljf.controller;
      
      // import...
      
      @Component
      public class TaskController {
          /**
           *  @Scheduled注解: 设定定时规则,可选三种规则:
           *       1. cron:cron表达式
           *
           *       2. fixedDelay:距离上一次定时任务执行完毕后N毫秒在执行,
           *
           *       3. fixedRate:执行周期,执行频率,定时任务执行开始,在过N毫秒后执行,例:
           *          执行A任务花了2秒,比如参数是3000,A任务执行完成之后,在过1秒后执行,
           *          执行A任务花了15秒,比如参数是3000,A任务执行完成之后,立即执行。
           */
          @Scheduled(fixedDelay = 3000)
          public void myTask() {
              try {
                  Thread.sleep(2000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              System.out.println(simpleDateFormat.format(new Date()));
          }
      }
      
      • 结果:

        在这里插入图片描述

5.5.2 corn表达式
  • cron表达式

    • corn表达式分为七个域,依次分别是:
      • 秒 分 时 日 月 周 年
    • 每个域之间使用空格分隔
    • 其中最后一个域(年)可以为空
    • 每个域都有自己允许的值和一些特殊字符构成
    • 使用这些特殊字符可以使我们定义的表达式更加灵活。
  • 下面是对这些特殊字符的介绍:

    • 逗号(,):指定一个值列表

      • 例如使用在月域上1,4,5,7表示1月、4月、5月和7月
    • 横杠(-):指定一个范围

      • 例如在时域上3-6表示3点到6点(即3点、4点、5点、6点)
    • 星号(*):表示这个域上包含所有合法的值

      • 例如,在月份域上使用星号意味着每个月都会触发
    • 斜线(/):表示递增

      • 例如使用在秒域上0/15表示每15秒
    • 问号(?):只能用在日和周域上,但是不能在这两个域上同时使用,表示不指定

      • 例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用 *,如果使用 * 表示不管星期几都会触发,实际上并不是这样。
    • 井号(#):只能使用在周域上,用于指定月份中的第几周的哪一天

      • 例如6#3,意思是某月的第三个周五 (6=星期五,3意味着月份中的第三周)
    • L:某域上允许的最后一个值,只能使用在日和周域上。

      • 当用在日域上,表示的是在月域上指定的月份的最后一天。
      • 用于周域上时,表示周的最后一天,就是星期六
    • W:W 字符代表着工作日 (星期一到星期五),只能用在日域上,它用来指定离指定日的最近的一个工作日

      在这里插入图片描述

  • cron表达式在线生成器:http://cron.qqe2.com/

5.6 SpringBoot整合Thymeleaf

  • pom.xml文件中加入thymeleaf起步依赖:

    <!-- thymeleaf 起步依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
  • application.yml中设置 thymeleaf 的缓存设置,设置为false。

    spring:
      thymeleaf:
        cache: false
    
  • 其他与以往发开一样,唯一需要注意的是:

    • 使用Ajax渲染页面时,Controller组件一般使用@RestController
    • 而使用Thymeleaf渲染页面时,Controller组件需要使用Controller