Spring Boot 3
第1章 First Spring Boot
认识Spring Boot
我们来看看官方是如何介绍的:
https://docs.spring.io/spring-boot/index.html


Spring Boot倡导约定优于配置,将简化开发发挥到极致。使用Spring Boot框架可以快速构建Spring应用,再也不需要大量的繁琐的的各种配置。Spring Boot框架设计的目标是:程序员关注业务逻辑就行了,环境方面的事儿交给Spring Boot就行。
Spring Boot特性:
- 快速创建独立的Spring应用程序。(Spring支持的SpringBoot都支持,也就是说SpringBoot全方位支持IoC,AOP等)
- 嵌入式的Tomcat、Jetty、Undertow容器。(web服务器本身就是几个jar包,Spring Boot框架自动嵌入了。)
- 需要什么功能时只需要引入对应的starter启动器即可。(启动器可以自动管理这个功能相关的依赖,自动管理依赖版本的控制)
- 尽最大努力,最大可能的自动配置Spring应用和第三方库。(例如:如果要进行事务的控制,不用做任何事务相关的配置,只需要在service类上添加@Transactional注解即可。)
- 没有代码生成,没有XML配置。(Spring Boot的应用程序在启动后不会动态地创建新的Java类,所有逻辑都是在编译期就已经确定好的)
- 提供了生产监控的支持,例如健康检查,度量信息,跟踪信息,审计信息等。也支持集成外部监控系统。
Spring Boot的开箱即用和约定优于配置:
- 开箱即用:Spring Boot框架设计得非常便捷,开发者能够在几乎不需要任何复杂的配置的情况下,快速搭建并运行一个功能完备的Spring应用。
- 约定优于配置:“约定优于配置”(Convention Over Configuration, CoC)是一种软件设计哲学,核心思想是通过提供一组合理的默认行为来减少配置的数量,从而简化开发流程。例如:Spring Boot默认约定了使用某个事务管理器,在事务方面不需要做任何配置,只需要在对应代码的位置上使用
@Transactional注解即可。
知识储备
学习本套课程的前提是你已经学过了:
- MyBatis
- Spring
- SpringMVC
主要版本说明
Spring Boot版本:3.3.5
IDEA版本:2024.2.4
JDK版本:21(Spring Boot3要求JDK的最低版本是JDK17)
First Spring Boot
需求:在浏览器上输入请求路径 http://localhost:8080/hello,在浏览器上显示 HelloWorld!
使用**Spring Boot3 开发web应用**,实现步骤如下:
第一步:创建一个空的工程,并设置JDK版本21(Spring Boot 3要求JDK最低版本是17)

设置jdk21

第二步:设置maven

第三步:创建一个Maven模块 sb3-01-first-web

第四步:打开Spring Boot 3官方文档,按照文档一步一步进行


第五步:要使用Spring Boot 3,需要继承这个开源项目。从官方指导文档中复制以下内容:

1 | <!--继承Spring Boot 3.3.3开源项目--> |
我们开发的每一个项目其实可以看做是 Spring Boot 项目下的子项目。
第六步:添加Spring Boot的web starter

这个也就是web启动器,在parent下立即添加如下配置,让Spring Boot项目具备开发web应用的依赖:
1 | <!--依赖--> |
关联的依赖也被引入进来,如下:

可以看到spring mvc被引入了,tomcat服务器也被引入了。
第七步:编写Spring Boot主入口程序
新建下面这个

1 | package com.powernode.springboot; |
第八步:编写controller
必须要放在主入口程序同级目录下或者子目录里
1 | // 提醒:这个HelloController要想被spring容器管理,这个类所在的位置必须满足:和SpringBoot主入口程序在同级目录下,或者子目录下。 |
第九步:运行main方法就是启动web容器

第十步:打开浏览器访问

便捷的部署方式
打jar包运行
Spring Boot提供了打包插件,可以将Spring Boot项目打包为**可执行 jar 包**。Web服务器(Tomcat)也会连同一块打入jar包中。只要电脑上安装了Java的运行环境(JDK),就可以启动Spring Boot项目。但注意不要去占用8080端口

根据官方文档指导,使用打包功能需要引入以下的插件:
1 | <!--这是一个能够创建可执行jar包的springboot插件。--> |
执行打包命令,生成可执行jar包:



单独的将这个 jar 包可以拷贝到任何位置运行,通过java -jar sb3-01-first-web-1.0-SNAPSHOT.jar命令来启动 Spring Boot 项目:

另外,Spring Boot框架为我们提供了非常灵活的配置,在可执行jar包的同级目录下新建配置文件:application.properties,并配置以下信息:
1 | server.port=8888 |
重新启动服务器,然后使用新的端口号访问:

SpringBoot的jar包和普通jar包的区别(面试题)
Spring Boot 打包成的 JAR 文件与传统的 Java 应用程序中的 JAR 文件相比确实有一些显著的区别,主要体现在依赖管理和可执行性上。
依赖管理:
- Spring Boot 的 JAR 包通常包含了应用程序运行所需的所有依赖项,也就是说它是一个“fat jar”(胖 JAR 包),这种打包方式使得应用可以独立运行,而不需要外部的类路径或应用服务器上的其他依赖。
- 普通的 JAR 文件一般只包含一个类库的功能,并且需要依赖于特定的类路径来找到其他的类库或者框架,这些依赖项通常在部署环境中已经存在,比如在一个应用服务器中。
可执行性:
- Spring Boot 的 JAR 文件可以通过直接执行这个 JAR 文件来启动应用程序,也就是说它是一个可执行的 JAR 文件。通过
java -jar your-application.jar命令就可以直接运行应用程序。 - 而普通的 JAR 文件通常是不可直接执行的,需要通过指定主类(main class)的方式或者其他方式来启动一个应用程序,例如使用
-cp或-classpath加上类路径以及主类名来执行。
Spring Boot 的这些特性使得部署和运行变得更加简单和方便,特别是在微服务架构中,每个服务都可以被打包成独立的 JAR 文件并部署到任何支持 Java 的地方。
SpringBoot的可执行jar包目录结构:

普通jar包的目录结构:
Spring Boot脚手架
什么是脚手架
建筑工程中的脚手架
在建筑工程领域,“脚手架”指的是临时性的结构,用于支撑建筑物以及建筑材料,同时为建筑工人提供工作平台。这种脚手架通常是由钢管、扣件、木板和其他配件组成的,可以根据施工需要搭建不同高度和形状的结构

软件开发中的脚手架
在软件开发领域,“脚手架”指的是用于快速创建项目基本结构的工具或模板。它帮助开发者初始化项目,设置必要的目录结构、文件模板以及依赖项。
Spring Boot脚手架
Spring Boot 脚手架(Scaffold)可以帮助开发者快速搭建一个Spring Boot项目结构,让开发者只专注于业务逻辑的开发,而不是在项目的初始阶段花费大量时间来配置环境或者解决依赖关系。
Spring Boot 脚手架工具存在多种形式,以下是一些常见的 Spring Boot 脚手架工具和方法:
- Spring Initializr:
这是 Spring 官方提供的工具,可以在 https://start.spring.io 上找到。它允许开发者选择所需的依赖、Java 版本、构建工具(Maven 或 Gradle)以及其他配置选项来生成一个新的 Spring Boot 项目。
- IntelliJ IDEA 内置支持:
IntelliJ IDEA 集成了 Spring Initializr 的功能,可以在 IDE 内直接创建 Spring Boot 项目。
- Start Alibaba Cloud:
阿里云提供的 Start Alibaba Cloud 增强版工具,除了基本的 Spring Boot 模块外,还集成了阿里云服务和中间件的支持。
- JHipster:
JHipster 是一个流行的脚手架工具,用于生成完整的 Spring Boot 应用程序,包括前端(Angular, React 或 Vue.js)和后端。它还包括用户管理和认证等功能。
- Yeoman Generators:
Yeoman 是一个通用的脚手架工具,它有一个庞大的插件生态系统,其中包括用于生成 Spring Boot 项目的插件。
- Bootify:
Bootify 是另一个用于生成 Spring Boot 应用程序的脚手架工具,提供了一些预定义的应用模板。
- Spring Boot CLI:
Spring Boot CLI 是一个命令行工具,允许用户通过命令行来编写和运行 Spring Boot 应用。
- Visual Studio Code 插件:
Visual Studio Code 社区提供了多个插件,如 Spring Boot Extension Pack,可以帮助开发者生成 Spring Boot 项目的基本结构。
- GitHub Gist 和 Bitbucket Templates:
在 GitHub 和 Bitbucket 上,有很多开发者分享了用于生成 Spring Boot 项目的脚本或模板。
- 自定义脚手架:
很多开发者也会根据自己的需求定制自己的脚手架工具,比如使用 Bash 脚本、Gradle 或 Maven 插件等。
使用官方提供的
使用官方脚手架生成Spring Boot项目
Spring Initializr:https://start.spring.io

点击“GENERATE”后,生成zip压缩包
将其解压后的目录结构是一个标准的maven 工程:
将项目放到IDEA当中
直接将解压后的sb3-02-use-spring-initializr拷贝到我们新建的空工程SpringBoot3下,然后重启idea就行了

注意:如果pom.xml文件的图标颜色不是蓝色,而是橘色,需要在pom.xml文件上右键,选择:add as maven project。这样pom.xml文件的图标就会变为蓝色了。
脚手架生成的pom.xml文件
1 |
|
脚手架生成的Spring Boot项目的结构

src下面就是程序的入口,java的这个位置是类的根路径,resources同样也是类的根路径,放在这里面相当于java的com同级,只不过java放的是源文件,resources放的是配置文件,static主要放静态的,templates放动态网页的模板文件
application.properties是我们主要配置的文件,是springboot默认的配置文件,
编写controller并测试
新建controller包,并新建HelloController类,如下图:

重点:默认情况下,SpringBoot项目只扫描主入口程序所在目录以及子目录,因此创建的Controller类要求放在主入口程序的同级目录下或子目录下。其他位置默认情况下扫描不到。
启动应用并访问:

使用阿里提供的
阿里巴巴提供的 Spring Boot 项目脚手架服务称为 DragonBoot(也被称为 Alibaba Cloud Spring Boot Initializr)。DragonBoot 基于 Spring Initializr,并在此基础上增加了更多的定制选项,特别是针对阿里巴巴云服务和中间件的支持。脚手架地址:https://start.aliyun.com/
当下(2024年)阿里云提供的脚手架使用的版本较低,国内有一些公司在用。如果要求版本较高的,则阿里云脚手架不适用。

使用IDEA工具的脚手架插件
IDEA工具自带了Spring Boot脚手架的插件,使用它会更加的方便,让我们来操作一下:


第2章 Spring Boot核心机制
为何以继承方式引入SpringBoot
提出疑问
以前我们在开发项目时,需要什么,引入对应的依赖就行,比如我们需要连接mysql数据,则引入mysql驱动的依赖,如下:
1 | <dependency> |
现在我们要使用SpringBoot框架,按说也应该采用依赖的方式将SpringBoot框架引入,如下:
1 | <dependency> |
但是SpringBoot官方推荐的不是直接引入依赖,而是采用继承的方式实现,如下:
1 | <parent> |
为什么?
作为父项目和作为依赖的区别
继承父工程的优势
- 依赖管理:可以在父工程中定义依赖的版本,子模块可以直接引用而不必指定版本号,让依赖管理更统一。
- 插件管理:可以在父工程中配置常用的插件及其版本,子模块可以直接使用这些配置。
- 属性设置:可以在父工程中定义一些通用的属性,如项目编码、Java 版本等。
- 统一配置:可以统一多个子模块的构建配置,确保一致性。
直接引入依赖的局限性(如果你不使用继承父工程的方式,而是通过直接引入依赖的方式来管理项目,那么你将失去上述的一些优势)
- 依赖版本管理:每个子模块都需要单独指定依赖的版本,这会导致大量的重复配置,并且难以维护。
- 插件配置:每个子模块都需要单独配置插件及其版本,无法共享父工程中的插件配置。
- 属性设置:每个子模块都需要单独设置通用的属性,如项目编码、Java 版本等。
- 构建配置:每个子模块的构建配置需要单独维护,难以保证一致性。
总结:选择哪种方式取决于你的具体需求。
- 如果你希望多个项目之间共享构建配置,那么使用父项目是一个好的选择;
- 如果你只是想在项目之间共享代码,那么应该使用依赖关系。
原理揭晓
通过源码来分析一下:



通过上图源码可以看到Spring Boot预先对开发中需要用到的依赖进行了版本的统一管理。我们需要和SpringBoot框架共享这个构建配置。因此官方推荐使用继承的方式引入SpringBoot框架。
依赖统一管理的好处
Spring Boot 框架的一个重要特性就是简化了项目依赖管理。它通过提供一个叫做“依赖管理”的功能来帮助开发者更容易地管理和使用第三方库和其他 Spring 组件。具体来说,Spring Boot 提供了一个包含多个 Spring 和其他常用库的依赖版本配置文件(通常是在 spring-boot-dependencies 文件中),这使得开发者不需要在自己的项目中显式指定这些依赖的版本号。
这样做有以下几个好处:
- 简化依赖声明:
开发者只需要在pom.xml文件中声明需要的依赖而不需要指定其版本号,因为 Spring Boot 已经为这些依赖指定了版本。例如,如果你需要使用mysql驱动,你只需要添加相应的依赖声明而不需要关心版本。
1 | <dependency> |
- 避免版本冲突:
当多个库之间存在依赖关系的时候,如果手动管理版本可能会导致版本之间的冲突(即“依赖地狱”)。Spring Boot 提供的统一版本管理可以减少这种冲突的可能性。 - 易于升级:
当 Spring Boot 发布新版本时,通常会更新其依赖库到最新稳定版。因此,当你升级 Spring Boot 版本时,它所管理的所有依赖也会随之更新到兼容的版本。 - 减少配置错误:
由于 Spring Boot 自动处理了依赖的版本,减少了手动输入版本号可能引入的拼写或格式错误。 - 提高开发效率:
开发者可以专注于业务逻辑的编写,而不是花费时间在解决依赖问题上。
总的来说,Spring Boot 的依赖管理功能使得开发者可以更加专注于业务逻辑的实现,同时减少了因依赖版本不一致而引发的问题,提高了项目的可维护性和开发效率。
当然,如果你在项目中需要更改某个依赖的版本号,不想使用SpringBoot框架指定的版本号,只需要在引入依赖时强行执行版本号即可,maven是支持就近原则的:
这样做就是采用SpringBoot指定版本的依赖:
1 | <dependency> |

这样做就是不采用SpringBoot指定版本的依赖:
1 | <dependency> |

Starter-启动器
在 Spring Boot 中,启动器(Starter)本质上是一个简化依赖管理的概念。
Spring Boot 的启动器本质上就是一组预定义的依赖集合,它们被组织成一个个 Maven的依赖,以方便开发者快速集成特定的功能模块。
如果你想做web开发,只需要引入web启动器。web启动器会自动引入web开发所需要的子依赖。
启动器实现原理
- 依赖聚合:
每个启动器通常对应一个特定的功能集或者一个完整的应用模块,如spring-boot-starter-web就包含了构建 Web 应用所需的所有基本依赖项,如 Spring MVC, Tomcat 嵌入式容器等。 - 依赖传递:
当你在项目中引入一个启动器时,它不仅会把自身作为依赖加入到你的项目中,还会把它的所有直接依赖项(transitive dependencies)也加入进来。这意味着你不需要单独声明这些依赖项,它们会自动成为项目的一部分。 - 版本管理:
启动器内部已经指定了所有依赖项的具体版本,这些版本信息存储在一个公共的 BOM(Bill of Materials,物料清单)文件中,通常是spring-boot-dependencies。当引入启动器时,实际上也间接引用了这个 BOM,从而确保了所有依赖项版本的一致性。 - 自动配置:
许多启动器还提供了自动配置(Auto-configuration),这是一种机制,允许 Spring Boot 根据类路径上的可用组件自动设置你的应用程序。例如,如果类路径上有 Spring MVC 和嵌入式 Tomcat,则 Spring Boot 会自动配置它们,并准备好一个 web 应用程序。
使用启动器的示例
假设你想创建一个基于 Spring MVC 的 RESTful Web 应用,你可以简单地将 spring-boot-starter-web 添加到你的项目中:
1 | <dependency> |
当你添加这个依赖时,Spring Boot 会处理所有必要的细节,包括添加 Spring MVC 和 Tomcat 作为嵌入式 Servlet 容器,并且根据类路径上的内容进行适当的自动配置。如下图所示:

都有哪些启动器
启动器通常包括:
- SpringBoot官方提供的启动器
- 非官方提供的启动器
官方提供的启动器
启动器命名特点:spring-boot-starter-*

非官方的启动器
启动器命名特点:*-spring-boot-starter

Spring Boot核心注解
如果加入了mybatis启动器,就必须配置数据源,否则报错
@SpringBootApplication注解
Spring Boot的主入口程序被@SpringBootApplication注解标注,可见这个注解的重要性,查看它的源码:

- 当前类被 @SpringBootApplication 标注,被该注解标注的类是springboot项目的入口类。
- 该类的main方法就是整个springboot项目的入口。
- 关于 @SpringBootApplication 注解:
从源码角度来看,该注解被以下三个注解标注了:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
也就是说 @SpringBootApplication 注解是一个复合注解,同时拥有以上三个注解的功能。
/@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@ComponentScan.Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @ComponentScan.Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)把这些注解直接复制到这里也可以代替@SpringBootApplication/
1 |
|
关于 @SpringBootConfiguration 注解:
从源码角度来看,该注解被 @Configuration 注解标注,被该注解标注的类统一是配置类,代替以前的配置。
因此得出一个结论:springboot项目的主入口类同时又是一个配置类。
因此在springboot主入口配置类当中使用 @Bean 注解标注方法的话,该方法的返回值对象应该会被纳入IoC容器的管理。
1 |
|
再写一个Controller
1 |
|
就可以通过浏览器接收到date了
关于 @EnableAutoConfiguration 注解:
该注解表示启用自动配置。
也就是说默认情况下,springboot应用都会默认启用自动配置。
自动配置有什么用?
所谓的自动配置只要启动,springboot应用会去类路径当中查找class,根据类路径当中有某个类,或某些类,来自动管理bean,不需要我们程序员手动配置。
比如:springboot检测到类路径当中有 SqlSessionFactory,或者在application.properties文件中配置了数据源,那么springboot会认为项目中
有mybatis框架,因此会将mybatis中相关的bean自动初始化,然后放到IoC容器当中,自动将这些bean管理起来。
SqlSessionFactory: MyBatis的核心工厂SqlSessionFactory会被自动配置。这个工厂负责创建SqlSession实例,后者用来执行映射文件中的SQL语句。
TransactionManager: DataSourceTransactionManager会被自动配置来管理与数据源相关的事务。
要先在pom里配上mybatis依赖
1
2
3
4
5
6
7
8
9
10
11
12<!--mybatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<!--添加mysql驱动依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>然后在application里配置数据源
1
2
3
4
5spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver//如果爆红就需要添加mysql依赖
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=liuqi3711022
spring.datasource.type=com.zaxxer.hikari.HikariDataSource1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Springboot304CoreAnnotationApplication {
public static void main(String[] args) {
// 通过 run方法的返回值是可以获取到 Spring 上下文对象的(也就是.var的那个)。
// ConfigurableApplicationContext 继承了 ApplicationContext
// 因此 run方法的返回值就是spring容器。
ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot304CoreAnnotationApplication.class, args);
//通过bean的name获取bean,就都能检测到
Object sqlSessionFactory = applicationContext.getBean("sqlSessionFactory");
System.out.println(sqlSessionFactory);
Object transactionManager = applicationContext.getBean("transactionManager");
System.out.println(transactionManager);
//关闭容器
applicationContext.close();
}
}
关于 @ComponentScan 注解:
负责组件扫描的。代替的xml配置是:
1 | <context:component-scan base-packages="com.powernode.springboot" /> |
这个注解出现在springboot主入口类上,因此组件扫描默认扫描的包是主入口程序所在的包以及该包下的所有子包。
要让bean纳入IoC容器的管理,必须将类放到主入口程序同级目录下,或者子目录下。
Spring Boot的单元测试(没看懂)
controller属于表示层或者叫web层
不使用单元测试怎么调用service
创建模块
使用脚手架创建springboot3-05-junit模块,不添加任何启动器
编写service

1 | //给起个名字叫userService |
1 | public interface UserService { |
直接在入口程序中调用service
1 |
|
执行结果:

这种方式就是手动获取Spring上下文对象ConfigurableApplicationContext,然后调用getBean方法从Spring容器中获取service对象,然后调用方法。
使用单元测试怎么调用service
test-starter引入以及测试类编写
使用单元测试应该如何调用service对象上的方法呢?
在使用脚手架创建Spring Boot项目时,为我们生成了单元测试类,如下:


当然,如果要使用单元测试,需要引入单元测试启动器,如果使用脚手架创建SpringBoot项目,这个test启动器会自动引入:
1 | <dependency> |
@SpringBootTest注解
@SpringBootTest 会创建一个完整的 Spring 应用程序上下文(Application Context),这个上下文包含了应用程序的所有组件和服务。以下是 @SpringBootTest 做的一些主要工作:
- 创建 ApplicationContext:
@SpringBootTest使用SpringApplication的run()方法来启动一个 Spring Boot 应用程序上下文。这意味着它会加载应用程序的主配置类和其他相关的配置类。
- 加载配置文件:
- 它会查找并加载默认的配置文件,如
application.properties
- 它会查找并加载默认的配置文件,如
- 自动配置:
- 如果应用程序依赖于 Spring Boot 的自动配置特性,
@SpringBootTest会确保这些自动配置生效。这意味着它会根据可用的类和bean来自动配置一些组件,如数据库连接、消息队列等。
- 如果应用程序依赖于 Spring Boot 的自动配置特性,
- 注入依赖:
- 使用
@SpringBootTest创建的应用程序上下文允许你在测试类中使用@Autowired注入需要的 bean,就像在一个真实的 Spring Boot 应用程序中一样。
- 使用
总的来说,@SpringBootTest 为你的测试提供了尽可能接近实际运行时环境的条件,这对于验证应用程序的行为非常有用。
注入service并调用
1 | // springboot项目中使用单元测试junit,那么单元测试类必须使用这个注解进行标注。 |
外部化配置
什么是外部化配置
外部化配置是指:将配置信息存储在应用程序代码之外的地方。这样配置信息可以独立于代码进行管理。这样方便了配置的修改,并且修改后不需要重新编译代码,也不需要重新部署项目。
在springboot应用程序默认是先找外部化配置
外部化配置的方式
SpringBoot支持多种外部化配置方式,包括但不限于:
- properties文件
- YAML文件
- 系统环境变量
- 命令行参数
- ……
外部化配置的优势
- 灵活性:配置文件可以独立于应用程序部署,这使得可以根据运行环境的不同来调整配置,而无需修改代码。
- 易于维护:配置变更不需要重新构建和部署应用程序,降低了维护成本。
- 安全性:敏感信息如数据库密码、API密钥等可以存储在外部,并且可以限制谁有权限访问这些配置信息。
- 共享性:多实例或多服务可以共享相同的配置信息,减少重复配置的工作量。
- 版本控制:配置文件可以存放在版本控制系统中,便于跟踪历史版本和回滚配置。
总之,外部化配置使得配置更加灵活、安全、易于管理和共享,是现代云原生应用中非常推荐的做法
外部化配置对比传统配置
在传统的SSM三大框架中,如果修改XML的配置后,需要对应用重新打包,重新部署。
使用SpringBoot框架的外部化配置后,修改配置后,不需要对应用重新打包,也不需要重新部署,最多重启一下服务即可。
application.properties
application.properties配置文件是SpringBoot框架默认的配置文件。
application.properties不是必须的,SpringBoot对于应用程序来说,都提供了一套默认配置(就是我们所说的自动配置)。
如果你要改变这些默认的行为,可以在application.properties文件中进行配置。
application.properties可以放在类路径当中,也可以放在项目之外。因此称为外部化配置。
 类的根路径calsspath
Spring Boot 框架在启动时会尝试从以下位置加载 application.properties 配置文件(优先级从高到低):
- file:./config/(在jar包外的):首先在Spring Boot 当前工作目录下的
config文件夹中查找。- 注意:如果没有找到application.properties会继续找application.yml,如果这两个都没有找到,才会进入以下位置查找,以此类推。
- file:./:如果在当前工作目录下
config目录中找不到时,再从当前工作目录中查找,找不到properties就再找yml。 - classpath:/config/:如果从工作目录中找不到,会从类路径中找,先从类路径的
/config/目录下寻找配置文件。 - classpath:/:如果在
/config/下没有找到,它会在类路径的根目录下查找。
Spring Boot 会按照这个顺序来加载配置文件,如果在多个位置有相同的属性定义,那么最先检查的位置中的属性值将优先使用。
如果你想要指定其他的配置文件位置或者改变默认的行为,可以通过 --spring.config.location= 后跟路径的方式来指定配置文件的具体位置。例如 :
1 | java -jar sb3-01-first-web-1.0-SNAPSHOT.jar --spring.config.location=file:///E:\a\b\application.properties |
这样,Spring Boot 将会首先从 E:\a\b\ 这个路径加载配置文件。注意,这种方式可以用来覆盖默认的配置文件位置,并且可以结合以上提到的位置一起使用。
注意:以上的--spring.config.location=file:///E:\a\b\application.properties就属于命令行参数,它将来会被传递到main方法的(String[] args)参数上。
1 |
|
使用@Value注解
@Value注解可以将application.properties/application.yml文件中的配置信息注入/绑定到java对象的属性上。
语法格式:@Value(“${key}”)
使用脚手架创建SpringBoot项目,不添加任何启动器,在resources/application.properties文件中进行如下配置:
1 | myapp.username=jackson |
编写service类:
1 |
|
编写单元测试:
1 |
|
运行结果:
YAML
YAML概述
SpringBoot采用集中式配置管理,所有的配置都编写到一个配置文件中:application.properties
如果配置非常多,层级不够分明,因此SpringBoot为了提高配置文件可读性,也支持YAML格式的配置文件:application.yml
YAML(YAML Ain’t Markup Language)是一种人类可读的数据序列化格式,它通常用于配置文件,在各种编程语言中作为一种存储或传输数据的方式。YAML的设计目标是易于阅读和编写,同时保持足够的表达能力来表示复杂的数据结构。
YAML文件的扩展名可以是**<font style="color:#DF2A3F;">.yaml</font>**或**<font style="color:#DF2A3F;">.yml</font>**。
常见的数据存储和交换格式
properties、XML、JSON、YAML这几种格式确实是用来存储和交换数据的常见方式,但它们各有特点和适用场景:
Properties
- 这种格式主要用于Java应用程序中的配置文件。它是键值对的形式,每一行是一个键值对,使用等号或冒号分隔键和值。
- 特点是简单易懂,但在处理复杂结构的数据时显得力不从心。
XML (eXtensible Markup Language)
- XML是一种标记语言,用来描述数据的格式。它支持复杂的数据结构,包括嵌套和属性。
- XML文档具有良好的结构化特性,适合传输和存储结构化的数据。但是,XML文档通常体积较大,解析起来也比较耗资源。
JSON (JavaScript Object Notation)
- JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,支持多种数据类型,如数字、字符串、布尔值、数组和对象。
- JSON因为简洁和高效而广泛应用于Web应用程序之间进行数据交换。
YAML (YAML Ain’t Markup Language)
- YAML设计的目标之一就是让人类更容易阅读。它支持类似JSON的数据序列化,但提供了更多的灵活性,例如缩进来表示数据结构。
- YAML非常适合用来编写配置文件,因为它允许以一种自然的方式组织数据,并且可以包含注释和其他人类可读的元素。
总结来说,这四种格式都可以用来存储和交换数据,但它们的设计初衷和最佳使用场景有所不同。选择哪种格式取决于具体的应用需求、数据复杂度、性能要求等因素。

YAML的语法规则
YAML的语法规则如下:
- 数据结构:YAML支持多种数据类型,包括:
- 字符串、数字、布尔值
- 数组、list集合
- map键值对 等。
- YAML使用
一个空格来分隔属性名和属性值,例如:properties文件中这样的配置:name=jackyaml文件中需要这样配置:name: jack
- YAML用
换行+空格来表示层级关系。注意不能使用tab,必须是空格,空格数量无要求,大部分建议2个或4个空格。例如:properties文件中这样的配置:myapp.name=mallyaml文件中就需要这样配置:
1 | myapp: |
- 同级元素左对齐。例如:
properties文件中有这样的配置:
1 | myapp.name=mall |
2. `yaml`文件中就应该这样配置:
1 | myapp: |
- 键必须是唯一的:在一个映射中,键必须是唯一的。
- 注释:使用
#进行注释。 - 大小写敏感
YAML的使用小细节
第一:普通文本也可以使用单引号或双引号括起来:(当然普通文本也可以不使用单引号和双引号括起来。)
- 单引号括起来:单引号内所有的内容都被当做普通文本,不转义(例如字符串中有\n,则\n被当做普通的字符串)
- 双引号括起来:双引号中有 \n 则会被转义为换行符
第二:保留文本格式
| 将文本写到这个符号的下层,会自动保留格式。
1
2
3
4
5myapp:
username: |
aaaa
bbbb
cccc
第三:文档切割
- — 这个符号下面的配置可以认为是一个独立的yaml文件。便于庞大文件的阅读。
配置文件合并
一个项目中所有的配置全部编写到application.properties文件中,会导致配置臃肿,不易维护,有时我们会将配置编写到不同的文件中,例如:application-mysql.properties专门配置mysql的信息,application-redis.properties专门配置redis的信息,最终将两个配置文件合并到一个配置文件中。
properties文件
配置文件里有中文的话编码格式会变成 ,需要在settings里有个File encoding,

application-mysql.properties
1 | spring.datasource.username=root |
application-redis.properties
1 | spring.data.redis.host=localhost |
application.properties
1 | spring.config.import=classpath:application-mysql.properties,classpath:application-redis.properties |
编写service测试,看看能否拿到配置信息:
1 |
|
yaml文件
application-mysql.yml
1 | spring: |
application-redis.yml
1 | spring: |
application.yml
1 | spring: |
多环境切换
在Spring Boot中,多环境切换是指在一个应用程序中支持多种运行环境配置的能力。这通常用于区分开发(development)、测试(testing)、预生产(staging)和生产(production)等不同阶段的环境。
这种功能使得开发者能够在不同的环境中使用不同的配置,比如数据库连接信息、服务器端口、环境变量等,而不需要更改代码。这对于维护一个可移植且易于管理的应用程序非常重要。
- 开发环境的配置文件名一般叫做:
application-dev.properties
1 | spring.datasource.username=dev |
- 测试环境的配置文件名一般叫做:
application-test.properties
1 | spring.datasource.username=test |
- 预生产环境的配置文件名一般叫做:
application-preprod.properties
1 | spring.datasource.username=preprod |
- 生产环境的配置文件名一般叫做:
application-prod.properties
1 | spring.datasource.username=prod |
然后添加下面的东西
如果你希望该项目使用生产环境的配置,你可以这样做:
- 第一种方式:在
application.properties文件中添加这个配置:spring.profiles.active=prod,这个prod就是用来区分环境的,测试环境就换成test - 第二种方式:在命令行参数上添加:–spring.profiles.active=prod
将配置绑定到bean
绑定简单bean
SpringBoot配置文件中的信息除了可以使用@Value注解读取之外,也可以将配置信息一次性赋值给Bean对象的属性。
例如有这样的配置:
1 | myapp: |
1 | # 将这里的配置信息一次性的绑定到bean对象的属性上。比 @Value 注解好用,方便。 |
Bean需要这样定义:
1 | // 纳入IoC容器的管理。 |
- 被绑定的bean,需要使用
@ConfigurationProperties(prefix = "app")注解进行标注,prefix用来指定前缀,哪个是前缀 - 配置文件中的
name、age、email要和bean对象的属性名name、age、email对应上。(属性名相同) - 并且bean中的所有属性都提供了
setter方法。因为底层是通过setter方法给bean属性赋值的。 - 这样的bean需要使用
@Component注解进行标注,纳入IoC容器的管理。@Component注解负责创建Bean对象,@ConfigurationProperties(prefix = "app")注解负责给bean对象的属性赋值。 - bean的属性需要是
非static的属性。
我们把这个Bean对象的类名打印一下看看:

可以发现底层实际上创建了AppBean的代理对象AppBean$$SpringCGLIB。
生成代理对象会影响效率,这里我们不需要使用代理功能,可以通过以下配置来取消代理机制:
1 |
|
绑定嵌套bean
当一个Bean中嵌套了一个Bean,这种情况下可以将配置信息绑定到该Bean上吗?当然可以。
有这样的一个配置:
1 | app: |
需要编写这样的两个Bean:
1 | public class Address { |
1 |
|
然后执行测试程序
@EnableConfigurationProperties与@ConfigurationPropertiesScan
将AppBean纳入IoC容器的管理,之前我们说了两种方式:第一种是使用@Component,第二种是使用@Configuration。SpringBoot其实还提供了另外两种方式:
- 第一种:@EnableConfigurationProperties
- 第二种:@ConfigurationPropertiesScan
这两个注解都是标注在SpringBoot主入口程序上的:
1 | // 将配置信息绑定到bean的第三种方式:在主入口程序上添加以下注解。 |
将配置赋值到Bean的Map/List/Array属性上
配置信息如下
1 | app2.abc.names[0]=jack |
代码如下:
1 | //@Component如果不加这个,就在主入口那边绑定bean |
提醒:记得入口程序使用@EnableConfigurationProperties({User.class, AppBean.class})进行标注。
yml配置信息:
1 | app2: |
将配置绑定到第三方对象
将配置文件中的信息绑定到某个Bean对象上,如果这个Bean对象没有源码,是第三方库提供的,怎么办?
此时可以单独编写一个方法,在方法上使用以下两个注解进行标注:
- @Bean
- @ConfigurationProperties
比如借用上面的类Address.class,可以写一个方法返回这个类的对象然后纳入ioc容器
1 | // 指定该类是一个配置类。 |
指定数据来源
之前所讲的内容是将Spring Boot框架默认的配置文件application.properties或application.yml作为数据的来源绑定到Bean上。如果配置信息没有在默认的配置文件中呢?可以使用@PropertySource注解指定配置文件的位置,这个配置文件可以是.properties,也可以是.xml。这里重点掌握.properties即可。
在resources目录下新建a目录,在a目录下新建b目录,b目录中新建group-info.properties文件,进行如下的配置:
1 | group.name=IT |
定义Java类Group,然后进行注解标注:
1 |
|
以下三个注解分别起到什么作用:
- @Configuration:指定该类为配置类,纳入Spring容器的管理
- @ConfigurationProperties(prefix = “group”):将配置文件中的值赋值给Bean对象的属性
- @PropertySource(“classpath:a/b/group-info.properties”):指定额外的配置文件
@ImportResource注解
创建Bean的三种方式总结:
- 第一种方式:编写applicationContext.xml文件,在该文件中注册Bean,Spring容器启动时实例化配置文件中的Bean对象。
- 第二种方式:@Configuration注解结合@Bean注解。
- 第三种方式:@Component、@Service、@Controller、@Repository等注解。
第二种和第三种我们都已经知道了。针对第一种方式,如果在SpringBoot框架中应该怎么实现呢?使用@ImportResource注解实现
定义一个普通的Java类:Person
1 | public class Person { |
在resources目录下新建applicationContext.xml配置文件,添加:

1 | <bean id="person" class="com.powernode.springboot.bean.Person"> |
在SpringBoot主入口类上添加@ImportResource进行资源导入,这样applicationContext.xml文件中的Bean将会纳入IoC容器的管理:
1 |
|
Environment
SpringBoot框架在启动的时候会将系统配置,环境信息全部封装到Environment对象中,如果要获取这些环境信息,可以调用>Environment接口的方法
在Spring Boot中,Environment接口提供了访问应用程序环境信息的方法,比如活动配置文件、系统环境变量、命令行参数等。Environment接口由Spring框架提供,Spring Boot应用程序通常会使用Spring提供的实现类AbstractEnvironment及其子类来实现具体的环境功能。
Environment对象封装的主要数据包括:
- Active Profiles: 当前激活的配置文件列表。Spring Boot允许应用程序定义不同的环境配置文件(如开发环境、测试环境和生产环境),通过激活不同的配置文件来改变应用程序的行为。
- System Properties: 系统属性,通常是操作系统级别的属性,比如操作系统名称、Java版本等。
- System Environment Variables: 系统环境变量,这些变量通常是由操作系统提供的,可以在启动应用程序时设置特定的值。
- Command Line Arguments: 应用程序启动时传递给主方法的命令行参数。
- Property Sources:
Environment还包含了一个PropertySource列表,这个列表包含了从不同来源加载的所有属性。PropertySource可以来自多种地方,比如配置文件、系统属性、环境变量等。
在Spring Boot中,可以通过注入Environment来获取上述信息。例如:
1 |
|
通过这种方式,你可以根据环境的不同灵活地配置你的应用程序。Environment是一个非常有用的工具,它可以帮助你管理各种类型的配置信息,并根据不同的运行时条件做出相应的调整。
Spring Boot中如何进行AOP的开发(需要补习)
Spring Boot AOP概述
面向切面编程AOP在Spring教程中已经进行了详细讲解,这里不再赘述,如果忘记的同学,可以重新听一下Spring教程中AOP相关的内容。这里仅带着大家在Spring Boot中实现AOP编程。
Spring Boot的AOP编程和Spring框架中AOP编程的唯一区别是:引入依赖的方式不同。其他内容完全一样。Spring Boot中AOP编程需要引入aop启动器:
1 | <!--aop启动器--> |

可以看到,当引入aop启动器之后,会引入aop依赖和aspectj依赖。
- aop依赖:如果只有这一个依赖,也可以实现AOP编程,这种方式表示使用了纯Spring AOP实现aop编程。
- aspectj依赖:一个独立的可以完成AOP编程的AOP框架,属于第三方的,不属于Spring框架。(我们通常用它,因为它的功能更加强大)
Spring Boot AOP实现
实现功能:项目中很多service,要求执行任何service中的任何方法之前记录日志。
创建Spring Boot项目引入aop启动器
1 | <!--aop启动器--> |
编写service并提供方法
1 | public interface UserService { |
1 |
|
编写切面
1 | //指定它是一个切面 |
测试
1 | public static void main(String[] args) { |
第3章 SSM整合
整合持久层框架MyBatis
准备数据库表及数据
创建数据库:springboot
使用IDEA工具自带的mysql插件来完成表的创建和数据的准备:




表创建成功后,为表准备数据,如下:

创建SpringBoot项目
引入mysql驱动以及mybatis的启动器

依赖如下:
1 | <!--mybatis的启动器--> |
注意,之前也提到过:
- Spring Boot官方提供的启动器的名字规则:spring-boot-starter-xxx
- 第三方(非Spring Boot官方)提供的启动器的名字规则:xxx-spring-boot-starter
编写数据源配置
前面提到过,Spring Boot配置统一可以编写到application.properties中,配置如下:
1 | # Spring Boot脚手架自动生成的 |
以上的配置属于连接池的配置,连接池使用的是Spring Boot默认的连接池:HikariCP
1 | # 数据源配置 |
编写实体类Vip
表t_vip中的字段分别是:
- id
- name
- card_number
- birth
对应实体类Vip中的属性名分别是:
- Long id;
- String name;
- String cardNumber;
- String birth;
创建包bean,在该包下新建Vip类,代码如下:
1 | public class Vip { |
编写Mapper接口
创建repository包,在该包下新建VipMapper接口,代码如下:
1 | public interface VipMapper { |
编写Mapper接口的XML配置文件
在resources目录下新建mapper目录,将来的mapper.xml配置文件放在这个目录下。
安装MyBatisX插件,该插件可以根据我们编写的VipMapper接口自动生成mapper的XML配置文件。

然后在VipMapper接口上:alt+enter,选择[mybatisx]generate mapper of xml,生成mapper of xml:需要选择一个生成的位置


接下来,你会看到Mapper接口中方法报错了,可以在错误的位置上使用alt+enter,选择Generate statement:

这个时候在mapper的xml配置文件中便生成了对应的配置,如下:

接下来就是编写SQL语句了,最终VipMapper.xml文件的配置如下:
1 |
|
配置文件起别名:
1 | # mybatis相关配置 |
1 | # mybatis相关配置 |
写个VipService接口
1 | public interface VipService { |
写实现类VipServiceImpl
1 |
|
添加Mapper的扫描
上面的VipMapper会有红线,是因为springboot不知道在哪里
在Spring Boot的入口程序上添加如下的注解,来完成VipMapper接口的扫描:
1 | // 通过这个指定去哪里找Mapper接口(配置Mapper的扫描。) |
告诉MyBatis框架MapperXML文件的位置
在application.properties配置文件中进行如下配置:
1 | # 2. 告诉springboot mapper.xml文件在哪里 |
1 | # 2. 告诉springboot,mapper配置文件的位置 |
测试整合MyBatis是否成功
在Spring Boot主入口程序中获取Spring上下文对象ApplicationContext,从Spring容器中获取VipMapper对象,然后调用相关方法进行测试:
1 | // 通过这个指定去哪里找Mapper接口(配置Mapper的扫描。) |
测试结果:

测试结果中可以看到cardNumber属性没有赋值成功,原因是:表中的字段名叫做card_number,和实体类Vip的属性名cardNumber对应不上。解决办法两个:
- 第一种方式:查询语句使用as关键字起别名,让查询结果列名和实体类的属性名对应上。
1 | <select id="selectAll" resultType="Vip"> |
- 第二种方式:通过配置自动映射
1 | # 3. 启用自动映射数据库表的列名和bean的属性名 |
mapper的xml文件中的sql语句仍然使用*的方式:
map-underscore-to-camel-case 是一个配置项,主要用于处理数据库字段名与Java对象属性名之间的命名差异。在许多数据库中,字段名通常使用下划线(_)分隔单词,例如 first_name 或 last_name。而在Java代码中,变量名通常使用驼峰式命名法(camel case),如 firstName 和 lastName。
当使用MyBatis作为ORM框架时,默认情况下它会将SQL查询结果映射到Java对象的属性上。如果数据库中的字段名与Java对象的属性名不一致,那么就需要手动为每个字段指定相应的属性名,或者使用某种方式来自动转换这些名称。
map-underscore-to-camel-case 这个配置项的作用就是在查询结果映射到Java对象时,自动将下划线分隔的字段名转换成驼峰式命名法。这样可以减少手动映射的工作量,并提高代码的可读性和可维护性。
Lombok库
Lombok 是一个 Java 库,它可以通过注解的方式减少 Java 代码中的样板代码。Lombok 自动为你生成构造函数、getter、setter、equals、hashCode、toString 方法等,从而避免了手动编写这些重复性的代码。这不仅减少了出错的机会,还让代码看起来更加简洁。
Lombok只是一个编译阶段的库,能够帮我们自动补充代码,在Java程序运行阶段并不起作用。(因此Lombok库并不会影响Java程序的执行效率)
添加依赖
在 Maven 的 pom.xml 文件中添加 Lombok 依赖:
1 | <dependency> |
IDEA中安装Lombok插件
高版本的IntelliJ IDEA工具默认都是绑定Lombok插件的,不需要再额外安装:
Lombok 的主要注解
@Data:
- 等价于
@ToString,@EqualsAndHashCode,@Getter,@Setter,@RequiredArgsConstructor. - 用于生成:必要参数的构造方法、getter、setter、toString、equals 和 hashcode 方法。
@Getter / @Setter:
- 分别用于生成所有的 getter 和 setter 方法。
- 可以作用于整个类,也可以作用于特定的字段。
@NoArgsConstructor:
- 生成一个无参构造方法。
@AllArgsConstructor:
- 生成一个包含所有实例变量的构造器。
@RequiredArgsConstructor:
- 生成包含所有被
final修饰符修饰的实例变量的构造方法。被final修饰的变量必须在构造方法执行前手动附上值0 - 如果没有
final的0实例变量,则自动生成无参数构造方法。
@ToString / @EqualsAndHashCode:
- 用于生成 toString 和 equals/hashCode 方法。
- 这两个注解都有
exclude属性,通过这个属性可以定制toString、hashCode、equals方法,也就是不包含的意思
注:Lombok只能帮助我们生成无参数构造方法和全参数构造方法,其他定制参数的构造方法无法生成。
如何使用 Lombok?
创建一个普通的Maven模块来快速测试一下Lombok库的使用:

添加最新依赖
在 Java 类中使用 Lombok 提供的注解。
1 |
|
编写测试程序:
1 | public class Test { |
Lombok的其他常用注解
@Value
该注解会给所有属性添加final,给所有属性提供getter方法,自动生成toString、hashCode、equals
通过这个注解可以创建不可变对象。
1 |
|
测试程序:
1 | public class CustomerTest { |
可以查看一下字节码,你会发现,@Value注解的作用只会生成:全参数构造方法、getter方法、hashCode、equals、toString方法。(没有setter方法。)
@Builder
GoF23种设计模式之一:建造模式
建造模式(Builder Pattern)属于创建型设计模式。GoF23种设计模式之一。
用于解决对象创建时参数过多的问题。它通过将对象的构造过程与其表示分离,使得构造过程可以逐步完成,而不是一次性提供所有参数。建造模式的主要目的是让对象的创建过程更加清晰、灵活和可控。
简而言之,建造模式用于:
- 简化构造过程:通过逐步构造对象,避免构造函数参数过多。
- 提高可读性和可维护性:让构造过程更加清晰和有序。
- 增强灵活性:允许按需配置对象的不同部分。
这样可以更方便地创建复杂对象,并且使得代码更加易于理解和维护。
建造模式的代码
1 | // 建造模式。23种设计模式之一。GoF之一。 |
1 | public class Test { |
使用@Builder注解自动生成建造模式的代码
该注解可以直接帮助我们生成以上的代码。使用@Builder注解改造以上代码。
1 |
|
1 | public class Test { |
@Singular
@Singular注解是辅助@Builder注解的。
当被建造的对象的属性是一个集合,这个集合属性使用@Singular注解进行标注的话,可以连续调用集合属性对应的方法完成多个元素的添加。如果没有这个注解,则无法连续调用方法完成多个元素的添加。代码如下:
1 |
|
1 | public class Test { |
@Slf4j
Lombok 支持多种日志框架的注解,可以根据你使用的日志框架选择合适的注解。以下是 Lombok 提供的**部分日志注解**及其对应的日志框架:
@Log4j:- 自动生成一个
org.apache.log4j.Logger对象。 - 适用于 Apache Log4j 1.x 版本。
- 自动生成一个
@Slf4j:- 自动生成一个
org.slf4j.Logger对象。 - 适用于 SLF4J(Simple Logging Facade for Java),这是一种日志门面,可以与多种实际的日志框架(如 Logback、Log4j 等)集成。
- 自动生成一个
@Log4j2:- 自动生成一个
org.apache.logging.log4j.Logger对象。 - 适用于 Apache Log4j 2.x 版本。
- 自动生成一个
使用示例
假设我们有一个类 UserService,并且我们想要使用 SLF4J 作为日志框架,我们可以这样使用 @Slf4j 注解:
1 |
|
1 | public class UserServiceTest { |
在这个例子中,log 是一个静态成员变量,表示一个 org.slf4j.Logger 对象。Lombok 自动生成了这个日志对象,并且你可以直接使用它来进行日志记录。
选择合适的注解
选择哪个注解取决于你使用的日志框架。例如:
- 如果你使用的是 SLF4J,可以选择
@Slf4j。 - 如果你使用的是 Log4j 1.x,可以选择
@Log4j。 - 如果你使用的是 Log4j 2.x,可以选择
@Log4j2。
注意事项
确保在使用这些注解之前,已经在项目中引入了相应的日志框架依赖。例如,如果你使用 SLF4J,你需要在项目中添加 SLF4J 的依赖,以及一个具体的日志实现(如 Logback)。对于其他日志框架,也需要相应地添加依赖。
示例依赖
如果你使用 Maven 项目,并且选择了 SLF4J + Logback 的组合,可以添加以下依赖:
1 | <!--Slf4j日志规范--> |
MyBatis逆向生成
MyBatis逆向工程:使用IDEA插件可以根据数据库表的设计逆向生成MyBatis的Mapper接口 与 MapperXML文件。
安装插件free mybatis tools

在IDEA中配置数据源数据库
然后在里面创建好数据


使用脚手架创建SpringBoot项目
添加依赖:mybatis依赖、mysql驱动、Lombok库

生成MyBatis代码放到SpringBoot项目中
在表上右键:Mybatis-Generator


代码生成后,如果在IDEA中看不到,这样做(重新从硬盘加载):

注意:生成的VipMapper接口上自动添加了@Repository注解,这个注解没用,删除即可。
编写mybatis相关配置
application.properties属性文件的配置:
1 | spring.application.name=springboot3-13-mybatis-gennerator |
编写测试程序
1 | //做包扫描 |
1 |
|
整合SpringMVC(SSM整合)
Spring Boot项目本身就是基于Spring框架实现的。因此SSM整合时,只需要在整合MyBatis框架之后,引入web启动器即可完成SSM整合。
使用脚手架创建SpringBoot项目

添加依赖:web启动器、mybatis启动器、mysql驱动依赖、lombok依赖
使用free mybatis tool插件逆向生成MyBatis代码

整合MyBatis
编写数据源的配置
1 | # 数据源 |
编写mapper xml配置文件的位置
1 | # mybatis配置 |
在主入口类上添加@MapperScan注解
1 |
|
编写service
编写VipService接口:
1 | public interface VipService { |
编写VipServiceImpl实现类:
1 |
|
编写controller
编写VipController,代码如下:
1 |
|
提示:这里使用了RESTFul编程风格,这个内容在SpringMVC课程中已经讲过。忘了的同学可以回头观看一下。
启动服务器测试
执行SpringBoot项目主入口的main方法,启动Tomcat服务器:
打开浏览器访问:http://localhost:8080/detail?cn=1234567893
到此为止,SSM框架就集成完毕了,通过这个集成也可以感觉到SpringBoot简化了SSM三大框架的集成。
第4章 Spring Boot自动配置
自动配置概述
SpringBoot的两大核心
Spring Boot 框架的两大核心特性可以概括为“启动器”(Starter)和“自动配置”(Auto-configuration)。
- 启动器(Starter):
Spring Boot 提供了一系列的 Starter POMs,它们是一组预定义的依赖关系。
当你在项目中引入一个 Starter POM 时,它会自动包含所有必要的 Spring 组件以及合理的默认设置。开发者不需要手动管理复杂的依赖关系,也不需要担心版本冲突的问题,减少了配置上的出错可能。
- 自动配置(Auto-Configuration):
当添加了特定的 Starter POM 后,Spring Boot 会**根据类路径上存在的 jar 包来自动配置 Bean(自动配置相关组件)(比如:SpringBoot发现类路径上存在mybatis相关的类,例如SqlSessionFactory.class,那么SpringBoot将自动配置mybatis相关的所有Bean。)**。
如果开发者没有显式地提供任何与特定功能相关的配置,Spring Boot 将使用其默认配置来自动设置这些功能。当然,如果需要的话,用户也可以覆盖这些默认设置。
这两个特性结合在一起,使得使用 Spring Boot 开发应用程序变得更加简单快速,减少了大量的样板代码和重复配置的工作。让程序员专注业务逻辑的开发,在环境方面耗费最少的时间。
体会自动配置带来的便捷
拿SpringBoot集成MyBatis为例。
以前,在没有SpringBoot框架的时候,我们用Spring集成MyBatis框架,需要进行如下的配置:
1 |
|
通过以上的配置可以看到Spring集成MyBatis的时候,需要手动提供BasicDataSource、SqlSessionFactoryBean、MapperScannerConfigurer、DataSourceTransactionManager等Bean的配置。
使用了Spring Boot框架之后,这些配置都不需要提供了,SpringBoot框架的自动配置机制可以全部按照默认的方式自动化完成。减少了大量的配置,在环境方面耗费很少的时间,让程序员更加专注业务逻辑的处理。我们只需要在application.yml中提供以下的配置即可:
1 | spring: |
spring-boot-starter是springboot框架最核心的启动器,做springboot项目时,这个启动器是必须的,如果创建这个项目的时候没有选择任何启动器,这个时候springboot项目最小配置就必须将spring-boot-starter配置
1 | <!--springboot框架建议以继承父工程的方式引入springboot。--> |
引入web启动器都有哪些组件会准备好
通过以下代码获取spring ioc容器中的所有注册的bean,一个Bean就是一个组件:
1 |
|
在springboot没有引入任何启动器的情况下,默认提供了59bean
引入web启动器可以发现,ioc容器中注册的bean总数量为160个
也就是说,引入了web启动器后,ioc容器中增加了101个bean对象(加入了101个组件)。这101个bean对象都是为web开发而准备的,例如我们常见的:
- dispatcherServlet:DispatcherServlet 是 Spring MVC 的前端控制器,负责接收所有的 HTTP 请求,并将请求分发给适当的处理器(Controller)
- viewResolver:ViewResolver 是 Spring MVC 中用于将逻辑视图名称解析为实际视图对象的组件。它的主要作用是根据控制器返回的视图名称,找到对应的视图实现(如 JSP、Thymeleaf、Freemarker 等),并返回给 DispatcherServlet 用于渲染视图。
- characterEncodingFilter:字符集过滤器组件,专门处理字符集,解决请求和响应的乱码问题。
- mappingJackson2HttpMessageConverter:负责处理消息转换的组件。它可以将json字符串转换成java对象,也可以将java对象转换为json字符串。
- ……
每一个组件都有它特定的功能。
没有使用SpringBoot之前,以上的很多组件都是需要手动配置的。
默认的包扫描规则
之前我们已经说过并且测试过:springboot默认情况下只扫描主入口类所在包及子包下的类。
这是因为@SpringBootApplication注解被@ComponentScan标注,代替spring以前的这个配置:<context:component-scan base-packages="主入口类所在包"/>
当然,我们也可以打破这个规则,通过以下两种方式:
- 第一种:@SpringBootApplication(scanBasePackages = “com”)
- 第二种:@ComponentScan(“com”)
1 | //@SpringBootApplication里面集成了这三个注解,componentscan是负责包扫描的,指定这个包下所有的bean可以被加载 |
默认配置
springboot为功能的实现提供了非常多的默认配置.
例如:tomcat服务器端口号在没有配置的情况下,默认是8080
当然,也可以在application.properties文件中进行重新配置:
1 | server.port=8081 |
再如,配置thymeleaf的模板引擎时,默认的模板引擎前缀是classpath:/templates/,默认的后缀是.html
当然,也可以重新配置:
1 | spring.thymeleaf.prefix=classpath:/templates/ |
通过创建脚手架时引入wen启动器会自动创建static(放置静态资源js图片)和templates(放置thymeleaf模版引擎下的xxx.html)
这些配置最终都会通过@ConfigurationProperties(prefix="")注解绑定到对应的bean的属性上。这个Bean我们一般称为属性类。例如:
ServerProperties:服务器属性类,专门负责配置服务器相关信息。
1 |
|
ThymeleafProperties:Thymeleaf属性类,专门负责配置Thymeleaf模板引擎的。
1 |
|
SpringBoot官方文档当中也有指导,告诉你都有哪些属性类,告诉你在application.properties中都可以配置哪些东西。默认值都是什么:

自动配置是按需加载的
SpringBoot提供了非常多的自动配置类,有的是web相关的自动配置,有的是mail相关的自动配置。但是这些自动配置并不是全部生效,它是按需加载的。导入了哪个启动器,则该启动器对应的自动配置类才会被加载。
这些自动配置类在哪里?
任何启动器都会关联引入这样一个启动器:spring-boot-starter,它是springboot框架最核心的启动器。
spring-boot-starter又关联引入了spring-boot-autoconfigure。所有的自动配置类都在这里。


SpringBoot框架提供的条件注解
如何做到按需加载的,依靠SpringBoot框架中的条件注解来实现的。
Spring Boot框架中的@ConditionalOnXxx系列注解属于条件注解(Conditional Annotations),它们用于基于某些条件来决定是否应该创建一个或一组Bean。这些注解通常用在自动配置类上,以确保只有在特定条件满足时才会应用相应的配置。
这里是一些常见的@ConditionalOnXxx注解及其作用:
- @ConditionalOnClass:当指定的类存在时,才创建Bean。
- @ConditionalOnMissingClass:当指定的类不存在时,才创建Bean。
- @ConditionalOnBean:当容器中存在指定的Bean时,才创建Bean。
- @ConditionalOnMissingBean:当容器中不存在指定的Bean时,才创建Bean。
- @ConditionalOnProperty:当配置文件中存在指定的属性时,才创建Bean。也可以设置属性值需要匹配的值。
- @ConditionalOnResource:当指定的资源存在时,才创建Bean。
- @ConditionalOnWebApplication:当应用程序是Web应用时,才创建Bean。
- @ConditionalOnNotWebApplication:当应用程序不是Web应用时,才创建Bean。
使用这些注解可以帮助开发者根据不同的运行环境或配置来灵活地控制Bean的创建,从而实现更智能、更自动化的配置过程。这对于构建可插拔的模块化系统特别有用,因为可以根据实际需求选择性地启用或禁用某些功能。
假设我们来实现这样一个功能:如果IoC容器当中**存在ABean**,就创建B`Bean,代码如下:
1 |
|
1 | //@SpringBootApplication里面集成了这三个注解,componentscan是负责包扫描的,指定这个包下所有的bean可以被加载 |
如果IoC容器当中**不存在Bean**,就创建B`Bean,代码如下:
1 |
|
当类路径当中存在DispatcherServlet类,则启用配置,反之则不启用配置,代码如下:
1 | //当类路径中存在DispatcherServlet这个类时配置生效 |
以上程序自行测试!
自动配置实现原理
我们来深入的分析一个问题:为什么导入web启动器,web开发相关的自动配置就会生效?
在程序没有开始执行之前都导入了哪些依赖
在程序没有开始运行之前,我们先来分析一下,当导入web启动器之后,底层都一连串的导入了哪些依赖!
- 从这里开始:导入了
spring-boot-starter-web【web启动器】 - 然后关联导入了
spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat、spring-web、spring-webmvc- 注意:
spring-boot-starter是springboot核心启动器,任何启动器在导入时,都会关联导入springboot核心启动器。
- 注意:
- 核心启动器导入之后,关联导入了一个jar包:
spring-boot-autoconfigure。- 注意:这个jar包中存放的是springboot框架**官方支持的自动配置类**。如下图:

- 官方支持的自动配置类有多少个呢,可以通过下图位置查看:


得知springboot3.3.5这个版本共152个自动配置类。自动配置类的命名规则是XxxxAutoConfiguration。
提示:哪个自动配置类生效,就代表哪个配置文件生效,那么对应的技术就完成了整合,就可以进行对应技术的开发。
从main方法开始执行之后都发生了什么
以上分析的是在项目结构上已经完成了相关依赖的导入,这些自动配置了导入到了项目当中,那么在运行时哪些自动配置类会被加载?哪些自动配置类会生效呢?我们接下来进行程序运行阶段的分析:
程序从main方法进入执行,主入口类上使用
@SpringBootApplication进行了标注。@SpringBootApplication注解是复合注解,代表以下三个注解的功能:@SpringBootConfiguration:它被@Configuration标注,说明主入口类就是一个配置类,此时该配置开始加载。@ComponentScan:默认扫描的是主入口所在包以及子包。因此spring-boot-autoconfigure包是扫描不到的,按说XxxAutoConfiguration自动配置类是无法加载的!!!那么这些自动配置类又是如何加载和生效的呢?@EnableAutoConfiguration:自动配置类的加载和生效全靠它了。该注解被翻译为:启用自动配置。如果后面加上(excludeName= {“A”, “B”}),就会排除这些不去自动配置
@EnableAutoConfiguration被@Import(AutoConfigurationImportSelector.class)标注@Import(AutoConfigurationImportSelector.class)的作用是:将AutoConfigurationImportSelector作为一个Bean加载到IoC容器中。- 这个Bean的作用是:负责收集和选择所有符合条件的自动配置类。
添加断点,跟踪
AutoConfigurationImportSelector源码:
通过跟踪得知,这
152个自动配置类的类名都会被加载到IoC容器中。注意:加载了152,并不是152个全部生效。如果给
这
152个自动配置类底层是怎么查找的?点击这里


这里的load返回一个list集合,然后这个方法把这个集合return,点进去load方法

这里可以看到后面是一个class类,也就是上面的AutoConfiguration.class
通过以上源码跟踪,得知,是从下图位置加载的:

最先获取到
152个,经过上图的一层一层的过滤(条件注解),最终筛选了26个自动配置类,为什么这么少,因为你只引入了web starter。这26个配置就是做web开发需要的最少配置
具体怎么排除的,请看以下解释:
- configurations = removeDuplicates(configurations);
去重:移除 configurations 列表中的重复项,确保每个配置类只出现一次。
- Set
exclusions = getExclusions(annotationMetadata, attributes);
获取排除列表:从注解元数据和属性中获取需要排除的配置类名称集合。因为@EnableAutoConfiguration注解还能这么用:@EnableAutoConfiguration(exclude = {排除列表}, excludeName = {排除列表})
- checkExcludedClasses(configurations, exclusions);
检查排除:验证 configurations 中是否有被排除的类,如果有,可能会抛出异常或记录警告。
- configurations.removeAll(exclusions);
移除排除项:从 configurations 列表中移除所有在 exclusions 集合中的配置类。
- configurations = getConfigurationClassFilter().filter(configurations);
过滤配置类:使用 ConfigurationClassFilter 对 configurations 进行进一步过滤。这一行通过条件注解进行判断,例如 @ConditionalOnClass、@ConditionalOnMissingBean 等。
- fireAutoConfigurationImportEvents(configurations, exclusions);
触发事件:触发自动配置导入事件,通知其他组件或监听器关于最终确定的配置类和排除的类。
自动配置类都干了啥
自动配置类导入了一堆相关的组件(一个组件一个功能),而每个组件获取配置时都是从属性类中获取,而属性类恰好又和配置文件绑定。
以DispatcherServletAutoConfiguration自动配置类为例,这个自动配置类主要是配置了SpringMVC中的前端控制器。
请看源码:


通过以上源码得知,DispatcherServletConfiguration组件的配置信息来源于WebMvcProperties属性类。WebMvcProperties类源码如下:

通过以上源码又得知,要对DispatcherServletConfiguration进行配置的话,应该在application.properties中使用这样的前缀配置:spring.mvc....

再来看嵌入式Web服务器工厂自定义程序自动配置:EmbeddedWebServerFactoryCustomizerAutoConfiguration,通俗讲:通过它可以配置web服务器。
请看源码:


只要加了@EnableConfigurationProperties()就会在ioc容器中创建serverProperties对象,这个bean就有了,然后把application.Properties的配置信息绑定到serverProperties对象,在application文件中有很多配置,以什么前缀的配置绑定这个对象属性上呢?

就是以server开头的,比如server.port=8081,8081就会赋给port
通过以上源码得知,这个自动配置类中也有很多组件,有tomcat组件,有jetty组件。单独看Tomcat,要配置Tomcat服务器,需要参照ServerProperties属性类,打开源码看看:

因此配置Tomcat服务器需要在application.properties文件中使用这样的前缀配置:server.
总结自动配置原理
- 运行环境准备阶段
- 引入web启动器
- 最终传递引入了自动配置的jar包
- 自动配置的jar包中有152个自动配置类,到此运行环境准备完毕。
- 运行阶段
- @EnableAutoConfiguration 启用自动配置,将152个自动配置类全部加载到IoC容器中,然后根据开发场景筛选出必须的自动配置类。
- 自动配置类加载了一堆组件。
- 每个组件需要的数据来自属性类。
- 属性类又和配置文件绑定在一起。
- 因此,最终一句话:导入启动器,修改配置文件,就可以完成对应功能的开发。
第5章 Spring Boot的web开发
SpringBoot的web自动配置
http请求协议:browser—>Server,http相应协议Server—>browser
新建项目sb3-09-web:添加web启动器,添加Lombok依赖。

web自动配置的依赖是如何传递的(这一部分视频没讲解,随便看看)
- 首先引入了
web启动器,如下:
1 | <dependency> |
web启动器传递引入了spring-boot-starter,如下:
1 | <dependency> |

spring-boot-starter会传递引入一个spring-boot-autoconfigure包,如下:
1 | <dependency> |


- 在
spring-boot-autoconfigure包中的.imports文件中罗列的需要导入的自动配置类,如下图:


web自动配置的实现原理
- 从入口程序开始:
1 | package com.powernode.sb309web; |

入口程序被@SpringBootApplication注解标注。
@SpringBootApplication注解被@EnableAutoConfiguration注解标注。表示启用自动配置。@EnableAutoConfiguration注解被@Import({AutoConfigurationImportSelector.class})注解标注。- 因此
AutoConfigurationImportSelector决定哪些自动配置类是需要导入的。 <font style="color:#080808;background-color:#ffffff;">AutoConfigurationImportSelector</font>底层实现步骤具体如下:





最终找的文件是:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
注意:任何jar包,包括第三方的依赖,自动配置类所在的路径以及文件名都是完全相同的,都是**META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports**
例如mybatis的自动配置类的列表文件也是这样,如下图:


通过web自动配置类逆推web配置的prefix
在自动配置列表中找到web自动配置相关的类:


以下就是web自动配置类列表:
1 | org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration |

通过web自动配置类的源码可以逆推web配置的prefix:
- WebMvcAutoConfiguration




- MultipartAutoConfiguration



- HttpEncodingAutoConfiguration



- ErrorMvcAutoConfiguration
- ServletWebServerFactoryAutoConfiguration
- DispatcherServletAutoConfiguration
- EmbeddedWebServerFactoryCustomizerAutoConfiguration
- RestTemplateAutoConfiguration
通过查看源码,得知,web开发时,在application.properties配置文件中可以配置的前缀是:
1 | # SpringMVC相关配置 |
Web自动配置都默认配置了什么
查看官方文档:

翻译如下:
Spring Boot 为 Spring MVC 提供了自动配置,这在大多数应用程序中都能很好地工作。除了已经实现了 Spring MVC 的默认功能外,自动配置还提供了以下特性:
- 包括
ContentNegotiatingViewResolver和BeanNameViewResolver的 Bean。ContentNegotiatingViewResolver自动根据HTTP请求头中Accept字段来选择合适的视图技术渲染响应。<font style="color:rgb(44, 44, 54);">BeanNameViewResolver</font>的作用是根据视图名称找到视图View对象。
- 支持提供静态资源,包括对 WebJars的支持。
- 静态资源路径默认已经配置好了。默认会去static目录下找。
- 自动注册
Converter、GenericConverter和Formatter的 Bean。Converter:转换器,做类型转换的,例如表单提交了用户数据,将表单数据转换成User对象。Formatter:格式化器,做数据格式化的,例如将Java中的日期类型对象格式化为特定格式的日期字符串。或者将用户提交的日期字符串,转换为Java中的日期对象。
- 支持
HttpMessageConverters。- 内置了很多的HTTP消息转换器。例如:
MappingJackson2HttpMessageConverter可以将json转换成java对象,也可以将java对象转换为json字符串。
- 内置了很多的HTTP消息转换器。例如:
- 自动注册
MessageCodesResolver。- SpringBoot会自动注册一个默认的
消息代码解析器 - 帮助你在表单验证出错时生成一些特殊的代码。这些代码让你能够更精确地定位问题,并提供更友好的错误提示。
- SpringBoot会自动注册一个默认的
- 静态
index.html文件支持。- Spring Boot 会自动处理位于项目静态资源目录下的 index.html 文件,使其成为应用程序的默认主页
- 自动使用
ConfigurableWebBindingInitializerBean。- 用它来指定默认使用哪个转换器,默认使用哪个格式化器。在这个类当中都已经配好了。
如果您不想使用自动配置并希望完全控制 Spring MVC,可以添加您自己的带有 **<font style="color:#DF2A3F;">@EnableWebMvc</font>** 注解的 @Configuration。
如果您希望保留这些 Spring Boot MVC 定制化设置并进行更多的 MVC 定制化(如拦截器、格式化程序、视图控制器等其他功能),可以添加您自己的类型为 WebMvcConfigurer 的 @Configuration 类。但不能使用@EnableWebMvc注解。
WebMvcAutoConfiguration原理
通过源码分析的方式,学习WebMvc的自动配置原理。
WebMvc自动配置是否生效的条件
1 |
|
- @AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })
- WebMvcAutoConfiguration自动配置类加载顺序在以上自动配置类加载后加载。
- @ConditionalOnWebApplication(type = Type.SERVLET)
- WebMvcAutoConfiguration自动配置类只在servlet环境中生效。
- @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
- 类路径中必须存在
Servlet.class``DispatcherServlet.class``WebMvcConfigurer.class,WebMvcAutoConfiguration自动配置类才会生效。
- 类路径中必须存在
- @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
- 类路径中不存在
WebMvcConfigurationSupport.class时WebMvcAutoConfiguration自动配置类才会生效。 - 注意:当使用@EnableWebMvc注解后,类路径中就会注册一个WebMvcConfigurationSupport这样的bean。
- 类路径中不存在
- @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) 不重要
- 指定WebMvcAutoConfiguration自动配置类的加载顺序
- @ImportRuntimeHints(WebResourcesRuntimeHints.class) 不重要
- 运行时引入WebResourcesRuntimeHints这个类,这个类的作用是给JVM或者其他组件提示信息的,提示一下系统应该如何处理类和资源。
总结来说,WebMvcAutoConfiguration类将在以下条件下生效:
- 应用程序是一个Servlet类型的Web应用;
- 环境中有Servlet、DispatcherServlet和WebMvcConfigurer类;
- 容器中没有WebMvcConfigurationSupport的bean。
如果这些条件都满足的话,那么这个自动配置类就会被激活,并进行相应的自动配置工作。
WebMvc自动配置生效后引入了两个Filter Bean
引入了HiddenHttpMethodFilter Bean
1 |
|
这个过滤器是专门处理Rest请求的。GET POST PUT DELETE请求。
引入了FormContentFilter Bean
1 |
|
OrderedFormContentFilter 是 Spring Boot 中用于处理 HTTP 请求的一个过滤器,特别是针对 PUT 和 DELETE 请求。这个过滤器的主要作用是在处理 PUT 和 DELETE 请求时,确保如果请求体中有表单格式的数据,这些数据会被正确解析并可用。
比如get请求是在请求行上提交数据,post请求正常在请求体中提交数据,put和delete如果请求体当中有form表单数据提交
WebMvc自动配置生效后引入了WebMvcConfigurer接口的实现类
在SpringBoot框架的WebMvcAutoConfiguration类中提供了一个内部类:WebMvcAutoConfigurationAdapter

SpringBoot在这个类WebMvcAutoConfigurationAdapter中进行了一系列的Spring MVC相关配置。
我们开发中要对Spring MVC的相关配置进行修改,可以编写一个类继承WebMvcAutoConfigurationAdatper,然后重写对应的方法即可。
因此,通过对WebMvcAutoConfigurationAdapter</font>类中的方法进行重写来修改Web MVC的默认配置。

关于WebMvcConfigurer接口
这个接口不是SpringBoot框架提供的,是Spring MVC提供的,在Spring框架4.3版本中引入的。这个接口的作用主要是允许开发者通过实现这个接口来定制Spring MVC的行为。
在这个接口中提供了很多方法,需要改变Spring MVC的哪个行为,则重写对应的方法即可,下面是这个接口中所有的方法,以及每个方法对应的Spring MVC行为的解释:
1 | public interface WebMvcConfigurer { |

WebMvcConfigurer接口的实现类WebMvcAutoConfigurationAdapter
WebMvcAutoConfigurationAdapter是Spring Boot框架提供的,实现了Spring MVC中的WebMvcConfigurer接口,对Spring MVC的所有行为进行了默认的配置。
如果想要改变这些默认配置,应该怎么办呢?看源码:

可以看到,该类上有一个注解@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class }),该注解负责启用配置属性。会将配置文件application.properties或application.yml中的配置传递到该类中。因此可以通过application.properties或application.yml配置文件来改变Spring Boot对SpringMVC的默认配置。WebMvcProperties和WebProperties源码如下:


通过以上源码得知要改变SpringBoot对SpringMVC的默认配置,需要在配置文件中使用以下前缀的配置:
- spring.mvc:主要用于配置 Spring MVC 的相关行为,例如路径匹配、视图解析、静态资源处理等
- spring.web:通常用于配置一些通用的 Web 层设置,如资源处理、安全性配置等。
自动配置中的静态资源处理
web站点中的静态资源指的是:js、css、图片等。
静态资源处理源码分析
关于SpringBoot对静态资源处理的默认配置,查看WebMvcAutoConfigurationAdapter源码,核心源码如下:

对以上源码进行解释:
1 |
|
1 | # 让springboot的静态资源处理失效 |
关于WebJars静态资源处理
默认规则是:当请求路径是/webjars/**,则会去classpath:/META-INF/resources/webjars/找。前面的路径可以更改,后面的是固定的无法更改
WebJars介绍
WebJars 是一种将常用的前端库(如 jQuery、Bootstrap、Font Awesome 等)打包成 JAR 文件的形式,方便在 Java 应用程序中使用。WebJars 提供了一种标准化的方式来管理前端库,使其更容易集成到 Java 项目中,并且可以利用 Maven 的依赖管理功能。
WebJars在SpringBoot中的使用
WebJars官网:https://www.webjars.org/


在官网上可以找到某个webjars的maven依赖,将依赖加入到SpringBoot项目中,例如我们添加vue的依赖:
1 | <!--webjars:将前端库打成jar包,方便在java项目中引入,也可以使用maven进行依赖管理。--> |
如下图表示加入成功:

在jar包列表中也可以看到:


在SpringBoot中,对WebJars的默认访问规则是:当请求路径是/webjars/**,则会去classpath:/META-INF/resources/webjars/找。
因此我们要想访问上图的index.js,则应该发送这样的请求路径:http://localhost:8080/webjars/vue/3.5.12/index.js
启动服务器,打开浏览器,访问,测试结果如下:


和IDEA中的文件对比一下,完全一样则表示测试成功:


关于普通静态资源处理
SpringBoot对普通静态资源处理的规则是:
当请求路径是http://localhost:8080/**,根据控制器方法优先原则,会先去找合适的控制器方法,如果没有合适的控制器方法,静态资源处理才会生效,则自动去类路径下的以下4个位置查找:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
我们可以在项目中分别创建以上4个目录,在4个目录当中放入静态资源,例如4张图片:


然后启动服务器,打开浏览器,访问,测试是否可以正常访问图片:

关于静态资源缓存处理
不管是webjars的静态资源还是普通静态资源,统一都会执行以下这个方法,这个方法最后几行代码就是关于静态资源的缓存处理方式。

什么是静态资源缓存,谁缓存,有什么用?
静态资源缓存指的是浏览器的缓存行为,浏览器可以将静态资源(js、css、图片、声音、视频)缓存到浏览器中,只要下一次用户访问同样的静态资源直接从缓存中取,不再从服务器中获取,可以降低服务器的压力,提高用户的体验。而这个缓存策略可以在服务器端程序中进行设置,SpringBoot对静态资源缓存的默认策略就是以下这三行代码:

以上三行代码的解释如下:
- registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
- 设置缓存的过期时间(如果没有指定单位,默认单位是秒)
- 浏览器会根据响应头中的缓存控制信息决定是否从本地缓存中加载资源,而不是每次都从服务器重新请求。这有助于减少网络流量和提高页面加载速度。
- 假设你配置了静态资源缓存过期时间为 1 小时(3600 秒),那么浏览器在首次请求某个静态资源后,会在接下来的一小时内从本地缓存加载该资源,而不是重新请求服务器。
- 可以通过
application.properties的来修改默认的过期时间,例如:spring.web.resources.cache.period=3600或者spring.web.resources.cache.period=1h
- registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
- 设置静态资源的 Cache-Control HTTP 响应头,告诉浏览器如何去缓存这些资源。
Cache-ControlHTTP 响应头 是HTTP响应协议的一部分内容。如下图响应协议的响应头信息中即可看到Cache-Control的字样:

常见的 Cache-Control 指令包括:
* max-age=<seconds>:表示响应在多少秒内有效。
* public:表示响应可以被任何缓存机制(如代理服务器)缓存。
* private:表示响应只能被用户的浏览器缓存
* no-cache:表示在使用缓存的资源之前必须重新发送一次请求进行验证。
* no-store:表示不缓存任何响应的资源。
- 例如:max-age=3600, public:表示响应在 3600 秒内有效,并且可以被任何缓存机制缓存。
- 可以通过`spring.web.resources.cache.cachecontrol.max-age=3600`以及`spring.web.resources.cache.cachecontrol.cache-public=true`进行重新配置。
- registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
- 设置静态资源在响应时,是否在响应头中添加资源的最后一次修改时间。SpringBoot默认配置的是:在响应头中添加响应资源的最后一次修改时间。
- 浏览器发送请求时,会将缓存中的资源的最后修改时间和服务器端资源的最后一次修改时间进行比对,如果没有变化,仍然从缓存中获取。
- 可以通过
spring.web.resources.cache.use-last-modified=false来进行重新配置。
静态资源缓存测试
根据之前源码分析,得知静态资源缓存相关的配置应该使用spring.web.resources.cache:





在application.properties文件中对缓存进行如下的配置:
1 | # 静态资源缓存设置 |
注意:cachecontrol.max-age配置的话,period会被覆盖。

启动服务器测试:看看是否在20秒内走缓存,20秒之后是不是就不走缓存了!!!
第一次访问:请求服务器

第二次访问:20秒内开启一个新的浏览器窗口,再次访问,发现走了缓存

第三次访问:20秒后开启一个新的浏览器窗口,再次访问,发现重新请求服务器

提示,为什么显示304,这是因为这个配置:spring.web.resources.cache.use-last-modified=true要去和最后一次修改作对比
web应用的欢迎页面
欢迎页测试
先说结论:只要在静态资源路径下提供index.html,默认被当做欢迎页面。静态资源路径指的是之前的4个路径:
1 | { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" } |
测试一下,在classpath:/static/目录下新建index.html页面:

启动服务器,测试结果如下:

如果同时在4个静态资源路径下都提供index.html,哪个页面会被当做欢迎页呢?

启动服务器,测试结果如下:

原因是什么呢?这是因为classpath:/META-INF/resources/是数组的首元素,因此先从这个路径下找欢迎页。

欢迎页源码分析
在WebMvcAutoConfiguration类中有一个内部类EnableWebMvcConfiguration,这个类中有这样一段代码:




通过以上源码追踪,得出结论:只要请求路径是/**的,会依次去{ "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }这四个位置找index.html页面作为欢迎页。
一个小小的疑惑
我们来看一下WebMvcAutoConfiguration的生效条件:

上图红框内表示,要求Spring容器中缺失WebMvcConfigurationSupport这个Bean,WebMvcAutoConfiguration才会生效。

但是我们来看一下EnableWebMvcConfiguration的继承结构:


很明显,EnableWebMvcConfiguration就是一个WebMvcConfigurationSupport这样的Bean。
那疑问就有了:既然容器中存在WebMvcConfigurationSupport这样的Bean,WebMvcAutoConfiguration为什么还会生效呢?
原因是因为:EnableWebMvcConfiguration是WebMvcAutoConfiguration类的内部类。在WebMvcAutoConfiguration进行加载的时候,EnableWebMvcConfiguration这个内部类还没有加载。因此这个时候在容器中还不存在WebMvcConfigurationSupport的Bean,所以WebMvcAutoConfiguration仍然会生效。
以上所说的WebMvcAutoConfiguration类中的内部类EnableWebMvcConfiguration,是用来启用Web MVC默认配置的。
注意区分:WebMvcAutoConfiguration的两个内部类:
WebMvcAutoConfigurationAdapter作用是用来:修改配置的EnableWebMvcConfiguration作用是用来:启用配置的
favorite icon(小图标)
favicon(也称为“收藏夹图标”或“网站图标”)是大多数现代网页浏览器的默认行为之一。当用户访问一个网站时,浏览器通常会尝试从该网站的根目录下载名为 favicon.ico 的文件,并将其用作标签页的图标。
如果网站没有提供 favicon.ico 文件,浏览器可能会显示一个默认图标,或者根本不显示任何图标。为了确保良好的用户体验,网站开发者通常会在网站的根目录下放置一个 favicon.ico 文件。
与其他静态资源一样,Spring Boot 会在配置的静态内容位置检查是否存在 favicon.ico文件。如果存在这样的文件,它将自动作为应用程序的 favicon 使用。
以上官方说明的:将favicon.ico文件放到静态资源路径下即可。
web站点没有提供favicon.ico时:

我们在https://www.iconfont.cn/ (阿里巴巴提供的图标库)上随便找一个图标,然后将图片名字命名为favicon.ico,然后将其放到SpringBoot项目的静态资源路径下:

启动服务器测试:记住(ctrl + F5强行刷新一下,避免影响测试效果)

SpringBoot的web手动配置(静态资源处理)
如果你对SpringBoot默认的静态资源处理方式不满意。可以通过两种方式来改变这些默认的配置:
如果你对SpringBoot默认的静态资源处理方式不满意。可以通过两种方式来改变这些默认的配置:
- 第一种:配置文件方式
- 通过修改
application.properties或application.yml - 添加
spring.mvc和spring.web相关的配置。
- 通过修改



- 第二种:编写代码方式
- SpringMVC框架为我们提供了
WebMvcConfigurer接口,需要改变默认的行为,可以编写一个类实现WebMvcConfigurer接口,并对应重写接口中的方法即可改变默认的配置行为。
- SpringMVC框架为我们提供了
- 第一种:配置文件方式
配置文件方式
要修改访问静态资源URL的前缀,这样配置:
1 | # 让springboot的静态资源处理失效,这个不影响META-INF |
要修改静态资源的存放位置,这样配置:
1 | spring.web.resources.static-locations=classpath:/static1/,classpath:/static2/ |
进行以上配置之后:
- 访问webjars的请求路径应该是这样的:http://localhost:8080/wjs/….
- 访问普通静态资源的请求路径应该是这样的:http://localhost:8080/static/….
- 普通静态资源的存放位置也应该放到
classpath:/static1/,classpath:/static2/下面,其他位置无效。
访问webjars测试结果如下:

访问普通静态资源测试结果如下:


如果访问dog2.jpg,就无法访问了:

但是,存储在classpath:/META-INF/resources/目录下的dog1.jpg仍然是可以访问的:

因此,存储在classpath:/META-INF/resources/位置的静态资源会被默认加载,不受手动配置的影响。
编写代码方式
我们在前面提到过,想要定制Spring MVC的行为,也可以编写类实现Spring MVC框架提供的一个接口WebMvcConfigurer,想定制哪个行为就重写哪个方法即可。
编写的类只要纳入IoC容器的管理。因此有以下两种实现方式:
- 第一种:编写类实现
WebMvcConfigurer接口,重写对应的方法。 - 第二种:以组件的形式存在:编写一个方法,用
@Bean注解标注。
第一种方式
编写配置类,对于web开发来说,配置类一般起名为:WebConfig。配置类一般存放到config包下,因此在SpringBoot主入口程序同级目录下新建config包,在config包下新建WebConfig类

重写使用快捷键ctrl+o然后搜addResourceHandlers
1 | // 这里的这种配置:在springboot默认的自动配置基础之上进行扩展配置。也就是说springboot之前的配置仍然生效。 |
注意:将application.properties文件中之前的所有配置全部注释掉。让其恢复到最原始的默认配置。

启动服务器进行测试:


通过测试,我们的配置是生效的。
我们再来看看,默认的配置是否还生效?

我们可以看到,Spring Boot对Spring MVC的默认自动配置是生效的。
因此,以上的方式只是在Spring MVC默认行为之外扩展行为。
如果你不想再继续使用SpringBoot提供的默认行为,可以使用@EnableWebMvc进行标注。例如:
1 | // 添加这个注解之后,表示不在使用springboot的提供的默认的自动配置。 |
测试结果:

可以看到,默认配置已经不再生效。
再来看看,我们自己的配置是否仍然生效:

仍然生效。
第二种方式
采用@Bean注解提供一个WebMvcConfigurer组件,代码如下:
1 | import org.springframework.context.annotation.Bean; |
测试结果如下:

通过了测试,并且以上代码也是在原有配置基础上进行扩展。
如果要弃用默认配置,仍然使用 @EnableWebMvc注解进行标注。自行测试!
其他配置也这样做即可
以上对静态资源处理进行了手动配置,也可以做其他配置,例如拦截器:
1 | import jakarta.servlet.http.HttpServletRequest; |
启动服务器,打开浏览器,发送请求http://localhost:8080/static/dog5.jpg,后台执行结果如下:

这说明拦截器生效。
为什么只要容器中有WebMvcConfigurer组件即可呢
源码分析:
WebMvcAutoConfiguration部分源码:

WebMvcAutoConfiguration类的内部类EnableWebMvcConfiguration,这个类继承了DelegatingWebMvcConfiguration(Delegating是委派的意思。)
DelegatingWebMvcConfiguration中的setConfigurers()方法用来设置配置。而配置参数是一个List集合,这个List集合中存放的是WebMvcConfigurer接口的实例,并且可以看到这个方法上面使用了@Autowired进行了自动注入,这也就是说为什么只要是IoC容器中的组件就能生效的原因。
我们再次进入到this.configurers.addWebMvcConfigurers(configurers);方法中进一步查看源码:

对于WebMvcConfigurerComposite类的代码来说,它是一个非常典型的**<font style="color:#DF2A3F;">组合模式</font>**。
组合模式的关键点:
- 组合多个 WebMvcConfigurer 实例:WebMvcConfigurerComposite 通过 delegates 列表组合了多个 WebMvcConfigurer 实例。
- 统一接口:WebMvcConfigurerComposite 实现了 WebMvcConfigurer 接口,因此可以像一个单一的 WebMvcConfigurer 一样被使用。
- 代理调用:在实现 WebMvcConfigurer 接口的方法时,WebMvcConfigurerComposite 会遍历 delegates 列表,调用每个 WebMvcConfigurer 实例的相应方法。
总结:WebMvcConfigurerComposite 主要采用了组合模式的思想,将多个 WebMvcConfigurer 实例组合在一起,形成一个整体。
注意:组合模式是GoF 23种设计模式中的结构型设计模式。
web请求的路径匹配
我们在学习SpringMVC的时候,路径匹配规则中学习了Ant风格的路径匹配规则。大家可以翻看一下之前的Spring MVC视频。
在Spring Boot3中,对web请求的路径匹配提供了两种规则:
- 第一种:AntPathMatcher(Ant风格)【较旧】
- 第二种:PathPatternParser(从Spring5.3中引入的。在SpringBoot2.4中引入的。)【较新:效率高】
- 效率比Ant高,一般新项目中使用
SpringBoot3中默认使用的是PathPatternParser,不需要任何配置。如果要使用AntPathMatcher,就需要进行如下的配置:
1 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher |
AntPathMatcher
Ant风格的路径匹配规则回顾:
* 匹配任意长度的任意字符序列(不包括路径分隔符)。示例:/foo/*.html 匹配 /foo/bar.html 和 /foo/baz.html。
****** 匹配任意数量的目录层级。示例:/foo/** 匹配 /foo/bar、/foo/bar/baz 和 /foo/bar/baz/qux。
? 匹配任意单个字符**。示例:/foo?bar 匹配 /foobar 和 /fooxbar。
[] 匹配指定范围内的单个字符。示例:/foo[a-z]bar 匹配 /fooabar、/foobbar 等。
{} 路径变量,用于提取路径的一部分作为参数。示例:/users/{userId} 匹配 /users/123,提取 userId=123。

如果在SpringBoot3中启用Ant风格,记得配置:
1 | spring.mvc.pathmatch.matching-strategy=ant_path_matcher |
如下代码:请分析以下路径匹配的是什么样的路径。
1 |
|
启动服务器并测试路径:

PathPatternParser
项目中不做配置,或者按照以下方式配置,都是PathPatternParser:
1 | spring.mvc.pathmatch.matching-strategy=path_pattern_parser |
PathPatternParser风格是兼容Ant风格的。只有一个地方PathPatternParser不支持,Ant支持。在Ant风格中,**可以出现在任意位置。在PathPatternParser中只允许**出现在路径的末尾。
可以测试一下,将配置文件中的Ant风格注释掉,采用PathPatternParser风格。然后控制器代码如下:
1 | package com.powernode.springboot.controller; |
启动服务器报错:

提示你,如果在路径当中出现了**,需要将路径匹配规则替换为Ant风格。因此路径当中如果出现**,那么必须使用Ant风格。除此之外,PathPatternParser均可用。
我们再来测试一下,**放到末尾,对于PathPatternParser是否可用?
1 |
|
启动服务器测试,可用:

路径匹配相关源码
底层选择路径匹配规则的源码是:

内容协商
内容协商机制是Spring MVC框架提供的,接下来主要是学习在SpringBoot中是如何支持SpringMVC内容协商机制的。
对内容协商的理解
内容协商机制是指服务器根据客户端的请求来决定返回资源的最佳表示形式。
白话文描述:客户端要什么格式的数据,咱后端就应该返回什么格式的数据。
- 客户端要JSON,咱就响应JSON。
- 客户端要XML,咱就响应XML。
- 客户端要YAML,咱就响应YAML。
你可能会有疑问:客户端接收数据时统一采用一种格式,例如JSON,不就行了吗。哪那么多事儿呀!!!
但在实际的开发中,不是这样的,例如:
- 遗留的老客户端系统,仍然处理的是XML格式的数据。
- 要求处理速度快的这种客户端系统,一般要求返回JSON格式的数据。
- 要求安全性高的客户端系统,一般要求返回XML格式的数据。
因此,在现代的开发中,不同的客户端可能需要后端系统返回不同格式的数据。总之后端应该满足这种多样化的需求。
实现内容协商的两种方式
通常通过HTTP请求头(如 Accept)或请求参数(如 format)来指定客户端偏好接收的内容类型(如JSON、XML等)。服务器会根据这些信息选择最合适的格式进行响应。
通过HTTP请求头(如 Accept)
SpringBoot框架中,在程序员不做任何配置的情况下,优先考虑的是这种方式。
服务器会根据客户端发送请求时提交的请求头中的”Accept: application/json” 或 “Accept: application/xml” 或 “Accept: text/html”来决定响应什么格式的数据。
客户端发送请求给服务器的时候,如何设置请求头的Accept?有以下几种常见实现方式:
- 写代码
- fetch API
- ajax的XMLHttpRequest
- axios库
- jQuery库……
- 用工具
- 接口测试工具,例如:Postman、Apifox等。
- 命令行工具:curl
对于我们编写的以下Controller来说:
1 | // 相当于@Controller + @ResponseBody ,默认是将数据转换成json字符串进行响应。 |
我们使用了@RestController,也就是使用了@ResponseBody。因此默认支持的是返回JSON数据。怎么才能支持返回XML格式的数据呢?需要做以下两步:
第一步:引入一个依赖
1 |
|
第二步:在实体类上添加一个注解
1 |
|
然后是接口的实现:
1 | public interface UserService { |
1 |
|
遇到问题:实际参数列表和形式参数列表长度不同、java: 无法将类xxx中的构造器xxx应用到给定类型| lombok相关
idea运行maven项目时,报错这个(如标题)
解决方案记录:
找到了之前的、能运行成功不报错的 maven项目。参考其pom.xml文件中lombok相关部分,将<path>标签下的lombok加个版本号,就运行成功了:
1 | <path> |
接下来,我们使用curl命令行工具,来模拟发送请求,并在请求头中设置Accept:

可以很清楚的看到,服务器根据不同的请求头返回了不同格式的数据。
Accept: application/xml则返回XML格式的数据Accept: application/json则返回JSON格式的数据
通过请求参数(如 format)
接下来我们使用请求参数的方式,来测试一下服务器的响应,注意:默认的请求参数名为format。
我们仍然使用curl命令行工具进行测试:

我们可以看到,并没有达到我们想要的效果,这是因为SpringBoot优先考虑的不是通过请求参数format方式。如何优先考虑使用format方式呢?做如下配置:
1 | # 采用format方式实现内容协商,如果没有配置这个选项,默认采用的是Accept字段方式实现内容协商。 |
再次测试:

可以看到,现在SpringBoot已经优先考虑使用请求参数format方式了。
当然,请求参数的名字可以不使用format吗?支持定制化吗?答案是支持的,例如你希望请求参数的名字为type,可以做如下配置:
1 | # 内容协商时,设置请求参数的名字,默认为format |
再次使用curl工具进行测试:

HttpMessageConverter接口
HttpMessageConverter的理解
HttpMessageConverter接口被翻译为:Http消息转换器。它起到转换Http消息的作用。
什么是Http消息?所谓的Http消息本质上就是浏览器向服务器发送请求时提交的数据,或者服务器向浏览器响应的数据。
而HttpMessageConverter接口就是负责完成请求/响应时的数据格式转换的。
在Spring MVC中提供了很多HttpMessageConverter接口的实现类,不同的Http消息转换器具有不同的转换效果,有的负责将Java对象转换为JSON格式的字符串,有的负责将Java对象转换成XML格式的字符串。
常见的HttpMessageConverter
内置的常见的HttpMessageConverter的实现类包括:
- 【请求】提交的表单(form)数据转换成Java对象的主要任务是由 FormHttpMessageConverter 消息转换器完成的
- 【请求】提交的JSON数据转换成Java对象的主要任务是由 MappingJackson2HttpMessageConverter 消息转换器完成的。(我们通常使用的
<font style="color:#DF2A3F;">@RequestBody</font>注解) - 【响应】将Java对象转换成JSON格式的数据,并将其写入HTTP响应体的任务是由 MappingJackson2HttpMessageConverter 消息转换器完成。(我们通常使用的
@ResponseBody注解) - 【响应】将Java对象转换成XML格式的数据,并将其写入HTTP响应体的任务通常由 Jaxb2RootElementHttpMessageConverter 消息转换器完成。
- 【响应】将 String 直接写入到响应体的任务是由 StringHttpMessageConverter 消息转换器完成。
- ……
请求时通过哪些条件确定使用哪个转换器
请求时通常根据以下条件来确定使用哪个消息转换器:
- 请求的 Content-Type 字段:
Spring MVC 会检查请求的 Content-Type 字段,以确定请求体的数据格式(例如 application/json、application/x-www-form-urlencoded、application/xml 等)。
- 方法参数类型:
控制器方法中接收请求体的参数类型(例如 @RequestBody)。

响应时通过哪些条件确定使用哪个转换器
响应时通常根据以下条件来确定使用哪个消息转换器:
- 请求提交时,请求头上的Accept字段 :
Spring MVC 会检查客户端请求的 Accept 字段,以确定客户端期望的响应格式(例如 application/json、application/xml 等)。
- 方法返回值类型:
控制器方法的返回值类型(例如 @ResponseBody)。
例如1:@ResponseBody + 控制器方法的返回值是String,例如public String name(){},则使用StringHttpMessageConverter转换器。(将字符串直接写入响应体)
例如2:@ResponseBody + 控制器方法的返回值是User,例如public User name(){},则使用MappingJackson2HttpMessageConverter转换器。(将java对象转换成json格式的字符串写入到响应体)

系统默认提供了哪些HttpMessageConverter
查看源码:
WebMvcAutoConfiguration.EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
WebMvcAutoConfiguration内部类EnableWebMvcConfiguration
EnableWebMvcConfiguration继承了DelegatingWebMvcConfiguration
DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport
在WebMvcConfigurationSupport类中有这样一个方法:addDefaultHttpMessageConverters() 用来添加默认的HttpMessageConverter对象。
通过断点调试,可以发现默认支持6个HttpMessageConverter,如下:

这6个HttpMessageConverter作用如下:
- ByteArrayHttpMessageConverter:
用于将字节数组(byte[])与HTTP消息体之间进行转换。这通常用于处理二进制数据,如图片或文件。
- StringHttpMessageConverter:
用于将字符串(String)与HTTP消息体之间进行转换。它支持多种字符集编码,能够处理纯文本内容。
- ResourceHttpMessageConverter:
用于将Spring的Resource对象与HTTP消息体之间进行转换。Resource是Spring中表示资源的接口,可以读取文件等资源。这个转换器对于下载文件或发送静态资源有用。
- ResourceRegionHttpMessageConverter:
用于处理资源的部分内容(即“Range”请求),特别是当客户端请求大文件的一部分时。这对于实现视频流媒体等功能很有用。
- AllEncompassingFormHttpMessageConverter:
用于处理表单,是一个比较全面的form消息转换器。处理标准的application/x-www-form-urlencoded格式的数据,以及包含文件上传的multipart/form-data格式的数据。
- MappingJackson2HttpMessageConverter:
使用Jackson库来序列化和反序列化JSON数据。可以将Java对象转换为JSON格式的字符串,反之亦然。
另外,通过以下源码,也可以看到SpringBoot是根据类路径中是否存在某个类,而决定是否添加对应的消息转换器的:


因此,我们只要引入相关的依赖,让类路径存在某个类,则对应的消息转换器就会被加载。
定义自己的HttpMessageConverter
可以看到以上6个消息转换器中没有yaml相关的消息转换器,可见,如果要实现yaml格式的内容协商,yaml格式的消息转换器就需要我们自定义了。
第一步:引入能够处理yaml格式的依赖
任何一个能够处理yaml格式数据的库都可以,这里选择使用jackson的库,因为它既可以处理json,xml,又可以处理yaml。
1 | <!--这个依赖也是jackson家族提供的,可以将java对象转换成yaml格式的字符串。--> |
编写测试程序,简单测试一下这个库的用法:
1 | //这只是一个测试程序,测试jackson家族提供的将对象转换成yaml格式字符串的api |
执行结果如下:

第二步:新增一种媒体类型yaml
默认支持xml和json两种媒体类型,并没有支持yaml,如果要支持yaml格式的,需要新增一个yaml媒体类型,在springboot的配置文件中进行如下配置:
1 | # 新增一种媒体类型yaml |
注意,以上types后面的yaml是媒体类型的名字,名字随意,如果媒体类型起名为xyz,那么发送请求时的路径应该是这样的:http://localhost:8080/detail?format=xyz
第三步:自定义HttpMessageConverter
编写类YamlHttpMessageConverter继承AbstractHttpMessageConverter,代码如下:
1 | // 这是一个消息转换器,专门处理yaml格式数据的。 |
第四步:配置消息转换器
addefaultHttpjMessageConverters这个方法默认往整个容器当中添加httpmessage转换器,默认是加了六个转换器,现在往里面再配一个新的转换器,也就是配进去
重写WebMvcConfigurer接口的configureMessageCongnverters方法:
1 | //配置的意思 |
SpringBoot整合Thymeleaf
传统web应用和前后端分离
如果你是做前后端分离的项目,这一章节的内容将用不上。
现代开发大部分应用都会采用前后端分离的方式进行开发,前端是一个独立的系统,后端也是一个独立的系统,后端系统只给前端系统提供数据(JSON数据),不需要后端解析模板页面,前端系统拿到后端提供的数据之后,前端负责填充数据即可。因此这一章节内容作为了解。
传统的WEB应用(非前后端分离):浏览器页面上展示成什么效果,后端服务器说了算,这是传统web应用最大的特点。

前后端分离的应用:前端是一个独立的系统,后端也是一个独立的系统,后端系统不再负责页面的渲染,后端系统只负责给前端系统提供开放的API接口,后端系统只负责数据的收集,然后将数据以JSON/XML等格式响应给前端系统。前端系统拿到接口返回的数据后,将数据填充到页面上。

前后端分离的好处:
- 职责清晰:前端专注于用户界面和用户体验,后端专注于业务逻辑和数据处理。
- 开发效率高:前后端可以并行开发,互不影响,提高开发速度。
- 可维护性强:代码结构更清晰,便于维护和扩展。
- 技术栈灵活:前后端可以独立选择最适合的技术栈。
- 响应式设计:前端可以更好地处理不同设备和屏幕尺寸。
- 性能优化:前后端可以独立优化,提升整体性能。
- 易于测试:前后端接口明确,便于单元测试和集成测试。
SpringBoot整合Thymeleaf
Java的模板技术有很多,SpringBoot支持以下的模板技术:
- Thymeleaf:
- 特点:Thymeleaf 是一个现代的服务器端Java模板引擎,它支持HTML5,XML,TEXT,JAVASCRIPT,CSS等多种模板类型。它能够在浏览器中预览,这使得前端开发更加便捷。Thymeleaf 提供了一套强大的表达式语言,可以轻松地处理数据绑定、条件判断、循环等。
- 优势:与Spring框架集成良好,也是SpringBoot官方推荐的。
- FreeMarker:
- 特点:FreeMarker 是一个用Java编写的模板引擎,主要用来生成文本输出,如HTML网页、邮件、配置文件等。它不依赖于Servlet容器,可以在任何环境中运行。
- 优势:模板语法丰富,灵活性高,支持宏和函数定义,非常适合需要大量定制化的项目。
- Velocity:
- 特点:Velocity 是另一个强大的模板引擎,最初设计用于与Java一起工作,但也可以与其他技术结合使用。它提供了简洁的模板语言,易于学习和使用。
- 优势:轻量级,性能优秀,特别适合需要快速生成静态内容的应用。
- Mustache:
- 特点:Mustache 是一种逻辑无感知的模板语言,可以用于多种编程语言,包括Java。它的设计理念是让模板保持简单,避免模板中出现复杂的逻辑。
- 优势:逻辑无感知,确保模板的简洁性和可维护性,易于与前后端开发人员协作。
- Groovy Templates:
- 特点:Groovy 是一种基于JVM的动态语言,它可以作为模板引擎使用。Groovy Templates 提供了非常灵活的模板编写方式,可以直接嵌入Groovy代码。
- 优势:对于熟悉Groovy语言的开发者来说,使用起来非常方便,可以快速实现复杂逻辑。
这些模板技术各有千秋,选择哪一种取决于项目的具体需求和个人偏好。Spring Boot 对这些模板引擎都提供了良好的支持,通常只需要在项目中添加相应的依赖,然后按照官方文档配置即可开始使用。
提醒:SpringBoot内嵌了Servlet容器(例如:Tomcat、Jetty等),使用SpringBoot不太适合使用JSP模板技术,因为SpringBoot项目最终打成jar包之后,放在jar包中的jsp文件不能被Servlet容器解析。
要在SpringBoot中整合Thymeleaf,按照以下步骤操作:
第一步:引入thymeleaf启动器
1 | <dependency> |
第二步:编写配置文件,指定前缀和后缀(默认不配置就是以下配置)
这个是给视图解析器使用的,方法里会有个返回值用于返回逻辑视图名称,如果返回的是一个hello,这时后端的视图解析器就起作用,把下面的前缀加在hello的前面,后缀加后面,变成classpath:/templates/hello.html,但这个不是html文件而是thymeleaf模板文件,这个就成了物理视图名称。引入web启动器的时候会在resources下自动生成这个文件目录
1 | spring.thymeleaf.prefix=classpath:/templates/ |
第三步:编写控制器
1 | package com.powernode.springboot.controller; |
第四步:编写thymeleaf模板页面
1 |
|
启动服务器,测试地址为:http://localhost:8080/hello?name=jackson

Thymeleaf的自动配置
Thymeleaf的自动配置类:ThymeleafAutoConfiguration.java
@EnableConfigurationProperties这个注解可以把配置文件里的配置绑定到thymeleaf属性对象上,

我们通过查看上图中红框中的类,可以找到thymeleaf的相关配置:也就是以spring.thymeleaf前缀开头的配置信息绑定到属性类对象上

与thymeleaf相关的配置统一使用spring.thymeleaf即可。并且通过源码可以进一步了解到默认的前缀和后缀:

也就是说,默认情况下,只要放在classpath:/templates/目录下的xxx.html会被自动当做为thymeleaf的模板文件被thymeleaf模板引擎解析。因此放在classpath:/templates/目录下的html文件不是静态页面,而是动态的thymeleaf模板页面。
自定义的话修改配置文件
1 | spring.thymeleaf.prefix=classpath:/t/ |
然后创建对应的文件

这时之前的hello.html就失效了
Thymeleaf核心语法
th:text与th:utext 替换标签体内容
th:text与th:utext都是用来替换标签体内容的,例如:如果什么都不写的效果是
1 | <h1>hello,<span >这里是标签体</span></h1> |

注意:在根标签中引入 xmlns:th=”http://www.thymeleaf.org",在编写th:语法时有智能提示。
加上后就可以替换,运行效果为hello,jackson
1 | <h1>hello,<span th:text="${name}">这里是标签体</span></h1> |
测试结果:
提示:标签体中的内容即使是一段HTML代码,也只是会被当做普通文本对待。例如我们让存储在域中的文本内容是一段HTML代码:
1 |
|
1 | <div th:text="${htmlCode}">我是一个DIV</div> |
测试结果:
th:utext会将内容当做一段HTML代码解析并替换。将以上测试代码修改为:
1 | <div th:utext="${htmlCode}">我是一个DIV</div> |
测试结果:
th:任意属性名 动态替换该属性的值
分开设置:
1 | // 向域对象当中绑定公司名和公司地址 |
1 | <a th:href="${companyUrl}" href="https://www.baidu.com" th:text="${company}">百度</a> |
测试结果:由
也就是说th后面加了href就可以动态替换链接,加了text就可以替换文本
th:attr 属性合并设置
分开设置:
合并设置:使用th:attr
1 | // 向域对象中存储一个样式 |
1 | <a th:href="${companyUrl}" href="http://www.baidu.com" th:style="${style}" style="color:green" th:text="${company}">百度</a> |
测试结果:
th:指令
指令非常多,具有代表性的例如:th:if,该指令用来控制元素隐藏和显示。true就是显示,flase就是不显示
在static静态资源目录下存放一张图片:dog1.jpg
然后编写这样的模板代码:
1 | <!--默认会去static去找这个文件--> |
测试结果,图片是显示的:
如果th:if的值修改为false,我们会发现隐藏了。
也可以通过网址参数进行控制,在hellocontroller里添加代码
1 |
|
1 | <!--修改代码--> |
测试结果1:

测试结果2

thymeleaf也支持运算符
例如>运算符,我们实现这样一个功能,如果提供的用户名长度大于6,则显示狗狗图片:
1 | <!--名字长度大于6就为true--> |
测试结果1:

另外thymeleaf也支持三目运算符:
1 | // 向域对象当中存储一个性别 |
如果性别是true,则显示男,false,则显示女。
1 | <!--传进来的如果是true就是男,否则是女--> |
thymeleaf的字符串拼接
加单引号就是字符串,不加就是一个对象
第一种方式:使用加号 +,然后访问http://localhost:8080/hello?name=jackson&flag=1
1 | <!--strings.toUpperCase(name)是变大写--> |

第二种方式:使用竖线 ||
1 | <h1>hello,<span th:text="|姓名:${#strings.toUpperCase(name)}。|">这里是标签体</span> </h1> |

循环遍历
创建bean包,user类
1 | private String name; |
创建service包,Userservice类
1 | public interface UserService { |
再创建impl,userserviceimpl
1 |
|
再在controller包下新建UserController
1 |
|
然后由ai生成了js和css样式,这里就不再复制
在templates里新建一个list.html
说明:
- ${users}:代表集合
- user:代表集合中的每个元素
- ${user.name}:元素的name属性值
1 |
|
访问网址:http://localhost:8080/list

注意:以上[[${state.index}]]这种语法属于thymeleaf中的内联表达式写法。也可以写成:[(${state.index})]
另外,状态对象state的属性包括:
- index:下标
- count:序号
- current:当前对象
- size:元素总数
- even:是否为偶数行
- odd:是否为奇数行
- first:是否为第一个元素
- last:是否为最后一个元素
条件判断th:if
th:if 语法用来决定元素是否显示:true显示。false隐藏。
实现这样一个功能:用户如果没有留下简介,则显示你比较懒没有留下任何介绍信息,如果留下了简介,则显示具体的简介信息。
1 | <!-- 这两种写法都可以<td th:if="为空">你这个人很懒</td>,为空就很懒,不为空就显示简介--> |
条件判断th:switch
实现一个这样的功能:如果城市是beijing,就显示汉字北京,以此类推,其他值显示未知。
1 | <td th:switch="${user.location}"> |

thymeleaf属性优先级
thymeleaf的属性优先级非常重要,因为它直接决定了模板的解析和执行顺序。
以下是Thymeleaf属性的优先级从高到低的列表,以表格形式展示:
| 优先级 | 属性 | 描述 |
|---|---|---|
| 1 | th:if |
如果条件为真,则渲染该元素。 |
| 2 | th:unless |
如果条件为假,则渲染该元素。 |
| 3 | th:with |
定义局部变量。 |
| 4 | th:switch |
开始一个 switch 语句。 |
| 5 | th:case |
定义 switch 语句中的 case 分支。 |
| 6 | th:each |
遍历列表,用于循环。 |
| 7 | th:remove |
移除元素或其属性。 |
| 8 | th:attr |
设置或修改元素的属性。 |
| 9 | th:classappend |
追加 CSS 类。 |
| 10 | th:styleappend |
追加内联样式。 |
| 11 | th:src |
设置元素的 src 属性。 |
| 12 | th:href |
设置元素的 href 属性。 |
| 13 | th:value |
设置元素的 value 属性。 |
| 14 | th:text |
设置元素的文本内容。 |
| 15 | th:utext |
设置元素的未转义文本内容。 |
| 16 | th:html |
设置元素的 HTML 内容。 |
| 17 | th:fragment |
定义模板片段。 |
| 18 | th:insert |
插入一个模板片段。 |
| 19 | th:replace |
替换当前元素为一个模板片段。 |
| 20 | th:include |
包含一个模板片段的内容。 |
| 21 | th:block |
用于逻辑分组,不产生任何HTML输出。 |
对于thymeleaf属性优先级,我总结了以下一段话,把它记住即可:
“先控制,再遍历,后操作,末内容。”
具体来说:
- 先控制:
th:if和th:unless用于条件控制,决定是否渲染元素。 - 再遍历:
th:each用于遍历列表,生成多个元素。 - 后操作:
th:with、th:switch、th:case、th:remove、th:attr等用于局部变量定义、条件分支、属性操作等。 - 末内容:
th:text、th:utext、th:html等用于设置元素的内容。
*{…} 表达式
*{...} 主要用于在上下文中访问对象的属性。这种表达式通常在表单处理和对象绑定场景中使用。
语法:*{property}:访问当前**上下文**对象的某个属性。
使用场景
- 表单绑定:在表单中绑定对象的属性。
- 对象属性访问:在模板中访问对象的属性,特别是当对象是当前上下文的一部分时。
1 | <!--<tr th:each="user,state : ${users}">--> |
示例
- 表单绑定
假设你有一个 User 对象,包含 name 和 age 属性,你可以在表单中使用 *{...} 表达式来绑定这些属性:
1 | <form th:object="${user}" method="post" action="/submit"> |
在这个例子中:
th:object="${user}"将user对象设置为当前上下文对象。th:field="*{name}"和th:field="*{age}"分别绑定到user对象的name和age属性。
- 对象属性访问
假设你有一个 User 对象,包含 name 和 age 属性,你可以在模板中使用 *{...} 表达式来访问这些属性:
1 | <div th:object="${user}"> |
在这个例子中:
th:object="${user}"将user对象设置为当前上下文对象。*{name}和*{age}分别访问user对象的name和age属性。
**与 **${...} 的区别
${...}:标准表达式,用于访问模型中的变量和执行简单的表达式。*{...}:属性选择表达式,用于在上下文中访问对象的属性,通常与th:object一起使用。
代码片段共享
片段是Thymeleaf中用于代码复用的基本机制。你可以将共享的部分提取到单独的HTML文件中,然后在其他模板中引用这些片段。
页面中公共的header.html
1 | <!--th:fragment的作用是把这段代码起个名叫h,方面以后用--> |
页面中公共的footer.html
1 | <footer th:fragment="f"> |
在a.html中包含以上两个公共部分:
1 |
|
在b.html中包含以上两个公共部分:
1 |
|
然后在UserController里加上
1 | // 只编写一个控制器方法,不做任何业务逻辑,只是为了跳转视图。 |
效果图:
主要作用是代码复用。实现此功能的主要代码:
在公共代码部分使用
th:fragment="片段名称"来声明公共代码片段的名字。在需要引入的地方使用
th:replace="~{文件名去掉后缀 :: 片段名称}"来引入。
小插曲:在springboot中如何实现:直接将请求路径映射到特定的视图,而不需要编写controller?
以前是在springmvc配置文件中配置一个viewName对应的控制器,现在新建:

使用ViewControllerRegistry进行视图与控制器的注册
1 | // 基于springboot的自动配置扩展配置 |
thymeleaf页面修改如何立即生效
第一步:引入springboot提供的dev tools
1 | <dependency> |
第二步:关闭应用重启功能,如果不关闭会导致每一次修改java代码后立即重启应用,不建议。我们现在只希望做到的功能是,修改thymeleaf模板文件后立即生效。
1 | #关闭应用重启功能 |
第三步:修改代码后在IDEA中按组合键ctrl+f9
以上三步配合即可。
异常处理
在controller层如果程序出现了异常,并且这个异常未被捕获,springboot提供的异常处理机制将生效。
Spring Boot 提供异常处理机制主要是为了提高应用的健壮性和用户体验。它的好处包括:
- 统一错误响应:可以定义全局异常处理器来统一处理各种异常,确保返回给客户端的错误信息格式一致,便于前端解析。
- 提升用户体验:能够优雅地处理异常情况,避免直接将技术性错误信息暴露给用户,而是显示更加友好的提示信息。
- 简化代码:开发者不需要在每个可能抛出异常的方法中重复编写异常处理逻辑,减少冗余代码,使业务代码更加清晰简洁。
- 增强安全性:通过控制异常信息的输出,防止敏感信息泄露,增加系统的安全性。
自适应的错误处理机制
springboot会根据请求头的Accept字段来决定错误的响应格式。
这种机制的好处就是:客户端设备自适应,提高用户的体验。




SpringMVC的错误处理方案
重点:如果程序员使用了SpringMVC的错误处理方案,SpringBoot的错误处理方案不生效。
局部控制 @ExceptionHandler
在控制器当中编写一个方法,方法使用@ExceptionHandler注解进行标注,凡是这个控制器当中出现了对应的异常,则走这个方法来进行异常的处理。局部生效。
1 | //响应json,相当于下面两个注解 |
http://localhost:8080/resource/2:
http://localhost:8080/resource/1:这是springboot自带的异常

用mvc局部方式,接着添加:
1 | // springmvc中的异常处理方案:局部方式。 |

可以再编写一个OtherController,让它也发生IllegalArgumentException异常,看看它会不会走局部的错误处理机制。
1 |
|
http://localhost:8080/other/1,仅局部生效
全局控制 @ControllerAdvice + @ExceptionHandler
也可以把以上局部生效的方法单独放到一个类当中,这个类使用@ControllerAdvice注解标注,凡是任何控制器当中出现了对应的异常,则走这个方法来进行异常的处理。全局生效。
(弹幕里看到说有什么异常的话记得加上thymeleaf插件)
将之前的局部处理方案的代码注释掉。使用全局处理方式,编写以下类:
1 | // @ControllerAdvice + @ExceptionHandler 可以用来定义全局异常处理器。 |
SpringBoot的错误处理方案
重点:如果SpringMVC没有对应的处理方案,会开启SpringBoot默认的错误处理方案。
SpringBoot默认的错误处理方案如下:
- 如果客户端要的是json,则直接响应json格式的错误信息。
- 如果客户端要的是html页面,则按照下面方案:
第一步(精确错误码文件):去
classpath:/templates/error/目录下找404.html``500.html等精确错误码.html文件。如果找不到,则去静态资源目录下的/error目录下找。如果还是找不到,才会进入下一步。第二步(模糊错误码文件):去
classpath:/templates/error/目录下找4xx.html``5xx.html等模糊错误码.html文件。如果找不到,则去静态资源目录下的/error目录下找。如果还是找不到,才会进入下一步。第三步(通用错误页面):去找
classpath:/templates/error.html如果找不到则进入下一步。第四步(默认错误处理):如果上述所有步骤都未能找到合适的错误页面,Spring Boot 会使用内置的默认错误处理机制,即
/error端点。
比如随便输入一个没有任何html的文件网址,就会走第四步显示error错误
在文件下有这样的网页
优先去templates找,但如果把这个404改成404a,精确查找找不到了就会桉顺序去找static下的404,直到四个路径都找不到了再进行模糊错误码查找
如果以上都没有了,就会去这里找,这是一个通用的错误

如何在错误页获取错误信息
Spring Boot 默认会在模型Model中放置以下信息:
- timestamp: 错误发生的时间戳
- status: HTTP 状态码
- error: 错误类型(如 “Not Found”)
- exception: 异常类名
- message: 错误消息
- trace: 堆栈跟踪
在thymeleaf中使用 ${message}即可取出信息。
注意:**springboot3.3.5**版本默认只向Model对象中绑定了timestamp``status``error。如果要保存exception``message``trace,需要开启以下三个配置:
1 | server.error.include-stacktrace=always |
在error里写上代码:
1 |
|

配置后:

前后端分离项目的错误处理方案
统一使用SpringMVC的错误处理方案,定义全局的异常处理机制:@ControllerAdvice + @ExceptionHandler
返回json格式的错误信息,其它的就不需要管了,因为前端接收到错误信息怎么处理是他自己的事儿。
服务器端负责页面渲染的项目错误处理方案
建议使用SpringBoot的错误处理方案:
- 如果发生的异常是HTTP错误状态码:
- 建议常见的错误码给定
精确错误码.html - 建议不常见的错误码给定
模糊错误码.html
- 建议常见的错误码给定
- 如果发生的异常不是HTTP错误状态码,而是业务相关异常:
- 在程序中处理具体的业务异常,自己通过程序来决定跳转到哪个错误页面。
- 建议提供
classpath:/templates/error.html来处理通用错误。
国际化(了解)
在Spring Boot中实现国际化(i18n)(i到n之间有18个字母)是一个常见的需求,它允许应用程序根据用户的语言和地区偏好显示不同的文本。
实现国际化
第一步:创建资源文件
创建包含不同语言版本的消息文件。这些文件通常放在src/main/resources目录下,并且以.properties为扩展名。例如:
messages.properties(默认语言,如英语)messages_zh_CN.properties(简体中文)messages_fr.properties(法语)
注意这个zh_CN或者fr是固定的不能动,messages可以动
每个文件都应包含相同的消息键,但值应对应于相应的语言。例如:
messages.properties:
1 | welcome.message=Welcome to our application! |
messages_zh_CN.properties:
1 | welcome.message=欢迎来到我们的应用! |
messages_fr.properties:
1 | welcome.message=Bienvenue dans notre application ! |
修改好后需要在settings里找到file encodings把字符设置成utf-8
第二步:在模板文件中取出消息
语法格式为:#{welcome.message}井号是资源文件当中的key
1 |
|
要跳转到这个页面还需要写个控制器

1 |
|
http://localhost:8080/welcome
如果将浏览器默认语言环境修改为法文


国际化实现原理
做国际化的自动配置类是:MessageSourceAutoConfiguration

通过以上源码得知,国际化对应的配置前缀是:spring.message,只要是这个开头的都会绑定到MessageSourceProperties上,这个文件的默认值就是message,但也可以修改
例如在application.properties中进行如下配置:
1 | # 配置国际化文件命名的基础名称 |
注意:标准标识符:en_US 和 zh_CN 这样的标识符是固定的,不能更改。可以设置的是basename。
在程序当中如何获取国际化信息
也就是通过java程序获取properties里面后面的那个welcome.message的配置信息
在国际化自动配置类中可以看到这样一个Bean:MessageSource,它是专门用来处理国际化的。我们可以将它注入到我们的程序中,然后调用相关方法在程序中获取国际化信息。
1 | // 在java程序当中获取属性资源文件中的配置信息。 |
定制web容器
web服务器切换为jetty
pringboot默认嵌入的web服务器是Tomcat,如何切换到jetty服务器?
实现方式:排除Tomcat,添加Jetty依赖
切换前:
**修改 **pom.xml 文件:在 pom.xml 中,确保你使用 spring-boot-starter-web 并排除 Tomcat,然后添加 Jetty 依赖。
1 | <!-- 排除 Tomcat --> |
再次重启就变成这样:
web服务器切换原理
从哪里可以看出springboot是直接将tomcat服务器嵌入到应用中的呢?看这个类:ServletWebServerFactoryAutoConfiguration

以上代码显示嵌入的是3个服务器。但并不是都生效,我们来看一下生效条件:

生效条件是,看类路径当中是否有对应服务器相关的类,如果有则生效。spring-boot-web-starter这个web启动器引入的时候,大家都知道,它间接引入的是tomcat服务器的jar包。因此默认Tomcat服务器被嵌入。如果想要切换web服务器,将tomcat相关jar包排除掉,引入jetty的jar包之后,jetty服务器就会生效,这就是切换web服务器的原理。
web服务器优化
通过以下源码得知,web服务器的相关配置和ServerProperties有关系:

查看ServerProperties源码:

得知web服务器的配置都是以server开头的。
那么如果要配置tomcat服务器怎么办?要配置jetty服务器怎么办?请看一下源码


通过以上源码得知,如果要对tomcat服务器进行配置,前缀为:server.tomcat
如果要对jetty服务器进行配置,前缀为:server.jetty。
在以后的开发中关于tomcat服务器的常见优化配置有:
1 | # 这个参数决定了 Tomcat 在接收请求时,如果在指定的时间内没有收到完整的请求数据,将会关闭连接。这个超时时间是从客户端发送请求开始计算的。 |
第6章 SpringBoot实用技术整合
logo设置
关闭logo图标
就是这个东西
配置方式
1 | spring.main.banner-mode=off |
代码方式
第一种代码:
1 |
|
第二种代码:流式编程/链式编程
1 |
|
修改logo图标
在src/main/resources目录下存放一个banner.txt文件。文件名固定。
利用一些网站生成图标:
https://www.bootschool.net/ascii (支持中文、英文)
http://patorjk.com/software/taag/ (只支持英文)
https://www.degraeve.com/img2txt.php (只支持图片)
获取图标粘贴到banner.txt文件中运行程序即可。
PageHelper整合
官网地址:https://pagehelper.github.io/
引入依赖
1 | <dependency> |
编写代码
1 |
|
新建项目引入
然后用mybatis工程逆向生成,右击数据库的表选择
生成了以下这些文件:
然后把这些文件都重新写一下
Vipmapper.java:
1 | public interface VipMapper { |
VipMapper.xml:
1 |
|
application.properties
1 | spring.application.name=springboot3-23-ph |
然后主入口程序:
1 | //这样可以扫描到vipmapper |
包的路径复制可以使用以下操作:右击文件夹然后选择copypath


然后创建以下:
1 | public interface VipService { |
1 |
|
然后新建Controller包和VipController类,引入时可以设置每页显示的数量为一个常数,新建util包和Constant类
1 | /** |
1 |
|
然后访问http://localhost:8080/list/1
web层响应结果封装
web层其实就是Controller层,对于前后端分离的系统来说,为了降低沟通成本,我们有必要给前端系统开发人员返回统一格式的JSON数据。多数开发团队一般都会封装一个R对象来解决统一响应格式的问题。
封装R对象
在上面的代码继续新建result包,新建一个类R
1 | /** |
测试数据
再新建个bean的User
1 |
|
然后vipController添加
1 |
|
改进R对象
以上R对象存在的问题是,难以维护,项目中可能会出现很多这样的代码:R.FAIL(400, “修改失败”)。
引入枚举类型进行改进:创建enums包和codeEnum类
1 | // 专门维护code+msg的一个枚举类型 |
改进R:
1 | // 建造模式 |
修改VipController
1 |
|
事务管理
SpringBoot中的事务管理仍然使用的Spring框架中的事务管理机制,在代码实现上更为简单了。不需要手动配置事务管理器,SpringBoot自动配置完成了。我们只需要使用@Transactional注解标注需要控制事务的方法即可。另外事务的特性等仍然延用Spring框架。大家可以在老杜发布的Spring视频教程中详细学习事务管理机制。以下代码是在SpringBoot框架中进行的事务控制:
创建bean包account类
1 |
|
创建repository包AccountMapper类
1 | public interface AccountMapper { |
然后使用mybatis插件生成mapper文件
生成到resources的mapper文件
然后挨个生成查询语句

AccountMapper.xml:
1 |
|
入口:
1 | //扫描 |
配置文件:
1 | # 数据源 |
在service下新建AccountService
1 | public interface AccountService { |
实现接口:
1 |
|
新建自定义异常,在exception包下建TransferException类
1 | /** |
然后是控制层
1 |
|
然后再resources的templates里弄三个html,error index success
1 |
|
1 |
|
1 |
|
然后需要为index配置东西,建config包webconfig类
1 |
|
然后访问http://localhost:8080/index

SpringBoot打war包
第一步:将打包方式设置为war
1 | <packaging>war</packaging> |

第二步:排除内嵌tomcat
1 | <dependency> |
第三步:添加servlet api依赖(引入tomcat,但scope设置为provided,这样这个tomcat服务器就不会打入war包了)
1 | <!--额外添加一个tomcat服务器,实际上是为了添加servlet api。scope设置为provided表示这个不会被打入war包当中。--> |
第四步:修改主类
1 |
|
第五步:把target文件删掉,执行clean和package命令打war包
生成在这里
第六步:配置tomcat环境,将war包放入到webapps目录下,启动tomcat服务器,并访问。
现在不叫javaee了叫JakarataEE 9
https://tomcat.apache.org/选tomcat10然后
然后解压配置环境



然后以管理员身份运行

如果乱码了需要去conf文件下的logging.properties配置,把所有utf-8改成gbk编码

然后关闭窗口,把之前的war包扔到tomcat的webapps文件夹里,然后再次启动startup.bat就开始自动部署,然后访问http://localhost:8080/springboot3-24-transaction-0.0.1-SNAPSHOT/index

SpringBoot的日志处理
日志概述
用system.out.println输出到控制台没有隐私等问题,其他的等后面再看吧
日志框架包括抽象层面的和具体层面的
抽象方面的:SFL4J,Commons logging
具体方面的:log4j,log4j2,logback(SpringBoot默认集成的),JUL
日志级别概述:
不同日志级别反应的严重程度不一样
1.TRACE:这是最低级别的日志信息,用于记录最详细的信息,通常是在调用应用时使用
2.DEBUG:用于记录程序运行时的详细信息,比如变量的值,进入或退出某个方法等,主要用于开发阶段的调试
3.INFO:记录应用程序的一般信息,如系统启动、服务初始化完成等,表示程序运行正常
4.WARN:警告信息,表示可能存在问题或者异常的情况,但是还不至于导致应用停止工作
5.ERROR:错误信息,表示发生了一个错误事件,该错误可能会导致某些功能无法正常工作
在生产环境中,我们可能会将日志级别设置为INFO或更高级别,以避免输出过多的调试信息。这也是SpringBoot默认的日志级别
在开发或测试环境中,降低为DEBUG甚至TRACE,便于进行详细的错误追踪和调试
日志级别从低到高是1-5.级别越低打印的日志信息就越多
更改日志级别:
新建工程然后引用web和lombok,在入口程序这样写
1 | // 这是lombok的一个注解,这个注解的作用是:为我们维护一个日志对象 log |
配置级别:
1 | # 配置日志级别 |
丰富启动日志
SpringBoot项目启动过程中的日志的丰富,启动完成后,项目进入正常运行阶段,这两个配置没用
这两个配置不会对我们程序员手动记录的日志起作用
1 | trace=true |
trace=true:启动SpringBoot的启动跟踪,生成包含启动信息的详细跟踪文件,内容是包含debug=true输出的内容
debug=true:启动SpringBoot的调用模式,增加启动日志的详细程度并显示自动配置报告
日志的粗细粒度
1 | # 测试日志控制的粗细粒度 |
怎么在项目中打印sql语句?默认级别是info,不会显示sql,但想降低级别又不应用到全局,只sql相关的使用debug
1 | #全局的日志级别 |
日志输出到文件
这两种方式不可共存
1 | # 以下的两种实现方式不可共存,其实是SpringBoot框架设计的一个小bug,可以在github提交一下 |
滚动日志
滚动日志是一种日志管理机制,用于防止日志文件无线增长,通过将日志文件分割成多个文件,每个文件只包含一定时间段或大小的日志记录,滚动日志可以帮助你更好地管理和维护日志文件,避免单个日志文件过大导致难以处理
但这个滚动策略只适合于logback框架,如果使用log4j2就需要单独在log4j2.xml里配置
1 | #滚动日志配置 |
日志框架切换
也就是排除logback的依赖然后添加别的
1 | <dependency> |
注意:一旦切换log4j2的日志框架,对于之前的配置来说,只有logback的滚动日志不再生效,其他配置仍然生效,如果要在log4j2中进行滚动日志,需要编写log4j2相关的xml配置文件,比较麻烦







