SpringBoot3

153 阅读13分钟

环境要求


环境&工具              | 版本(or later) |
| ------------------ | ------------ |
| SpringBoot         | 3.0.5+       |
| IDEA               | 2021.2.1+    |
| Java               | 17+          |
| Maven              | 3.5+         |
| Tomcat             | 10.0+        |
| Servlet            | 5.0+         |
| GraalVM Community  | 22.3+        |
| Native Build Tools | 0.9.19+

SpringBoot是什么

SpringBoot是一个简化快捷可迅速构建Spring 应用的Spring框架。

***SpringBoot底层是Spring

特性:
1.提供可选的starter,简化应用整合。web-starter,mybatis-starter等等。
2.内置Tomcat容器

入门Demo

image.png

image.png

image.png

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yry</groupId>
    <artifactId>spring_boot3_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring_boot3_demo</name>
    <description>spring_boot3_demo</description>

    <!-- 所有springboot项目都必须继承自 spring-boot-starter-parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.2</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!-- web开发的场景启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <!-- SpringBoot应用打包插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

******
-   官方提供的场景:命名为:`spring-boot-starter-*`
-   第三方提供场景:命名为:`*-spring-boot-starter`
******
package com.yry.spring_boot3_demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "Hello,Spring Boot 3!";
    }
}
package com.yry.spring_boot3_demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBoot3DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBoot3DemoApplication.class, args);
    }
}

依赖管理机制

1、为什么导入`starter-web`所有相关依赖都导入进来?
-   开发什么场景,导入什么场景启动器。
-   maven依赖传递原则。A-B-C: A就拥有B和C
-   导入场景启动器,场景启动器自动把这个场景的所有核心依赖全部导入进来。

2、为什么版本号都不用写?
-   每个boot项目都有一个父项目`spring-boot-starter-parent`
-   parent的父项目是`spring-boot-dependencies`
-   父项目 **版本仲裁中心**,把所有常见的jar的依赖版本都声明好了。

自动配置机制

1.默认的包扫描规则
-   -   `@SpringBootApplication` 标注的类就是主程序类
    -   **SpringBoot只会扫描主程序所在的包及其下面的子包,自动的component-scan功能**
    -   **自定义扫描路径**
     @SpringBootApplication(scanBasePackages = "com.yry")
     @ComponentScan("com.yry")` 直接指定扫描的路径
2.配置默认值
    -   配置文件的所有配置项是和某个类的对象值进行一一绑定的。
    -   绑定了配置文件中每一项值的类:属性类。
比如:
 `ServerProperties`绑定了所有Tomcat服务器有关的配置
 `MultipartProperties`绑定了所有文件上传相关的配置
3.按需加载自动配置
- 导入场景`spring-boot-starter-*`,场景启动器除了会导入相关功能依赖,还会导入一个`spring-boot-starter`,
是所有`starter``starter`,基础核心starter。 `spring-boot-starter`导入了一个包 `spring-boot-autoconfigure`。
包里面都是各种场景的`AutoConfiguration`自动配置类。
-   虽然全场景的自动配置都在 `spring-boot-autoconfigure`这个包,但是不是全都开启的。

**导入哪个场景就开启哪个自动配置,导入场景启动器触发 `spring-boot-autoconfigure`这个包的自动配置生
效、容器中就会具有相关场景的功能。

image.png

image.png

@SpringBootApplication注解

 @SpringBootApplication
`@SpringBootApplication`由三个注解组成`@SpringBootConfiguration``@EnableAutoConfiguratio``@ComponentScan`

`@EnableAutoConfiguration`SpringBoot开启自动配置的核心。
-   -   是由`@Import(AutoConfigurationImportSelector.class)`提供功能:批量给容器中导入组件。
    -   SpringBoot启动会默认加载 142个配置类。这142个配置类来自于`spring-boot-autoconfigure``METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`文件指定的。
    -   项目启动的时候利用 @Import 批量导入组件机制把 `autoconfigure` 包下的142 
        `xxxxAutoConfiguration`类导入进来(自动配置类)。虽然导入了`142`个自动配置类,但是并不是这
        `142`个自动配置类都能生效,每一个自动配置类,都有条件注解`@ConditionalOnxxx`,只有条件成
        立,才能生效。
`xxxxAutoConfiguration`**自动配置类**
每个自动配置类都可能有这个注解`@EnableConfigurationProperties(ServerProperties.class)`,用来把配
置文件中配的指定前缀的属性值封装到 `xxxProperties`属性类中。以Tomcat为例:把服务器的所有配置都是
以`server`开头的。配置都封装到了属性类中。给**容器**中放的所有组件的一些核心参数,都来自于
`xxxProperties``xxxProperties`都是和配置文件绑定。

条件注解

如果注解指定的条件成立,则触发指定行为
@ConditionalOnClass:如果类路径中存在这个类,则触发指定行为
@ConditionalOnMissingClass:如果类路径中不存在这个类,则触发指定行为
@ConditionalOnBean:如果容器中存在这个Bean(组件),则触发指定行为
@ConditionalOnMissingBean:如果容器中不存在这个Bean(组件),则触发指定行为
案列展示:
package com.yry.spring_boot3_demo.config;

import com.yry.spring_boot3_demo.bean.Cat;
import com.yry.spring_boot3_demo.bean.Dog;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;

@SpringBootConfiguration
public class AppConfiguration {

    //如果容器中存在User类则在容器中创建cat实例
    @ConditionalOnClass(name = "com.yry.spring_boot3_demo.bean.User")
    @Bean
    public Cat cat(){
        Cat cat = new Cat();
        return cat;
    }
    //如果容器中不存在User类则在容器中创建dog实例
    @ConditionalOnMissingClass(value = "com.yry.spring_boot3_demo.bean.User")
    @Bean
    public Dog dog(){
        Dog dog = new Dog();
        return dog;
    }
}

@SpringBootApplication
public class SpringBoot3DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run =
                SpringApplication.run(SpringBoot3DemoApplication.class, args);

        String[] cats = run.getBeanNamesForType(Cat.class);
        for(String s :cats){
            System.out.println("cat:"+s);
        }
        String[] dogs = run.getBeanNamesForType(Dog.class);
        for(String s :dogs){
            System.out.println("dog:"+s);
        }
    }

}
输出:cat:cat
其他条件注解
@ConditionalOnRepositoryType (org.springframework.boot.autoconfigure.data)  
@ConditionalOnDefaultWebSecurity (org.springframework.boot.autoconfigure.security)  
@ConditionalOnSingleCandidate (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnWebApplication (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnWarDeployment (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnJndi (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnResource (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnExpression (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnClass (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnEnabledResourceChain (org.springframework.boot.autoconfigure.web)  
@ConditionalOnMissingClass (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnNotWebApplication (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnProperty (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnCloudPlatform (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnBean** (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnMissingBean (org.springframework.boot.autoconfigure.condition)  
@ConditionalOnMissingFilterBean (org.springframework.boot.autoconfigure.web.servlet)  
@Profile (org.springframework.context.annotation)  
@ConditionalOnInitializedRestarter (org.springframework.boot.devtools.restart)  
@ConditionalOnGraphQlSchema (org.springframework.boot.autoconfigure.graphql)  
@ConditionalOnJava (org.springframework.boot.autoconfigure.condition)

属性绑定

@ConfigurationProperties: 声明组件的属性和配置文件哪些前缀开始项进行绑定
@EnableConfigurationProperties:快速注册注解
-场景:SpringBoot默认只扫描自己主程序所在的包。如果导入第三方包,即使组件上标注了 @Component、
@ConfigurationProperties 注解也没用。因为组件都扫描不进来,此时使用这个注解就可以快速进行属性绑定并
把组件注册进容器。
将容器中任意组件(Bean)的属性值和配置文件的配置项的值进行绑定
-  1、给容器中注册组件(@Component、@Bean)
-  2、使用@ConfigurationProperties 声明组件和配置文件的哪些配置项进行绑定
@ConfigurationProperties(prefix = "user")
@Component
public class User {
    private String userName;
    private int age;

    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + ''' +
                ", age=" + age +
                '}';
    }
}
application.properties
user.user-name=张三
user.age=18
@SpringBootApplication
public class SpringBoot3DemoApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext run =
                SpringApplication.run(SpringBoot3DemoApplication.class, args);

        User user = run.getBean(User.class);
        System.out.println(user.toString());
    }

}
输出:User{userName='张三', age=18}
@EnableConfigurationProperties:快速注册注解

//-场景:SpringBoot默认只扫描自己主程序所在的包。如果导入第三方包,即使组件上标注了 @Component、
//@ConfigurationProperties 注解也没用。因为组件都扫描不进来,此时使用这个注解就可以快速进行属性绑定并把组件注册进容器。
@EnableConfigurationProperties(value = Dog.class)
@SpringBootConfiguration
public class AppConfiguration {
}

@ConfigurationProperties(prefix = "dog")
public class Dog {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + ''' +
                '}';
    }
}

application.properties
dog.name=小黄

@SpringBootApplication
public class SpringBoot3DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run =
                SpringApplication.run(SpringBoot3DemoApplication.class, args);
        Dog dog = run.getBean(Dog.class);
        System.out.println(dog.toString());
    }
}
输出:Dog{name='小黄'}

复杂对象properties和yml表示法

@Component
@ConfigurationProperties(prefix = "person") //和配置文件person前缀的所有配置进行绑定
@Data
public class Person {
    private String name;
    private Integer age;
    private Date birthDay;
    private Boolean like;
    private Child child; //嵌套对象
    private List<Dog> dogs; //数组(里面是对象)
    private Map<String,Cat> cats; //表示Map
}

@Data
public class Dog {
    private String name;
    private Integer age;
}

@Data
public class Child {
    private String name;
    private Integer age;
    private Date birthDay;
    private List<String> text; //数组
}

@Data
public class Cat {
    private String name;
    private Integer age;
}
properties表示法
person.name=张三
person.age=18
person.birthDay=2010/10/12 12:12:12
person.like=true
person.child.name=李四
person.child.age=12
person.child.birthDay=2018/10/12
person.child.text[0]=abc
person.child.text[1]=def
person.dogs[0].name=小黑
person.dogs[0].age=3
person.dogs[1].name=小白
person.dogs[1].age=2
person.cats.c1.name=小蓝
person.cats.c1.age=3
person.cats.c2.name=小灰
person.cats.c2.age=2
yml表示法
person:
  name: 张三
  age: 18
  birthDay: 2010/10/10 12:12:12
  like: true
  child:
    name: 李四
    age: 20
    birthDay: 2018/10/10
    text: ["abc","def"]
  dogs:
    - name: 小黑
      age: 3
    - name: 小白
      age: 2
  cats:
    c1:
      name: 小蓝
      age: 3
    c2: {name: 小绿,age: 2} #对象也可用{}表示
细节注意:
**文本**:
-   **单引号**不会转义【\n 则为普通字符串显示】
-   **双引号**会转义【\n会显示为**换行符**】
**大文本**
-   `|`开头,大文本写在下层,保留文本格式,换行符正确显示
-   `>`开头,大文本写在下层,折叠换行符
**多文档合并**
-   使用`---`可以把多个yaml文档合并在一个文档中,每个文档区依然认为内容独立

日志配置

日志门面(接口)
JCL(Jakarta Commons Logging)
SLF4J(Simple Logging Facade)
jboss-logging

日志实现
Log4j
JUL(java.util.logging)
Log4j2
Logback
1.Spring使用commons-logging作为内部日志,但底层日志实现是开放的。可对接其他日志框架。
spring5及以后 commons-logging被spring直接自己写了。
2.支持 jul,log4j2,logback。SpringBoot 提供了默认的控制台输出配置,也可以配置输出为文件。
3.logback是默认使用的。
4.虽然日志框架很多,但是我们不用担心,使用 SpringBoot的默认配置就能工作的很好
SpringBoot怎么把日志默认配置好的
1、每个`starter`场景,都会导入一个核心场景`spring-boot-starter`
2、核心场景引入了日志的所用功能`spring-boot-starter-logging`
3、默认使用了`logback + slf4j` 组合作为默认底层日志
4`日志是系统一启动就要用``xxxAutoConfiguration`是系统启动好了以后放好的组件,后来用的。
5、日志是利用**监听器机制**配置好的。`ApplicationListener`6、日志所有的配置都可以通过修改配置文件实现。以`logging`开始的所有配置。

日志格式

2023-03-31T13:56:17.511+08:00  INFO 4944 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-03-31T13:56:17.511+08:00  INFO 4944 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.7]
默认输出格式:

-   时间和日期:毫秒级精度
-   日志级别:ERROR, WARN, INFO, DEBUG, or TRACE.
-   进程 ID
-   ---: 消息分割符
-   线程名: 使用[]包含
-   Logger 名: 通常是产生日志的**类名**
-   消息: 日志记录的内容

注意: logback 没有FATAL级别,对应的是ERROR

日志级别

-   由低到高:`ALL,TRACE, DEBUG, INFO, WARN, ERROR,FATAL,OFF`;

    -   只会打印指定级别及以上级别的日志
    -   ALL:打印所有日志
    -   TRACE:追踪框架详细流程日志,一般不使用
    -   DEBUG:开发调试细节日志
    -   INFO:关键、感兴趣信息日志
    -   WARN:警告但不是错误的信息日志,比如:版本过时
    -   ERROR:业务错误日志,比如出现各种异常
    -   FATAL:致命错误日志,比如jvm系统崩溃
    -   OFF:关闭所有日志记录

-   不指定级别的所有类,都使用root指定的级别作为默认级别
-   SpringBoot日志默认级别是INFO

1.  在application.properties/yaml中配置logging.level.<logger-name>=<level>指定日志级别
2.  level可取值范围:`TRACE, DEBUG, INFO, WARN, ERROR, FATAL, or OFF`,定义在 `LogLevel`类中
3.  root 的logger-name叫root,可以配置logging.level.root=warn,代表所有未指定日志级别都使用 root 的 warn 级别

日志分组

将相关的logger分组在一起,统一配置。

#日志分组
logging:
  group: #自定义abc分组,指定对应的包路径
    abc: com.yry.spring_boot3_demo.config,com.yry.spring_boot3_demo.controller
  level: #设置自定义分组日志级别
    abc: info
SpringBoot 预定义两个组
Name | Loggers                                                                           
| ---- | ------------------------------------------------------------------- |
| web  | org.springframework.core.codec
         org.springframework.http, org.springframework.web      
         org.springframework.boot.actuate.endpoint.web
         org.springframework.boot.web.servlet.ServletContextInitializerBeans |
| sql  | org.springframework.jdbc.core
         org.hibernate.SQL, org.jooq.tools.LoggerListener

image.png

日志文件输出

SpringBoot 默认只把日志写在控制台,如果想额外记录到文件,可以在application.properties中添加
logging.file.name 或 logging.file.path配置项。

logging.file.name   | logging.file.path | 示例     | 效果                        
| ----------------- | ----------------- | -------- | ---------------------      
| 未指定            | 未指定             |          | 仅控制台输出                
| 指定              | 未指定             | my.log   | 写入指定文件。可以加路径          
| 未指定            | 指定               | /var/log | 写入指定目录,文件名为spring.log(默认的名称为spring.log)
| 指定              | 指定               |          | 以logging.file.name为准

文件归档与滚动切割

归档:每天的日志单独存到一个文档中。
切割:每个文件10MB,超过大小切割成另外一个文件。
1.每天的日志应该独立分割出来存档。如果使用logback(SpringBoot 默认整合),可以通过
  application.properties/yaml文件指定日志滚动规则。
2.如果是其他日志系统,需要自行配置(添加log4j2.xml或log4j2-spring.xml3.支持的滚动规则设置如下
配置项描述
logging.logback.rollingpolicy.file-name-pattern日志存档的文件名格式(默认值:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz)
logging.logback.rollingpolicy.clean-history-on-start应用启动时是否清除以前存档(默认值:false)
logging.logback.rollingpolicy.max-file-size存档前,每个日志文件的最大大小(默认值:10MB)
logging.logback.rollingpolicy.total-size-cap日志文件被删除之前,可以容纳的最大大小(默认值:0B)。设置1GB则磁盘存储超过 1GB 日志后就会删除旧日志文件
logging.logback.rollingpolicy.max-history日志文件保存的最大天数(默认值:7).

image.png

自定义日志配置

日志系统自定义
Logbacklogback-spring.xml 或 logback.xml
Log4j2log4j2-spring.xml 或 log4j2.xml
JDK(Java Util Logging)logging.properties
如果可能,我们建议您在⽇志配置中使⽤ -spring 变量(例如, logback-spring.xml ⽽
不是 logback.xml )。如果您使⽤标准配置⽂件,spring ⽆法完全控制⽇志初始化。
最佳实战:⾃⼰要写配置,配置⽂件名加上 xx-spring.xml

切换日志组合

使用log4j2就需要先移除默认logback日志框架,然后引入对应的log4j2-spring.xml配置文件,实现日志自定义配置。
<dependencies>
    <!-- web开发的场景启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 在starter中移除spring默认的logback日志-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
1. 导⼊任何第三⽅框架,先排除它的⽇志包,因为SpringBoot底层控制好了⽇志
2. 修改 application.properties 配置⽂件,就可以调整⽇志的所有⾏为。如果不够,可
以编写⽇志框架⾃⼰的配置⽂件放在类路径下就⾏,⽐如 logback-spring.xml、log4j2-spring.xml

SpringBoot3-web开发

SpringBootWeb开发能力,由SpringMvc提供。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

image.png

image.png

image.png

静态资源

image.png

image.png

规则一:访问:/webjars/** 路径就去 classpath:/META-INF/resources/webjar

image.png

规则则⼆:访问: /** 路径就去 静态资源默认的四个位置找资源
1. classpath:/META-INF/resources/
2. classpath:/resources/
3. classpath:/static/
4. classpath:/public/

image.png

自定义静态资源规则配置

#开启静态资源映射规则 默认truefalse静态资源无法访问
spring.web.resources.add-mappings=true
#⾃定义webjars资源访问路径前缀
spring.mvc.webjars-path-pattern=/wj/**
#静态资源访问路径前缀,当开启前缀配置后,访问静态资源就必须带上前缀,否则无法访问
#http://localhost:8080/1.jpg (old)不加前缀的访问
#http://localhost:8080/agent/1.jpg (new)加前缀的访问
spring.mvc.static-path-pattern=/agent/**
#自定义静态资源文件路径
spring.web.resources.static-locations=classpath:/my/,classpath:/dwp/

Ant⻛格路径⽤法

Ant ⻛格的路径模式语法具有以下规则: 
*:表示任意数量的字符。 
?:表示任意⼀个字符。  
**:表示任意数量的⽬录。
{}:表示⼀个命名的模式占位符。 
[]:表示字符集合,例如[a-z]表示⼩写字⺟。 
例如: 
*.html 匹配任意名称,扩展名为.html的⽂件。 
/folder1/*/*.java 匹配在folder1⽬录下的任意一级⽬录下的.java⽂件。 
/folder2/**/*.jsp 匹配在folder2⽬录下任意⽬录深度的.jsp⽂件。 
/{type}/{id}.html 匹配任意⽂件名为{id}.html,在任意命名的{type}⽬录下的⽂件。 
注意:Ant ⻛格的路径模式语法中的特殊字符需要转义,
如:
要匹配⽂件路径中的星号,则需要转义为\\*。 
要匹配⽂件路径中的问号,则需要转义为\\?。



AntPathMatcherPathPatternParser
PathPatternParser 在 jmh 基准测试下,有 6~8 倍吞吐量提升,降低 30%~40%空间分配 率 
PathPatternParser 兼容 AntPathMatcher语法,并⽀持更多类型的路径模式

总结:
使⽤默认的路径匹配规则,是由 PathPatternParser 提供的。
# 改变路径匹配策略: 
# ant_path_matcher ⽼版策略; 
# path_pattern_parser 新版策略; 
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

多端内容适配

1.1. 基于请求头内容协商:(默认开启) 
1.2. 客户端向服务端发送请求,携带HTTP标准的Accept请求头。 
1.3. Accept: application/json 、 text/xml 、 text/yaml 
1.4. 服务端根据客户端请求头期望的数据类型进⾏动态返回

2.1. 基于请求参数内容协商:(需要开启) 
2.2. 发送请求 GET /xxx?format=json 
2.3. 匹配到 @GetMapping("/xxx") 
2.4. 根据参数协商,优先返回 json 类型数据【需要开启参数匹配设置】 
2.5. 发送请求 GET /xxx?format=xml,优先返回 xml 类型数据
1. 引⼊⽀持写出xml内容依赖
<dependency> 
    <groupId>com.fasterxml.jackson.dataformat</groupId> 
    <artifactId>jackson-dataformat-xml</artifactId> 
</dependency>

2.创建返回xml模型
@JacksonXmlRootElement // 可以写出为xml⽂档 
@Data public class Person { 
    private Long id; 
    private String userName; 
    private String email; 
    private Integer age; 
}

3. 开启基于请求参数的内容协商 
# 开启基于请求参数的内容协商功能。 默认参数名:format。 默认此功能不开启 
spring.mvc.contentnegotiation.favor-parameter=true 
# 指定内容协商时使⽤的参数名。默认是 format 
spring.mvc.contentnegotiation.parameter-name=type

image.png

image.png