# dailyblue_boot
**Repository Path**: dailyblue/dailyblue_boot
## Basic Information
- **Project Name**: dailyblue_boot
- **Description**: Spring Boot 是 Pivotal 团队在 Spring 的基础上提供的一套全新的开源框架,其目的是为了简化 Spring 应用的搭建和开发过程。Spring Boot 去除了大量的 XML 配置文件,简化了复杂的依赖管理。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-11-07
- **Last Updated**: 2022-11-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Spring Boot 概述
Spring Boot 是 Pivotal 团队在 Spring 的基础上提供的一套全新的开源框架,其目的是为了简化 Spring 应用的搭建和开发过程。Spring Boot 去除了大量的 XML 配置文件,简化了复杂的依赖管理。
Spring Boot 具有 Spring 的一切优秀特性,Spring 能做的事,Spring Boot 都可以做,而且使用更加简单,功能更加丰富,性能更加稳定而健壮。随着近些年来微服务技术的流行,Spring Boot 也成了时下炙手可热的技术。
Spring Boot 集成了大量常用的第三方库配置,Spring Boot 应用中这些第三方库几乎可以是零配置的开箱即用(out-of-the-box),大部分的 Spring Boot 应用都只需要非常少量的配置代码(基于 Java 的配置),开发者能够更加专注于业务逻辑。

## 创建 SpringBoot 项目
下来我们通过 Intellij IDEA 创建第一个 Spring Boot 项目。
Intellij IDEA 一般可以通过两种方式创建 Spring Boot 项目:
- 使用 Maven 创建
- 使用 Spring Initializr 创建
### Maven 方式创建
首先,文件--->新建--->项目

其次,选择名称、组名和存放路径。

下来,引入 Spring Boot 的相关依赖:
```xml
...
org.springframework.boot
spring-boot-starter-parent
最新版本号
org.springframework.boot
spring-boot-starter-web
...
```
最后,编写 Spring Boot 启动类
创建一个名为 XxxApplication 主程序,用来启动 Spring Boot 应用
````java
@SpringBootApplication
public class XxxApplication {
public static void main(String[] args) {
SpringApplication.run(XxxApplication.class, args);
}
}
````
**注意**:一般 Boot 项目的启动名称都为 项目名+Application 方式。
创建好的项目结构如下:

### Spring Initializr 方式创建
IntelliJ IDEA 支持用户使用 Spring 项目创建向导(Spring Initializr )快速地创建一个 Spring Boot 项目
首先,选择项目创建向导,分别处理如下操作:
1. 项目名称
2. 存放位置
3. 组
4. JDK设置

**注意**:如果start.spring.io网速不好,可以点击齿轮按钮修改成国内镜像:https://start.aliyun.io

## Yaml 概述
Spring Boot 提供了大量的自动配置,极大地简化了 spring 应用的开发过程,当用户创建了一个 Spring Boot 项目后,即使不进行任何配置,该项目也能顺利的运行起来。当然,用户也可以根据自身的需要使用配置文件修改 Spring Boot 的默认设置。
SpringBoot 默认使用以下 2 种全局的配置文件,其文件名是固定的。
- application.properties
- application.yml
其中,application.yml 是一种使用 YAML 语言编写的文件,它与 application.properties 一样,可以在 Spring Boot 启动时被自动读取,修改 Spring Boot 自动配置的默认值。
**注意**:当两种文件都同时存在时,以 application.properties 为主。
### 概述
YAML 全称 YAML Ain't Markup Language,它是一种以数据为中心的标记语言,比 XML 和 JSON 更适合作为配置文件。
想要使用 YAML 作为属性配置文件(以 .yml 或 .yaml 结尾),需要将 SnakeYAML 库添加到 classpath 下,Spring Boot 中的 spring-boot-starter-web 或 spring-boot-starter 都对 SnakeYAML 库做了集成, 只要项目中引用了这两个 Starter 中的任何一个,Spring Boot 会自动添加 SnakeYAML 库到 classpath 下。
下面是一个简单的 application.yml 属性配置文件。
```yaml
server:
port: 8080
```
### 语法
YAML 的语法如下:
- 使用缩进表示层级关系。
- 缩进时不允许使用 Tab 键,只允许使用空格。
- 缩进的空格数不重要,但同级元素必须左侧对齐。
- 大小写敏感。
- Key的冒号和值中间有空格隔开。
例如:
```yaml
server:
port: 8082
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/guanwei
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: guanwei
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: false
```
### 数据结构
YAML 支持以下三种数据结构:
- 字面量:单个的、不可拆分的值
- 对象:键值对的集合
- 数组:一组按次序排列的值
#### 字面量写法
字面量是指单个的,不可拆分的值,例如:数字、字符串、布尔值、以及日期等。
在 YAML 中,使用“key: value”的形式表示一对键值对,如 name: 关为。
字面量直接写在键值对的“value”中即可,且默认情况下字符串是不需要使用单引号或双引号的。
```yaml
name: 关为
```
#### 对象
在 YAML 中,对象可能包含多个属性,每一个属性都是一对键值对。
YAML 为对象提供了 2 种写法:
- 普通写法:使用缩进表示对象与属性的层级关系。
- 行内写法:使用 Map 格式表示对象中属性和值的关系。
```yaml
# 普通写法
user1:
name: 关为
age: 18
sex: 男
# 行内写法
user2: {name: 关为,age: 18,sex: 男}
```
#### 数组
在 YAML 中,数组也和对象一样,存在两种写法,分别也是:普通写法和行内写法。
```yaml
# 普通写法
array1:
- 张三
- 李四
- 王五
# 行内写法
array2: [张三,李四,王五]
```
#### 复合结构写法
````yaml
class:
id: 1
name: 软件一班
headmaster:
id: 1
name: 王老师
subject: 数学老师
desc: 班主任,班级管理的管家
students:
- id: 1
name: 张三
age: 19
- id: 2
name: 李四
age:21
- id: 3
name: 王五
age: 20
````
## Spring Boot 使用 MVC
虽然 SpringMVC 相较于 Servlet 在使用上已经有了极大的提升,但是在环境搭建、配置文件和对注解的使用上仍然有些繁琐,有些同学在想有没有一种方案,可以快速搭建 SpringMVC 环境?
### 引入依赖
这里集成了 SpringMVC、Servlet等相关依赖并设置了兼容版本。
```xml
org.springframework.boot
spring-boot-starter-web
```
### 创建控制类
这里没什么特别的地方,和过去我们学习的 SpringMVC 一致。
```java
@Controller
@RequestMapping("/first")
public class FirstController {
@GetMapping("/index")
public String index() {
return "index";
}
@GetMapping("/json")
@ResponseBody
public String json() {
return "json";
}
}
```
### 文件结构
默认情况下,Spring Boot 将从类路径或 ServletContext 的根目录中的名为 src/main/resources/static 的目录提供静态内容。
在静态内容当中我们可以放js,css样式等文件,除Web服务,我们还可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持各种模板技术,包括Thymeleaf,FreeMarker 和 JSP。当然 SpringBoot 不推荐用 JSP 来作为视图层,通常情况我们把模板放在 src/main/resources/templates下。
以下目录就是典型的模板与静态资源目录结构:

### 相关注解
| 名称 | 解释 | 属性 |
| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| @Controller | 这个是一个 IoC 注解,一般用于标注控制层的类
负责产生对象。 | |
| @ResponseBody | 设置当前方法返回的是数据而不是跳转页面。 | |
| @RestController | 这个是一个复合注解,是@Controller+@ResponseBody
代表产生对象和指定方法返回结果是输出的内容。 | |
| @RequestMapping | 映射注解,可以注解到类或者方法上
有一些子注解:
1. @GetMapping
2. @PostMapping
3. @PutMapping
4. @DeleteMapping | 1. value属性 @RequestMapping 注解的默认属性,因此如果只有 value 属性时,可以省略该属性名,如果有其它属性,则必须写上 value 属性名称。
2. path 属性和 value 属性都用来作为映射使用。path 属性支持通配符匹配,如`@RequestMapping(path="/first/*")`表示`http://localhost:8080/first/zhangsan` 或 `http://localhost:8080/first/lisi` 都能够正常访问
3. name属性相当于方法的注释,使方法更易理解。如 `@RequestMapping(value = "/first",name = "第一个备注")`
4. method 属性用于表示该方法支持哪些 HTTP 请求。如果省略 method 属性,则说明该方法支持全部的 HTTP 请求。
5. params 属性用于指定请求中**必须**包含什么名称的参数。 |
| @RequestParam | 请求参数,书写到形式参数之前 | 可以手动映射参数和形参的关系,也可以设置默认值。 |
| @PathVariable | Rest 风格参数传递 | |
### 配置文件
```yaml
server:
port: 8081
servlet:
context-path: /dailyblue
spring:
application:
name: dailyblue
```
### 启动并访问
启动启动类,并打开浏览器输入路径访问:

### Web启动器
Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,其本身就是 Spring 框架的一部分,可以与 Spring 无缝集成,性能方面具有先天的优越性,是当今业界最主流的 Web 开发框架之一。
Spring Boot 是在 Spring 的基础上创建一款开源框架,它提供了 spring-boot-starter-web(Web 场景启动器) 来为 Web 开发予以支持。spring-boot-starter-web 为我们提供了嵌入的 Servlet 容器以及 SpringMVC 的依赖,并为 Spring MVC 提供了大量自动配置,可以适用于大多数 Web 开发场景。
Spring Boot 为 Spring MVC 提供了自动配置,并在 Spring MVC 默认功能的基础上添加了以下特性:
- 引入了 ContentNegotiatingViewResolver 和 BeanNameViewResolver(视图解析器)
- 对包括 WebJars 在内的静态资源的支持
- 自动注册 Converter、GenericConverter 和 Formatter (转换器和格式化器)
- 对 HttpMessageConverters 的支持(Spring MVC 中用于转换 HTTP 请求和响应的消息转换器)
- 自动注册 MessageCodesResolver(用于定义错误代码生成规则)
- 支持对静态首页(index.html)的访问
- 自动使用 ConfigurableWebBindingInitializer
只要我们在 Spring Boot 项目中的 pom.xml 中引入了 spring-boot-starter-web ,即使不进行任何配置,也可以直接使用 Spring MVC 进行 Web 开发。
> 注意:由于 spring-boot-starter-web 默认替我们引入了核心启动器 spring-boot-starter,因此,当 Spring Boot 项目中的 pom.xml 引入了 spring-boot-starter-web 的依赖后,就无须在引入 spring-boot-starter 核心启动器的依赖了。
## 配置绑定
所谓“配置绑定”就是把配置文件中的值与 JavaBean 中对应的属性进行绑定。通常,我们会把一些配置信息(例如,数据库配置)放在配置文件中,然后通过 Java 代码去读取该配置文件,并且把配置文件中指定的配置封装到 JavaBean(实体类) 中。
SpringBoot 提供了以下 2 种方式进行配置绑定:
- 使用 @ConfigurationProperties 注解
- 使用 @Value 注解
### @ConfigurationPreperties 注解
通过 Spring Boot 提供的 @ConfigurationProperties 注解,可以将全局配置文件中的配置数据绑定到 JavaBean 中。下面我们以 Spring Boot 项目 dailyblue_boot为例,演示如何通过 @ConfigurationProperties 注解进行配置绑定。
#### application.yml
在 Dailyble_boot 的全局配置文件 application.yml 中添加以下自定义属性。
```yaml
student:
id: 1
name: 张三
sex: 男
age: 19
loves: [ '足球','游戏','网球' ]
room:
name: 软件一班
address: 南2楼3楼302
```
#### 实体类
在 Dailyble_boot 项目的 bean 中创建一个名为 Student 的实体类,并将配置文件中的属性映射到这个实体类上,代码如下:
```java
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
*
* @ConfigurationProperties:告诉 SpringBoot 将本类中的所有属性和配置文件中相关的配置进行绑定
* prefix = "student":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能
*/
@Data
@ConfigurationProperties(prefix = "student")
@Component
public class Student implements Serializable {
private Integer id;
private String name;
private Character sex;
private Integer age;
private String[] loves;
private Room room;
}
```
#### 注意
- 只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能。如果我们想要使用 @ConfigurationProperties 注解进行配置绑定,那么首先就要保证该对 JavaBean 对象在 IoC 容器中,所以需要用到 @Component 注解来添加组件到容器中。
- JavaBean 上使用了注解 @ConfigurationProperties(prefix = “person”) ,它表示将这个 JavaBean 中的所有属性与配置文件中以“person”为前缀的配置进行绑定。
#### 控制层类
在 Dailyble_boot 项目的 controller 中创建一个名为 FirstController 的类,注入 Student 类并将它显示到页面中,代码如下:
```java
@RestController
@RequestMapping("/first")
public class FirstController {
@Resource
private Student student;
@GetMapping("/a")
public Student a() {
return student;
}
}
```
#### 启动并查看
启动项目,并输入 http://localhost:8080/first/a 查看效果:

> **一个需要注意的问题:**
>
> 
>
> 如何解决呢?
>
> 在 pom.xml 中引入如下注解:
>
> ```xml
>
> org.springframework.boot
> spring-boot-configuration-processor
> true
>
> ```
### @Value 注解
当我们只需要读取配置文件中的某一个配置时,可以通过 @Value 注解获取。
以 Spring Boot 项目 dailyblue_boot 为例,新建实体类 Student2 ,使用 @Value 注解进行配置绑定,代码如下:
```java
@Data
@Component
public class Student2 implements Serializable {
@Value("${student.id}")
private Integer id;
@Value("${student.name}")
private String name;
@Value("${student.sex}")
private Character sex;
@Value("${student.age}")
private Integer age;
private String[] loves;
private Room room;
}
```
### @Value 与 @ConfigurationProperties 对比
@Value 和 @ConfigurationProperties 注解都能读取配置文件中的属性值并绑定到 JavaBean 中,但两者存在以下不同。
#### 使用位置不同
@ConfigurationProperties:标注在 JavaBean 的类名上。
@Value:标注在 JavaBean 的属性上。
#### 功能不同
@ConfigurationProperties:用于批量绑定配置文件中的配置。
@Value:只能一个一个的指定需要绑定的配置。
#### 松散绑定支持不同
@ConfigurationProperties:支持松散绑定(松散语法),例如实体类 Student 中有一个属性为 firstName,那么配置文件中的属性名支持以下写法:
- student.firstName
- student.first-name
- student.first_name
- STUDENT_FIRST_NAME
@Vaule:不支持松散绑定。
#### SpEL 支持不同
@ConfigurationProperties:不支持 SpEL 表达式。
@Value:支持 SpEL 表达式。
#### 复杂类型封装
@ConfigurationProperties:支持所有类型数据的封装,例如 Map、List、Set、以及对象等;
@Value:只支持基本数据类型的封装,例如字符串、布尔值、整数等类型。
#### 应用场景不同
@Value 和 @ConfigurationProperties 两个注解之间,并没有明显的优劣之分,它们只是适合的应用场景不同而已。
若只是获取配置文件中的某项值,则推荐使用 @Value 注解。
若专门编写了一个 JavaBean 来和配置文件进行映射,则建议使用 @ConfigurationProperties 注解。
我们在选用时,根据实际应用场景选择合适的注解能达到事半功倍的效果。
### @PropertySource 注解
如果将所有的配置都集中到 application.properties 或 application.yml 中,那么这个配置文件会十分的臃肿且难以维护,因此我们通常会将与 Spring Boot 无关的配置(例如自定义配置)提取出来,写在一个单独的配置文件中,并在对应的 JavaBean 上使用 @PropertySource 注解指向该配置文件。
以 Dailyblue_Boot 为例,将与 student 相关的自定义配置移动到 src/main/resources 下的 student.properties 中(注意,必须把 application.properties 或 application.yml 中的相关配置删除),如下图:

student.properties 的配置如下:
```properties
student.id=1
student.name=张三
student.sex=男
student.age=19
student.loves=足球,游戏,网球
student.room.name=软件一班
student.room.address=南2楼3楼302
```
Student 类中引入@PropertySource 注解即可,Student2 类的写法基本一致。

**注意**:
- @PropertySource 只对 properties 文件可以进行加载,但对于 yml 或者 yaml 不能支持。
- 如果读取中文时出现乱码,使用 @PropertySource(value = "classpath:student.properties", encoding="UTF-8")
## 导入Spring配置
默认情况下,Spring Boot 中是不包含任何的 Spring 配置文件的,即使我们手动添加 Spring 配置文件到项目中,也不会被识别。

那么 Spring Boot 项目中真的就无法导入 Spring 配置吗?答案是否定的。
Spring Boot 为了我们提供了以下 2 种方式来导入 Spring 配置:
- 使用 @ImportResource 注解加载 Spring 配置文件
- 使用全注解方式加载 Spring 配置
### @ImportResource 注解
在主启动类上使用 @ImportResource 注解可以导入一个或多个 Spring 配置文件,并使其中的内容生效。
我们还是使用 Dailyblue_Boot 项目为例
#### 创建类
在 pojo 包下创建一个类 DemoA ,代码如下:
```java
@Data
public class DemoA {
private String name;
}
```
#### 引入 spring.xml
在 resource 文件夹下创建 spring.xml 配置文件,代码如下:
```xml
```
#### 控制层
控制层的类注入刚才的 DemoA,代码如下:
```java
@RestController
@RequestMapping("/first")
public class FirstController {
@Resource
private DemoA da;
@GetMapping("/c")
public DemoA c() {
return da;
}
}
```
#### 启动类
修改启动类,引入 @ImportResource 注解,代码如下:
```java
@SpringBootApplication
@ImportResource(locations = {"classpath:/spring.xml"})
public class DailyblueBootApplication {
public static void main(String[] args) {
SpringApplication.run(DailyblueBootApplication.class, args);
}
}
```
### 全注解方式加载 Spring 配置
Spring Boot 推荐我们使用全注解的方式加载 Spring 配置,其实现方式如下:
1. 使用 @Configuration 注解定义配置类,替换 Spring 的配置文件。
2. 配置类内部可以包含有一个或多个被 @Bean 注解的方法,这些方法会被 AnnotationConfigApplicationContext 或 AnnotationConfigWebApplicationContext 类扫描,构建 bean 定义(相当于 Spring 配置文件中的标签),方法的返回值会以组件的形式添加到容器中,组件的 id 就是方法名。
代码部分很简单,这里仅仅书写配置加载类:
```java
@Configuration
public class DemoB {
@Bean
public DemoC getDemoC(){
return new DemoC();
}
}
```
## 定制 Spring MVC
Spring Boot 抛弃了传统 xml 配置文件,通过配置类(标注 @Configuration 的类,相当于一个 xml 配置文件)以 JavaBean 形式进行相关配置。
Spring Boot 对 Spring MVC 的自动配置可以满足我们的大部分需求,但是我们也可以通过自定义配置类并实现 WebMvcConfigurer 接口的方式来定制 Spring MVC 配置,例如拦截器、格式化程序、视图控制器等等。
SpringBoot 1.5 及以前是通过继承 WebMvcConfigurerAdapter 抽象类来定制 Spring MVC 配置的,但在 SpringBoot 2.0 后,这个抽象类就被弃用了,改为实现 WebMvcConfigurer 接口来定制 Spring MVC 配置。
WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的,且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以定制 Spring MVC 的配置。

在 Spring Boot 项目中,我们可以通过以下 2 中形式定制 Spring MVC:
- 扩展 Spring MVC
- 全面接管 Spring MVC
下面,我们分别对这两种定制 Spring MVC 的形式进行介绍。
### 扩展 Spring MVC
如果 Spring Boot 对 Spring MVC 的自动配置不能满足我们的需要,我们还可以通过自定义一个 WebMvcConfigurer 类型的配置类,来扩展 Spring MVC。这样不但能够保留 Spring Boot 对 Spring MVC 的自动配置,享受 Spring Boot 自动配置带来的便利,还能额外增加自定义的 Spring MVC 配置。
**注意**:配置类标注 @Configuration,但不标注 @EnableWebMvc 注解。
#### 创建静态页面
在 static 文件夹下创建 login.html 和 index.html 页面

#### 配置类
创建一个类实现 WebMvcConfigurer 接口
```java
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//当访问 "/" 或 "/index.html" 时,都直接跳转到登陆页面
registry.addViewController("/").setViewName("login.html");
registry.addViewController("/index.html").setViewName("login.html");
}
}
```
#### 效果

### 全面接管 Spring MVC
在一些特殊情况下,我们可能需要抛弃 Spring Boot 对 Spring MVC 的全部自动配置,完全接管 Spring MVC。此时我们可以自定义一个 WebMvcConfigurer 类型的配置类,并在该类上标注 @EnableWebMvc 注解,来实现完全接管 Spring MVC。
**注意**:完全接管 Spring MVC 后,Spring Boot 对 Spring MVC 的自动配置将全部失效。
#### 就修改一个地方:
```java
@Configuration
@EnableWebMvc
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//当访问 "/" 或 "/index.html" 时,都直接跳转到登陆页面
registry.addViewController("/").setViewName("login.html");
registry.addViewController("/index.html").setViewName("login.html");
}
}
```
引入 @EnableWebMvc 注解
#### 页面效果

#### 控制台

#### 直接访问 login.html

Spring Boot 能够访问位于静态资源文件夹中的静态文件,这是在 Spring Boot 对 Spring MVC 的默认自动配置中定义的,当我们全面接管 Spring MVC 后,Spring Boot 对 Spring MVC 的默认配置都会失效,此时再访问静态资源文件夹中的静态资源就会报错了。
## Spring Boot 拦截器
我们对拦截器并不陌生,无论是 Struts 2 还是 Spring MVC 中都提供了拦截器功能,它可以根据 URL 对请求进行拦截,主要应用于登陆校验、权限验证、乱码解决、性能监控和异常处理等功能上。Spring Boot 同样提供了拦截器功能。
在 Spring Boot 项目中,使用拦截器功能通常需要以下 3 步:
1. 定义拦截器
2. 注册拦截器
3. 指定拦截规则(如果是拦截所有,静态资源也会被拦截)
### 定义拦截器
在 Spring Boot 中定义拦截器十分的简单,只需要创建一个拦截器类,并实现 HandlerInterceptor 接口即可。
HandlerInterceptor 接口中定义以下 3 个方法,如下表。
| 返回值类型 | 方法声明 | 描述 |
| ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| boolean | preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) | 该方法在控制器处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。 |
| void | postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) | 该方法在控制器处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步修改。 |
| void | afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) | 该方法在视图渲染结束后执行,可以通过此方法实现资源清理、记录日志信息等工作。 |
### 注册拦截器
创建一个实现了 WebMvcConfigurer 接口的配置类(使用了 @Configuration 注解的类),重写 addInterceptors() 方法,并在该方法中调用 registry.addInterceptor() 方法将自定义的拦截器注册到容器中。
在配置类 SpringMvcConfig 中,添加以下方法注册拦截器,代码如下:
```java
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(你的拦截器类对象);
}
}
```
### 指定拦截规则
修改 SpringMvcConfig 配置类中 addInterceptors() 方法的代码,继续指定拦截器的拦截规则,代码如下:
```java
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(你的拦截器类对象).order(1).addPathPatterns("/**") //拦截所有请求,包括静态资源文件
.excludePathPatterns("/", "/login", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**"); //放行登录页,登陆操作,静态资源
}
}
```
在指定拦截器拦截规则时,调用了几个方法,这几个方法的说明如下:
- addPathPatterns:该方法用于指定拦截路径,例如拦截路径为“/**”,表示拦截所有请求,包括对静态资源的请求。
- excludePathPatterns:该方法用于排除拦截路径,即指定不需要被拦截器拦截的请求。
- order:多个拦截器执行顺序优先级,值越小优先级越高。
至此,拦截器的基本功能已经完成。
## 默认异常处理
在日常的 Web 开发中,会经常遇到大大小小的异常,此时往往需要一个统一的异常处理机制,来保证客户端能接收较为友好的提示。Spring Boot 同样提供了一套默认的异常处理机制。
### Spring Boot 默认异常处理机制
Spring Boot 提供了一套默认的异常处理机制,一旦程序中出现了异常,Spring Boot 会自动识别客户端的类型(浏览器客户端或机器客户端),并根据客户端的不同,以不同的形式展示异常信息。
#### 对于浏览器而言
对于浏览器客户端而言,Spring Boot 会响应一个 "whitelabel" 错误视图,以 HTML 格式呈现错误信息:

#### 对于机器客户端而言
对于机器客户端而言,Spring Boot 将生成 JSON 响应,来展示异常消息。
```json
{
"timestamp": "2022-11-02T14:49:56.885+00:00",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/dailyblue/first/d"
}
```
### Spring Boot 异常处理自动配置原理
Spring Boot 通过配置类 ErrorMvcAutoConfiguration 对异常处理提供了自动配置,该配置类向容器中注入了以下 4 个组件。
- ErrorPageCustomizer:该组件会在在系统发生异常后,默认将请求转发到“/error”上。
- BasicErrorController:处理默认的“/error”请求。
- DefaultErrorViewResolver:默认的错误视图解析器,将异常信息解析到相应的错误视图上。
- DefaultErrorAttributes:用于页面上共享异常信息。
下面,我们依次对这四个组件进行详细的介绍。
#### ErrorPageCustomizer
ErrorMvcAutoConfiguration 向容器中注入了一个名为 ErrorPageCustomizer 的组件,它主要用于定制错误页面的响应规则。
```java
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
```
ErrorPageCustomizer 通过 registerErrorPages() 方法来注册错误页面的响应规则。当系统中发生异常后,ErrorPageCustomizer 组件会自动生效,并将请求转发到 “/error”上,交给 BasicErrorController 进行处理,其部分代码如下:
```java
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
//将请求转发到 /errror(this.properties.getError().getPath())上
ErrorPage errorPage
= new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
// 注册错误页面
errorPageRegistry.addErrorPages(errorPage);
}
```
#### BasicErrorController
ErrorMvcAutoConfiguration 还向容器中注入了一个错误控制器组件 BasicErrorController,代码如下。
```java
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
```
BasicErrorController 的定义如下。
```java
//BasicErrorController 用于处理 “/error” 请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
......
/**
* 该方法用于处理浏览器客户端的请求发生的异常
* 生成 html 页面来展示异常信息
*/
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
//获取错误状态码
HttpStatus status = getStatus(request);
//getErrorAttributes 根据错误信息来封装一些 model 数据,用于页面显示
Map model = Collections
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
//为响应对象设置错误状态码
response.setStatus(status.value());
//调用 resolveErrorView() 方法,使用错误视图解析器生成 ModelAndView 对象(包含错误页面地址和页面内容)
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
/**
* 该方法用于处理机器客户端的请求发生的错误
* 产生 JSON 格式的数据展示错误信息
*/
@RequestMapping
public ResponseEntity