SpingBoot3入门学习-Web开发-三

SpringBoot的Web开发能力,由SpringMVC提供。

自动配置流程分析

1.需要在pom.xml文件中导入需要使用的场景

复制代码
spring-boot-starter-web
XML 复制代码
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.在场景spring-boot-starter-web 的配置文件中会导入一个

复制代码
spring-boot-starter

3.在这个starter中又会导入一个

复制代码
spring-boot-autoconfigure 自动配置功能

4.自动配置它配置了那些东西啦,由于springboot启动时候需要用到

复制代码
@SpringBootApplication 注解。

在@SpringBootApplication 注解上又使用了**@EnableAutoConfiguration**开启自动配置功能注解

开启自动配置注解上又使用了自动批量导入组件功能

那我们查看下他是从哪里批量导入的组件,进入到AutoConfigurationImportSelector类中

最后加载路径:

复制代码
"META-INF/spring/%org.springframework.boot.autoconfigure.AutoConfiguration.imports"

注意:

Boot3 及更早:所有自动配置类全部写在 spring-boot-autoconfigure.jar 内部的 AutoConfiguration.imports 文件里(包含 webmvc、redis、jdbc 等所有配置)

Boot4:不再存在单一大包 autoconfigure,各个功能独立拆分所以4.0需要在webmvc包中查找。

XML 复制代码
org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.WebMvcObservationAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web.WebMvcHealthEndpointExtensionAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.actuate.web.mappings.WebMvcMappingsAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration

绑定了配置文件的一堆配置项

·1、SpringMVC的所有配置:spring.mvc

·2、Web场景通用配置:spring.web

·3、文件上传配置:spring.servlet.multipart

·4、服务器的配置:server:如:编码方式

默认配置规则

在官方文档中已有说明:

1.包含了ContentNegotiatingViewResolverBeanNameViewResolver 组件,方便视图解析

2.默认的静态资源处理机制:静态资源放在static文件夹下即可直接访问

3.自动注册了Converter,GenericConvVerter,Formatter 组件,适配常见的数据类型转换 和格式化需求。

4.支持HttpMessageConverters ,可以方便返回json等数据类型

5.注册MessageCodesResolver ,方便国际化及错误消息处理

6.支持静态index.html

7.自动使用ConfigurableWebBindinglnitializer, 实现消息处理、数据绑定、类型转化等功能

静态配置规则

java 复制代码
//在这些配置之后才执行自动配置
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class },
		afterName = "org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration")
//如果这是一个web应用配置才会生效,类型为SERVLET
@ConditionalOnWebApplication(type = Type.SERVLET)
//容器中有这些组件才会生效
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//容器中没有WebMvcConfigurationSupport配置才会生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
//优先级排序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@ImportRuntimeHints(WebResourcesRuntimeHints.class)
public final class WebMvcAutoConfiguration {

}

这个WebMvcAutoConfiguration 类下面放了两个Filter:

HiddenHttpMethodFilter ;页面表单交Rest请求 (GET、POST、PUT、DELETE)

FormContentFilter:表单内容Filter,GET(数据放URL后面)、POST(数据放请求体)请求可以携带数据,PUT、DELETE的请求体数据会被忽略

这个文件中还有一个类实现了WebMvcConfigurer 他是用于向容器中增加配置的。

给容器中放了WebMvcConfigurer组件;给SpringMVC添加各种定制功能

所有的功能最终会和配置文件进行绑定

WebMvcProperties.class:spring.mvc 配置文件

WebProperties.class:spring.web配置文件

如下方法实现了静态资源规则:

资源查找的两个方法分析

第一个方法规则:我们看到addResourceHandler方法第二个参数是需要传递路径上面调用了

复制代码
getWebjarsPathPattern()方法获取路径。跟踪进去看到这个方法调用了一个私有变量路径写死
复制代码
"/webjars/**"

第二个方法:调用了

复制代码
this.mvcProperties.getStaticPathPattern()

它又调用了自己类中变量 staticPathPattern

跟踪方法,第三个参数返回值是

最终就是:

第一个方法规则:

访问:/webjars/** 路径就会去

复制代码
classpath:/META-INF/resources/webjars/  路径下找资源,
作用:可以直接访问第三方包下的静态资源

第二个方法规则:

访问:/** 路径就会去类路径下四个位置查找资源

复制代码
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/

静态资源设置了缓存

如果服务这个资源没有发生变化,下次访问的时候就可以直接让浏览器用自己缓存中的东西,而不用给服务器发请求。

复制代码
setCachePeriod(cachePeriod)设置缓存周期,以秒为单位。默认0秒
复制代码
setCacheControl(cacheControl)设置Http控制,默认没有控制。参考HTTP 缓存 - HTTP | MDN
复制代码
setUseLastModified() 是否使用最后一次修改。

如果要进行这些规则修改需要在application.yaml配置文件中使用:spring.web

欢迎页规则

在这个文件中还有一个类:

复制代码
EnableWebMvcConfiguration

它下面又有两个handlerMapping方法(handlerMapping的都是用于处理请求的):

复制代码
welcomePageHandlerMapping()  有欢迎页面规则
复制代码
welcomePageNotAcceptableHandlerMapping()

最终:欢迎页会到静态资源中的四个目录中取查找index.html,如果找到就展示。

Favicon图标

只要是Favicon.ico放在了静态资源目录下就会自动被找到。

自定义静态资源的规则

方式一:配置方式

spring.web

spring.mvc

方式二:代码方式

1.在主程序创建一个目录,并创建一个类

2.这个类需要添加注解@Configuration 告诉程序这是一个配置类

3.让这个类实现 WebMvcConfigurer 接口

4.重写接口中的方法,静态资源需要重写addResourceHandlers() 方法

java 复制代码
@Configuration // 配置类
public class Myconfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //保留以前配置
        WebMvcConfigurer.super.addResourceHandlers(registry);

        //自己的自定义配置
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }

}

第二种代码写法:

不用实现WebMvcConfigurer 接口,在类方法中匿名创建WebMvcConfigurer接口实现类,重写addResourceHandlers()方法

java 复制代码
@Configuration // 配置类
public class Myconfig {
    @Bean
    public WebMvcConfigurer webMvcConfigurer () {
      return new WebMvcConfigurer (){
           @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                //保留以前配置
                WebMvcConfigurer.super.addResourceHandlers(registry);

                //自己的自定义配置
              
 registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
            }
            
        }

    }

}

为什么在容器中放入一个WebMvcConfiguration组件就能实现配置生效

1.WebMvcAutoConfiguration是一个自动配置类,它里面有一个EnableWebMvcConfiguration类

2.EnableWebMvcConfiguration 继承与 DelegatingWebMvcConfiguration,这两个都生效

3.DelegatingwebMvcConfiguration 利用DI把容器中所有WebMvcConfigurer 注入进来

别人调用 DelegatingwebMvcConfiguration 的方法配置底层规则,而它调用所有 WebMvcConfigure

r的配置底层方法。

同理,使用相同的思路也能配置其他比如拦截器等。

路径匹配

Spring5.3之后加入了更多的请求路径匹配的实现策略;

以前只支持 AntPathMatcher策略,现在提供了PathPatternParser策略。并且可以让我们指定到底使用那种策略。

1.AntPathMatcher 风格路径用法

Ant风格的路径模式语法具有以下规则:

*: 表示任意数量的字符。

?: 表示任意一个字符。

** : 表示任意数量的目录。

{} : 表示一个命名的模式占位符。

: 表示字符集合,例如a-z表示小写字母。

+ :表示可以有多个

示例:

表示:a开头的任意多个字符路径下,b开头的后面一个字符串路径,

例如:

·*.html匹配任意名称,扩展名为.html的文件。

·/folder1/*/*.java 匹配在folder1路径下的任意两级目录下的.java文件。

/folder2/**/*.jsp匹配在folder2路径下任意目录深度的.jsp文件。

·/{type}{}id}.html 匹配任意文件名为(id).html,在任意命名的(type)目录下的文件。

注意:Ant风格的路径模式语法中的特殊字符需要转义,如:

·要匹配文件路径中的星号,则需要转义为\\*。

·要匹配文件路径中的问号,则需要转义为\\?。

AntPathMatcher 与 PathPatternParser

PathPatternParser 在jmh基准测试下,有6~8倍吞吐量提升,降低30%~40%空间分配率

PathPatternParser 兼容 AntPathMatcher语法,并支持更多类型的路径模式

PathPatternParser"**"多段匹配的支持仅允许在模式末尾使用

注意新版PathPatternParser 不支持 ** 双星号 在路径中间。如果配置在了中间需要配置为老版本的Ant匹配策略

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

内容协商功能

一个接口适配多端不同接口

1.多端内容适配

1.默认规则

SpringBoot多端内容适配。

1.1.基于请求头内容协商:

客户端向服务端发送请求,携带HTTP标准的Accept请求头。

  • **Accept:**application/json、text/xml、text/yaml
  • 服务端根据客户端请求头期望的数据类型进行动态返回

1.2.基于请求参数内容协商:

  • 发送请求 GET /projects/spring-boot?format=json
  • 匹配到**@GetMapping("/projects/spring-boot")**
  • 根据参数协商,优先返回json类型数据**需要开启参数匹配设置**
  • 发送请求GET/projects/spring-boot?format=xml,优先返回 xml类型数据
  • 如果使用**?format=xml 请求方式需要开启配置 spring.mvc.contentneqotiation.favor-parameter=true**
  • 如果想参数名不是format 那么可以配置:spring.mvc.contentnegotiation.parameter-name=type 这里配置的type,以后请求就使用?type=xml

SpringBoot项目导入json包默认支持返回值json格式,如果需要返回值解析成xml需要导入包:

需要在bean类上添加注解**@JacksonXmlRootElement()**

SpringBoot4以上用下面这个依赖:

XML 复制代码
<dependency>
    <groupId>tools.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

SpringBoot3用下面这个依赖:

复制代码
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

核心区别

com.fasterxml.jackson.dataformat tools.jackson.dataformat
Jackson 版本 2.x(旧版) 3.x(新版)
groupId com.fasterxml.jackson.* tools.jackson.*
Java 包名 com.fasterxml.jackson.dataformat.xml tools.jackson.dataformat.xml
Spring Boot 版本 SB 3.x 及以前 SB 4.0 默认使用
最低 JDK Java 8 Java 17
Spring Boot 3.x (Jackson 2) Spring Boot 4.x (Jackson 3)
依赖 com.fasterxml.jackson.dataformat:jackson-dataformat-xml tools.jackson.dataformat:jackson-dataformat-xml
注解包名 com.fasterxml.jackson.dataformat.xml.annotation tools.jackson.dataformat.xml.annotation
根元素注解 @JacksonXmlRootElement @JacksonXmlRootElement(不变)
属性注解 @JacksonXmlProperty @JacksonXmlProperty(不变)
包装器注解 @JacksonXmlElementWrapper @JacksonXmlElementWrapper(不变)
java 复制代码
@JacksonXmlRootElement(localName = "employee")
@Data
public class Employee {
    @JacksonXmlProperty(localName = "id")
    private Integer id;
    
    @JacksonXmlProperty(localName = "name")
    private String name;
}

自定义数据返回类型

localhost:8080/cat?format=json 返回数据就是json类型格式的数据。

localhost:8080/cat?format=xml 返回数据就是xml类型格式的数据。

如果我想要返回自己定义的格式啦?

例如:我想服务器给我返回数据是yaml格式数据?

localhost:8080/cat?format =yaml

我们想要自定义数据格式返回需要熟悉底层原理,熟悉底层原理只要熟悉HttpMessageConverter底层是如何工作的。

1. @ResponseBody 由 HttpMessageConverter 处理的

标注了@ResponseBody 的返回值将会由支持它的 HttpMessageConverter 写给浏览器

由于Controller类上使用了注解@RestController ,这个注解又是 @Controller + @ResponseBody组合,在类上标注了@ResponseBody等于给类中所有方法都标注注解@ResponseBody

Spring MVC 采用前端控制器模式 (Front Controller),DispatcherServlet 是所有 HTTP 请求的单一入口。

当请求到达时,Servlet 容器(Tomcat 等)将请求交给 DispatcherServlet,它负责"分发"给后续组件处理:

完整调用链路(@ResponseBody 场景)

复制代码
HTTP Request
    ↓
Tomcat → HttpServletRequest/HttpServletResponse
    ↓
DispatcherServlet.doService() → doDispatch()
    ↓
HandlerMapping → 找到 @RequestMapping 对应的 HandlerMethod
    ↓
DispatcherServlet → 获取 HandlerAdapter(默认 RequestMappingHandlerAdapter)
    ↓
HandlerAdapter.handle() → 调用 Controller 方法
    ↓
Controller 方法返回带 @ResponseBody 注解的对象
    ↓
RequestResponseBodyMethodProcessor 处理返回值
    ↓
HttpMessageConverter.write() 序列化(如 JSON)
    ↓
写入 HttpServletResponse.getOutputStream()
    ↓
Tomcat 发送 HTTP Response

关键步骤详解

1. 请求进入 DispatcherServlet

DispatcherServlet 继承自 FrameworkServlet,后者实现了 HttpServlet.service(),将所有 HTTP 方法(GET/POST/PUT/DELETE 等)统一路由到 processRequest(),最终调用 DispatcherServlet.doService()

doService() 中,DispatcherServlet 会设置一些请求属性(如 WebApplicationContext、LocaleResolver 等),然后调用核心的 doDispatch() 方法。

2. 查找处理器:HandlerMapping

doDispatch() 内部遍历所有注册的 HandlerMapping,找到能处理当前请求的处理器。对于注解驱动的 Controller,使用的是 RequestMappingHandlerMapping,它会根据 URL 和方法注解匹配到具体的 HandlerMethod

3. 获取适配器:HandlerAdapter

找到处理器后,DispatcherServlet 再遍历 HandlerAdapters,找到支持该处理器的适配器。对于 @RequestMapping 标注的方法,匹配的是 RequestMappingHandlerAdapter

4. 执行 Controller 方法

RequestMappingHandlerAdapter 内部会:

  • 用参数解析器(HandlerMethodArgumentResolver)解析方法入参

  • 调用 Controller 方法

  • 用返回值处理器(HandlerMethodReturnValueHandler)处理返回值

5. @ResponseBody 的识别与处理

当 Controller 方法或类上有 @ResponseBody(或 @RestController)时,返回值处理器链中,RequestResponseBodyMethodProcessor 会匹配并接管处理。

RequestResponseBodyMethodProcessor 的核心逻辑:

  1. 根据请求的 Accept 头进行内容协商(Content Negotiation),确定响应的 MediaType

  2. 遍历 RequestMappingHandlerAdapter 中注册的 HttpMessageConverter 列表

  3. 调用 canWrite(Class, MediaType) 找到能处理该返回值类型和 MediaType 的转换器

  4. 调用 write() 将 Java 对象序列化并写入响应流

6. HttpMessageConverter 序列化

HttpMessageConverter 是实际做"对象 ↔ HTTP 报文体"转换的组件。

以返回 JSON 为例:

  • 默认使用 MappingJackson2HttpMessageConverter(需要 Jackson 依赖)

  • 它调用 Jackson 的 ObjectMapper 将 Java 对象序列化为 JSON 字符串

  • 设置响应头 Content-Type: application/json

  • 写入 HttpServletResponse.getOutputStream()

write() 方法的典型实现:

7. 跳过视图解析

关键点 :当 HttpMessageConverter 接管了响应后,Controller 方法返回给 DispatcherServletModelAndViewnullDispatcherServlet 检测到 ModelAndView == null 时,不会执行任何视图解析和渲染逻辑,直接结束请求处理

案例实现yaml数据格式返回(springboot3)

1.添加依赖(Jackson 2)

XML 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
</dependency>

2.配置application.properties中配置增加一个媒体类型

java 复制代码
spring.mvc.contentnegotiation.media-types.yaml=application/yaml

3.写一个配置类实现WebMvcConfigurer 接口重写实现它的 configureMessageConverters()方法或extendMessageConverters()方法

  • configureMessageConverters清空原有全部转换器,只保留你自己的
  • extendMessageConverters追加,保留 spring 默认 json 转换器,只新增你的,绝大多数业务场景用这个
  • **注意:**application.properties添加的媒体类型和super()方法中写的一致
java 复制代码
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * SpringBoot4(SpringFramework7) 自定义消息转换器
 */
public class MyCustomHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

   private ObjectMapper objectMapper = null;//把对象转成yaml

 // 声明支持的MediaType,例如 text/plain;charset=UTF-8
    public MyCustomHttpMessageConverter() {
         //通过父类构造方法传入类型告诉SpringBoot这个MessageConverter支持哪种媒体类型
        super(new MediaType("application", "yaml", Charset.forName("uTF-8")));
        
         // 1. 先配置 YAMLFactory,禁用文档开始标记 ---
        YAMLFactory factory = YAMLFactory.builder()
                .disable(YAMLWriteFeature.WRITE_DOC_START_MARKER)
               .build();
        objectMapper =new ObjectMapper (factory );
    }

    /**
     * 判断是否支持该目标Class类型
     */
    @Override
    protected boolean supports(@NonNull Class<?> clazz) {
        // 返回true代表处理这个类型;示例全部放行,实际按需写逻辑
        return Object.class.isAssignableFrom(clazz);
    }

    /**
     * 请求体读取:http请求报文 → java对象
     */
    @Override
    protected Object readInternal(@NonNull Class<?> clazz, @NonNull HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        // 读取inputMessage.getBody()输入流,反序列化为对象
        return null;
    }

    /**
     * 对象写出:java对象 → http响应报文输出流
     */
    @Override
    protected void writeInternal(@NonNull Object t, @NonNull HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        // 将对象序列化写入 outputMessage.getBody()
            //try-with写法,自动关流
            try(OutputStream os=outputMessage.getBody()) {
            this.yamlmapper.writeValue(os, o);
        }
    }

    
}
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 方式1:add 添加到末尾,优先级低
        converters.add(new MyCustomHttpMessageConverter());

        // 方式2:add(0,xxx) 放到列表第一个,最高优先级,优先执行你的转换器
        // converters.add(0, new MyCustomHttpMessageConverter());
    }
}

springboot4返回yaml

1.导入依赖

java 复制代码
<!-- Jackson 3 的 YAML 支持 -->
<dependency>
    <groupId>tools.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
</dependency>

使用包中的YAMLMapper 转换对象为yaml格式

java 复制代码
//    public static void main(String[] args) {
//        User user = new User();
//        user.setName("张三");
//        user.setAge(18);
//        user.setEmail("dfsdfds@qq.com");
//
//        // 1. 先配置 YAMLFactory,禁用文档开始标记 ---
//        YAMLFactory factory = YAMLFactory.builder()
//                .disable(YAMLWriteFeature.WRITE_DOC_START_MARKER)
//                .build();
//        YAMLMapper mapper = new YAMLMapper(factory);
//
//        String yaml = mapper.writeValueAsString(user);
//
//        System.out.println(yaml);
//    }
  1. application.yml添加对应的媒体类型spring.mvc.contentnegotiation.media-types.yaml=application/yaml

注意:配置为application/yaml 访问浏览器后application/yaml 不是浏览器标准支持的 MIME 类型,所以浏览器没有内置渲染逻辑。显示在浏览器可以配置为text/yaml 但这样就失去了 YAML 的语义,客户端也无法区分这是 YAML 还是普通文本

java 复制代码
spring:
  mvc:
    contentnegotiation:
     
      # 启用基于请求参数的内容协商
      favor-parameter: true
      # 参数名默认为 format,这里显式声明
      parameter-name: format
      # 注册 format=yaml 对应的媒体类型
      media-types:
        yaml: application/yaml

      # 不带 format 参数时,默认返回 JSON
      default-content-type: application/json

3.配置类 重写configureMessageConverters 方法添加YAML 的 HttpMessageConverter

写一个类继承制AbstractHttpMessageConverter<Object>抽象类

或实现HttpMessageConverter接口

java 复制代码
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * SpringBoot4(SpringFramework7) 自定义消息转换器
 */
public class MyCustomHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

   private ObjectMapper objectMapper = null;//把对象转成yaml

 // 声明支持的MediaType,例如 text/plain;charset=UTF-8
    public MyCustomHttpMessageConverter() {
         //通过父类构造方法传入类型告诉SpringBoot这个MessageConverter支持哪种媒体类型
        super(new MediaType("application", "yaml", Charset.forName("uTF-8")));
        
         // 1. 先配置 YAMLFactory,禁用文档开始标记 ---
        YAMLFactory factory = YAMLFactory.builder()
                .disable(YAMLWriteFeature.WRITE_DOC_START_MARKER)
               .build();
        objectMapper =new ObjectMapper (factory );
    }

    /**
     * 判断是否支持该目标Class类型
     */
    @Override
    protected boolean supports(@NonNull Class<?> clazz) {
        // 返回true代表处理这个类型;示例全部放行,实际按需写逻辑
        return Object.class.isAssignableFrom(clazz);
    }

    /**
     * 请求体读取:http请求报文 → java对象
     */
    @Override
    protected Object readInternal(@NonNull Class<?> clazz, @NonNull HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        // 读取inputMessage.getBody()输入流,反序列化为对象
        return null;
    }

    /**
     * 对象写出:java对象 → http响应报文输出流
     */
    @Override
    protected void writeInternal(@NonNull Object t, @NonNull HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        // 将对象序列化写入 outputMessage.getBody()
            //try-with写法,自动关流
            try(OutputStream os=outputMessage.getBody()) {
            this.yamlmapper.writeValue(os, o);
        }
    }

    
}
  • WebMvcConfigurer#configureMessageConverters(HttpMessageConverters.ServerBuilder builder)(新 Builder 方式)
  • SpringBoot 专用:ServerHttpMessageConvertersCustomizer Bean(生产最推荐

方式一:写配置类实现接口方式

java 复制代码
@Configuration // 配置类
public class Myconfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) {
        // addCustomConverter:添加自定义转换器,放到转换器列表最前面,优先级最高
         builder.addCustomConverter(new MyCustomHttpMessageConverter());
    }

方式二:配置类使用注解@Bean方式注入到容器

java 复制代码
@Configuration
public class MyConfig {

    /**
     * SpringBoot4 服务端MVC消息转换器自定义
     */
    @Bean
    public ServerHttpMessageConvertersCustomizer serverHttpMessageConvertersCustomizer() {
        return builder -> {
            // 添加自定义转换器,放到头部,优先执行
            builder.addCustomConverter(new MyCustomHttpMessageConverter());
        };
    }
}
  1. Controller方法
java 复制代码
@RestController
public class UserController {

    @GetMapping("/user")
    public User getUser() {
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        user.setEmail("dfsdfds@qq.com");
        return user;
    }
}

模版引擎

由于SpringBoot使用了嵌入式Servlet容器。所以JSP默认是不能使用的。

如果需要服务端页面渲染,优先考虑使用 模板引擎。

官方推荐使用Thymeleaf: www.thymeleaf.org 是服务器渲染端

整合Thymeleaf

1.导入依赖包

java 复制代码
<dependency>
   
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2.配置spring.thymeleaf

自动配置原理

  1. 开启了 org.springframework.boot.autoconfigure.thymeleaf. ThymeleafAutoConfiguration 自动

配置

2.属性绑定在 ThymeleafProperties 中,对应配置文件 spring.thymeleaf 内容

3.所有的模板页面默认在classpath:/templates文件夹下

在自动配置属性中有两个默认属性:前缀和后缀

页面展示demo

1.导入依赖包后,再Controller文件夹下写一个HelloController

java 复制代码
@Controller //这个注解用于前后端不分离的项目
//@RestController //这个注解用于前后端分离的项目
public class HelloController {

    @GetMapping ("/hello2")
    public String hello(@RequestParam (value = "name") String name, Model model) {

        //把需要的数据放在model中,前端页面就可以通过model获取数据
        model.addAttribute("name", name);

        //返回模版视图名,就是templates文件夹下html的页面名称
        // =前缀+视图名称+后缀 例如:classpath:/templates/hello.html
        return "hello";
    }
}

2.在templates下添加页面

3.如果请求中需要带参数请求,并把结果展示到页面需要把结果放到Model 中。

4.页面中获取动态数据需要使用到 th:text="${}"

thymeleaf基础语法

如果需要在HTML 页面中有自动提示功能需要在页面的html标签中添加

复制代码
xmlns:th="http://www.thymeleaf.org"

th:xxx:动态渲染指定的html标签属性值、或者th指令(遍历、判断等)

th:text:标签体内文本值渲染,原文本输出。

th:utext:标签体内文本值渲染,但是带有html标签会被浏览器解析

th:属性 :标签指定属性渲染,这里的属性就是html标签中的属性例如src ,style等

th:attr:标签任意多个属性渲染,例如:<img

src="1.jpg" style="width:30@px;" th:attr="src={imgUrl}, style=istyle}" />

th:if
th:each

..:其他th指令

表达式:动态取值

${} :变量取值

@{} :url路径,如果项目配置根路经(server.servlet.context-path=/demo)改变也不受影响。

#{} :国际化消息

~{} :片段引用

*{} :变量选择:需要配合th:object绑定对象

内置对象和系统工具

  • param:请求参数对象
  • session:session对象
  • application :application对象
  • #execInfo:模板执行信息
  • #messages:国际化消息
  • #uris:uri/url工具
  • #conversions:类型转换工具
  • #dates:日期工具,是java.util.Date 对象的工具类
  • #calendars :类似#dates,只不过是 java.util.Calendar 对象的工具类
  • #temporals : JDK8+ java.time APl 工具类
  • #numbers:数字操作工具
  • #strings:字符串操作
  • #objects:对象操作
  • #bools:bool操作
  • #arrays :array工具
  • #lists :list工具
  • #sets:set工具
  • #maps:map工具
  • #aggregates:集合聚合工具(sum.avg)
  • #ids:id生成工具

使用方法参考官网:Tutorial: Using Thymeleaf

th:each 循环遍历

属性优先级

模版片段

1.先把公共部分抽取出来,写到一个html页面中。然后在th:fragment标签取一个名称

2.使用抽取出来的模版片段,在需要使用模版片段位置写上

th:replace=**~{}**标签,第一个common是模版名称common.html ,第二个参数myheader 就是片段名称

springboot热启动插件

修改html页面代码,直接在浏览器可以看到效果不用重新启动项目,但是需要按下ctrl+F9

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

国际化配置

1.Spring Boot 在类路径根下查找messages资源绑定文件。resources文件夹下名为:messages.properties

messages.properties : 默认

messages_zh_CN.properties:中文环境

messages_en_US.properties:英语环境

2.在文件中填写上对应的中英文

3.在页面中可以使用表达式#{}获取国际化的配置项值

错误处理

SpringMVC的错误处理机制依然保留,MVC处理不了,才会交给boot进行处理

1-4是原来springMVC处理错误的规则:

如果我们在自己写的控制器方法上添加了 @ExceptionHandler(Exception.class),发生错误时候就会来调取当前控制器内部处理错误的方法。

java 复制代码
@Controller //这个注解用于前后端不分离的项目
//@RestController //这个注解用于前后端分离的项目
public class HelloController {
    @ResponseBody //把错误消息返回到页面上
    @ExceptionHandler(Exception.class)  //捕获所有异常
    public String handleException(Exception e){
        return "你访问的页面发生了错误"+"错误信息:"+e.getMessage();
    }
}

如果统一处理所有控制器中异常,创建一个类添加注解@ControllerAdvice

java 复制代码
@ControllerAdvice //这个类是处理所有@Controller抛出的异常
public class GlobeExceptionHandler {

    @ResponseBody //把错误消息返回到页面上
    @ExceptionHandler(Exception.class)  //捕获所有异常
    public String handleException(Exception e){
        return "你访问的页面发生了错误---------------"+"错误信息:"+e.getMessage();
    }
}

如果没有springMVC处理异常的相关方法,就会按照下面处理:

解析一个错误页,如果发生了500,404、503、403这些错误,springboot框架会去查找类路径下模板引擎,默认在classpath:/templates/error/精确码.html(例如:500.html)

如果没有模板引擎,在静态资源文件夹下找 精确码.html

如果还是匹配不到就在classpath:/templates/error/5xx.html ,classpath:/templates/error/4xx.html

如果没有模板引擎,在静态资源文件夹下找 5xx.html,4xx.html

如果模板引擎路径templates下有 error.html页面,就直接渲染,没有使用springboot框架提供的默认error模型视图白页。

WEB新特性

1.Problemdetails

错误信息返回新格式

RFC 7807: https://www.rfc-editor.org/rfc/rfc7807

默认这个配置是关闭的,如果需要开启需要在application.properties中配置:

复制代码
#problemdetails默认 false是关闭的
spring.mvc.problemdetails.enabled=true

2.函数式WEB

SpringMvC5.2 以后允许我们使用函数式的方式,定义Web的请求处理流程。

函数式接口

Web请求处理的方式:

  1. @Controller+@RequestMapping :耦合式(路由、业务耦合)

  2. 函数式Web: 分离式(路由、业务分离)

web函数式核心对象

核心四大对象

1、RouterFunction:定义路由信息。发什么请求,谁来处理

2、RequestPredicate:定义请求:请求规则。请求方式(GET、POST)、请求参数

  1. ServerRequest:封装请求完整数据

  2. ServerResponse:封装响应完整数据

web函数式步骤:

1.创建一个配置类添加注解@Configuration,创建一个方法返回值是RouterFunction<ServerResponse>

java 复制代码
@Configuration //标记这是一个配置类
public class WebFunctionConfig {

    @Bean  //使用@Bean注解标记这是一个Bean时候方法中的UserHandler类会被自动注入到容器中
    public RouterFunction<ServerResponse> userRouter(UserHandler userHandler){
        return RouterFunctions.route() //路由函数工具定义路由信息
                // 定义路由信息,参数1:请求路径,参数2:请求条件,参数3:请求处理逻辑
                .GET("/user/{id}", RequestPredicates.accept(MediaType.ALL), userHandler::getUser)
                .PUT("/user", RequestPredicates.accept(MediaType.ALL), userHandler::updateUser)
                .build();
        
    }

}

2.将参数3 处理响应数据,专门写一个类处理逻辑部分

这个类中的方法必须是返回ServerResponse ,因为参数3 需要的是RouterFunction<ServerResponse>

java 复制代码
@Service // 标记这是一个服务类
public class UserHandler {


    public  ServerResponse getUser(ServerRequest request) {
        return ServerResponse.ok().body("User " + request.pathVariable("id"));
    }

    public ServerResponse updateUser(ServerRequest serverRequest) {
        return ServerResponse.ok().body("Update User " + serverRequest.body(User.class));
    }
}

MSS整合

SpringBoot整合 Spring.SpringMVc MyBatis进行数据访问场景开发

1.创建项目导入需要mysql驱动包,mybatis包

XML 复制代码
     <!-- web场景 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>
        <!-- 数据库场景 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- mybatis场景 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- lombok场景 用于bean -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

2.在配置文件中application.properties进行配置数据库

XML 复制代码
spring.application.name=demo4

// 数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3.写数据库相对应的bean对象

java 复制代码
@Data // getter setter toString
public class User {
    private int id;
    private String name;
    private int age;
}

4.写mapper接口,写业务查询方法。方法中传递的每一个参数我们都使用@Param进行签名,在sql语句中使用签名参数进行取值。

java 复制代码
public interface  Usermapping {


    /**
     * 根据id查询用户
     * 每一个mapper方法都有一个标签SQL语句对应
     *所有的参数都使用@Param("xx")进行签名,使用指定签名的名称在SQL中取值
     * @param id
     * @return
     */
    public User getUserById(@Param("id") int id);

}

点击提示会自动在mapper.xml文件中生成相应的sql语句

安装插件MyBatisX,在写好mapper接口后可以选择提示自动生成

安装好插件后,在写好mapper接口后可以选择提示自动生成mapper.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.haha.demo4.mapper.Usermapping">

    <!-- 根据id查询用户  -->
    <select id="getUserById" resultType="com.haha.demo4.bean.User">
        select * from user where id=#{id}
    </select>
</mapper>

以上我们写的mapper接口要让mybatis知道在哪里,需要在主入口类上添加注解@MpperScan 扫描到我们mapper接口。

java 复制代码
@MapperScan("com.haha.demo4.mapper") // 扫描mapper接口


@SpringBootApplication
public class Demo4Application {

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

}

而且还要在application.properties配置xxxxmapper.xml文件在哪里。

XML 复制代码
#MyBatis的配置项
mybatis.mapper-locations=classpath:/mapper/*.xml

5.在写一个Controller方法,请求获取数据

java 复制代码
@RestController
public class UserController {
    
    @Autowired // 自动注入接口
    Usermapping usermapping;
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") int id){
       
        return  usermapping.getUserById( id);
    }
}

注意:如果Bean中写的字段名称和数据库中不相同时候,

解决方式一:使用取别名方式

解决方式二:如果名称符合驼峰命名,可以开启配置

java 复制代码
#打开驼峰命名规则配置
mybatis.configuration.map-underscore-to-camel-case=true

springboot3基本特性

springApplication

自定义banner

在application.properties 中配置banner的位置

java 复制代码
spring.banner.location=classpath:banner.txt

把我们只做的banner复制到banner.txt中即可。

自定义springApplication

方式一:将原来的一句分解成多句,启动进行中间设置

java 复制代码
@SpringBootApplication
public class Demo4Application {

    public static void main(String[] args) {

      
        SpringApplication app = new SpringApplication(Demo4Application.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }

方式二:使用SpringApplicationBuilder 对象进行流式编写

java 复制代码
@SpringBootApplication
public class Demo4Application {

    public static void main(String[] args) {

        
        new SpringApplicationBuilder()
                .main(Demo4Application.class)
                .sources(Demo4Application.class)
                .bannerMode(Banner.Mode.OFF)
                .run(args);
    }

}

@profile("标记")

容器中的组件上都可以使用它。

使用方法:

1.在类上或方法上添加注解,可以标注多个标记**@profile({"标记","标记"})**

2.使用注解生效,在application.properties配置文件中进行激活注解

java 复制代码
spring.profiles.active=dev,test

设置多个表示多个一起生效。

java 复制代码
#包含指定环境,不管你激活哪个环境,这个都要有。总是要生效的环境
spring.profiles.include=dev,test

命令行激活: 当打包成jar包后可以在后面使用 - - 加配置文件中的配置内容

java 复制代码
java-jarxxx.jar --spring.profiles.active=dev

springboot3核心原理

事件和监听器

1.生命周期监听

作用:用于监听应用的生命周期

自定义监听器(SpringApplicationRunListener)

1.编写一个类实现SpringApplicationRunListener 接口,重写 里面所有方法

java 复制代码
public class MyApplicationListenner implements SpringApplicationRunListener {
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("=====starting正在启动=======");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        System.out.println("==========environmentPrepared环境准备完成============");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("==========contextPrepared上下文ioc容器准备完成============");
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("==========contextLoaded上下文ioc容器加载完成============");
    }

    @Override
    public void started(ConfigurableApplicationContext context,  Duration timeTaken) {
        System.out.println("==========started启动完成============");
    }

    @Override
    public void ready(ConfigurableApplicationContext context,  Duration timeTaken) {
        System.out.println("==========ready准备就绪============");
    }

    @Override
    public void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("==========failed启动失败============");
    }
}

2.在META-INF/spring.factories中配置org.springframework.boot.SpringApplicationRunListener=自己实现的类,还可以指定一个有参构造器,接受两个参数(springApplication application,String\[\] args)

java 复制代码
org.springframework.boot.SpringApplicationRunListener=com.haha.demo.listenner.MyApplicationListenner

运行后结果:

java 复制代码
已连接到地址为 ''127.0.0.1:52958',传输: '套接字'' 的目标虚拟机

=====starting正在启动=======

==========environmentPrepared环境准备完成============

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v4.1.0)

==========contextPrepared上下文ioc容器准备完成============

2026-08-09T22:03:59.946+08:00  INFO 15712 --- [demo] [           main] com.haha.demo.DemoApplication            : Starting DemoApplication using Java 26.0.2 with PID 15712 (C:\Users\LuoDeLiang\IdeaProjects\demo\target\classes started by LuoDeLiang in C:\Users\LuoDeLiang\IdeaProjects\demo)
2026-08-09T22:03:59.953+08:00  INFO 15712 --- [demo] [           main] com.haha.demo.DemoApplication            : No active profile set, falling back to 1 default profile: "default"

==========contextLoaded上下文ioc容器加载完成============

2026-08-09T22:04:00.940+08:00  INFO 15712 --- [demo] [           main] o.s.boot.tomcat.TomcatWebServer          : Tomcat initialized with port 8080 (http)
2026-08-09T22:04:00.956+08:00  INFO 15712 --- [demo] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2026-08-09T22:04:00.957+08:00  INFO 15712 --- [demo] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/11.0.22]
2026-08-09T22:04:01.017+08:00  INFO 15712 --- [demo] [           main] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 1002 ms
2026-08-09T22:04:01.461+08:00  INFO 15712 --- [demo] [           main] o.s.boot.tomcat.TomcatWebServer          : Tomcat started on port 8080 (http) with context path '/'
2026-08-09T22:04:01.467+08:00  INFO 15712 --- [demo] [           main] com.haha.demo.DemoApplication            : Started DemoApplication in 2.139 seconds (process running for 3.204)

==========started启动完成============
==========ready准备就绪============

还有以下每个阶段感知接口:

SpringBoot基于事件驱动开发

以前模式

使用发布订阅模式

1.事件发布器实现ApplicationEventPublisherAware 获取到底层发布对象

类上添加注解,将对象添加到容器中@Component @Service等

java 复制代码
@Component 
public class EventPublisher implements ApplicationEventPublisherAware {
    
    // 底层发布者对象
    private ApplicationEventPublisher applicationEventPublisher;
    
    /**
     * 获取底层发布者对象
     * @param applicationEventPublisher
     */
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher=applicationEventPublisher;
    }
    
    /**
     * 发布事件
     * @param event
     */
    public void publish(ApplicationEvent  event){
        // 发布事件
        applicationEventPublisher.publishEvent(event);
    }
}

2.定义发布的事件,继承ApplicationEvent

我们写的发布方法 publish(ApplicationEvent event) 参数是ApplicationEvent

java 复制代码
// 自定义事件类:登录事件,继承 Spring 的 ApplicationEvent
public class LogingEvent extends ApplicationEvent {
    // 使用构造方法,传入用户对象 数据源Use对象作为事件源存入父类
    //父类内部保存这个 source,后面监听方可以通过 event.getSource() 获取到 User 对象
    public LogingEvent(User sourceUser) {
        super(sourceUser);
    }
}

3.在控制器方法中发布事件

java 复制代码
@RestController
public class UserController {

    @Autowired // 自动注入接口
    Usermapping usermapping;
    
    @Autowired // 自动注入发布者
    EventPublisher eventPublisher;
    
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") int id){

        User user = usermapping.getUserById( id);
        //准备好事件
        LogingEvent logingEvent = new LogingEvent(user);
        //发布事件
        eventPublisher.publish(logingEvent);
        
        return  usermapping.getUserById( id);
    }
}

4.写监听器接收这个事件,并使用注解,添加对象到容器中@Component @Service等

方式一:实现监听器 ApplicationListener< ApplicationEvent>

java 复制代码
@Component 
public class LoginListener implements ApplicationListener<LogingEvent> {
    @Override
    public void onApplicationEvent(LogingEvent event) {
        User source = (User) event.getSource();
        System.out.println("用户:" + source.getName() + " 存在了");
    }
}

方式二:使用@EventListener 注解

java 复制代码
@Component
public class TestListener {
    
    @EventListener
    public void handleLoginEvent( LogingEvent event){
        User source = (User) event.getSource();
        System.out.println("用户:" + source.getName() + " 存在了");
      
    }
}

这两种方式都可以写成service,如果后面需要增加业务只需要订阅LogingEvent 事件,并添加监听注解即可。

例如:

java 复制代码
@Service
public class ServiceUser {
    
    @EventListener
    public void GetUser( LogingEvent event){
        User source = (User) event.getSource();
        System.out.println("用户:" + source.getName() + " 存在了");
      
    }
}

自定义Starter

核心作用

  1. 代码复用,消除重复配置 多个项目需要同一套功能,不用每个项目都写一遍 Bean、配置类、导入一堆 jar。

举例:封装登录事件、工具类、mybatis 扩展、自定义加密解密、统一日志、统一返回封装。 引入 starter,直接注入 Bean 就能用。

  1. 自动装配,开箱即用 借助 META‑INF/spring/org.springframework.boot.autoconfigure.imports 文件,项目引入依赖后,SpringBoot 自动加载配置类,不需要手动写 @EnableXXX(也可以做开关注解)。 不需要开发者手动 new 对象、写 @Bean。

  2. 业务能力封装、对外提供组件 把内部通用业务逻辑封装成 starter,团队内各个业务项目直接引入,统一业务规则。 比如:统一用户鉴权组件、消息推送组件、流程工具组件。

  3. 统一版本管理,解决依赖冲突 Starter 内部管理好所需要的第三方 jar 版本,使用方不用关心各个子依赖版本,减少版本冲突问题。

自定义starter步骤:

1.创建自定义starter项目,引入spring-boot-starter基础依赖

2.编写模块功能,引入模块所有需要的依赖。编写xxxAutoConfiguration自动配置类

3.编配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.impo
rts
指定启动需要加载的自动配置

4.打包成 jar,其他项目引入 maven 依赖。其他项目引入即可使用

5.项目启动,SpringBoot 读取 imports 文件,自动创建里面定义的 Bean,直接 @Autowired 注入使用

自定义配置文件中属性提示

java 复制代码
 <!-- 配置属性文件提示 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

示例:

1.创建一项目模块,把公共部分代码抽取出来放到源代码根目录下:

controller代码:

java 复制代码
@RestController
public class UserController {

    @Autowired
    UserService userService; //注入服务层对象

    @GetMapping("/user")
    public String getUser() {
        //调用服务层获取数据,返回结果给浏览器
       return  userService.getUser();

    }
}

services服务层代码:

java 复制代码
@Service
public class UserService {

    //注入属性对象
    @Autowired
     UserProperties userProperties; 

    public String getUser() {
        //调用属性对象的方法,返回属性设置值
        return userProperties.getUsername() + " ------------" + userProperties.getAge();

    }
}

属性类:用于在application.properties 中配置

@ConfigurationProperties(prefix = "user")

@Configuration

java 复制代码
@ConfigurationProperties(prefix = "user")
@Configuration
@Data
public class UserProperties {

    private String username;
    private int age;
}

2.导入这个项目必须要使用到的依赖包

XML 复制代码
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.删除这个模块中的main方法主函数类

4.写一个自动配置类 xxxAutoConfiguration

由于别人的项目导入我们的依赖包后,springboot只能扫描加载自己classpath目录下的文件,扫描不到我们的包,所以我们需要在我们的自动配置类中导入我们需要的所有组件

java 复制代码
@Configuration
@Import({UserService.class, UserController.class, UserProperties.class})
public class UserAutoConfiguration {
}

5.现在我们自己的starten,就是一个半自动的,只要别人导入我们的包,在主程序类上配置@import(UserAutoConfiguration.class) 就能使用

自定义一个注解

我们还可以在改变成别人导入我们依赖,添加一个注解@EnableUser 就能使用

java 复制代码
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时保留
@Target(ElementType.TYPE) // 表示注解可以用于类、接口、枚举
@Documented // 表示注解可以被文档化
@Import(UserAutoConfiguration.class) //导入自己自动配置类
public @interface EnableUser {
    
}

现在使用导入包后,只需要在主入口类上添加注解@EnableUser

终极处理方式:导入包后自动导入全部组件

在资源目录下创建META-INF/spring/文件夹,并放入名称为org.springframework.boot.autoconfigure.AutoConfiguration.impo
rts 文件,在文件中写上加载的自动配置类路径

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.impo
rts

相关推荐
Java内核笔记1 小时前
容错能力进入 spring-core:Spring Boot 4 原生重试机制全解析
java·后端
未秃头的程序猿1 小时前
虚拟线程上线一周后翻车了——pinning问题排查实录
java·后端·架构
VALENIAN瓦伦尼安教学设备1 小时前
ASHOOTER激光对中仪如何通过颜色确定调整是否合适
数据库·嵌入式硬件·算法
Wang's Blog1 小时前
AI Agent白手起家58: 项目可观测性——用 LangSmith 实现全链路追踪
数据库·人工智能
wuminyu1 小时前
JDK21解决虚拟线程IO阻塞原理剖析
java·linux·c语言·jvm·c++
带刺的坐椅1 小时前
Solon AOT & Native:三段式编译,从 Java 到原生可执行文件
java·aot·solon·native
LccKyI1 小时前
C#学习day06(方法/函数及其关键字,附思维导图)
经验分享·学习·c#
程序员良辰1 小时前
【TongWeb8】使用 Crontab 定时重启和检测 TongWeb 服务
java·中间件·tomcat
xian_wwq2 小时前
【学习笔记】Loop Engineering,从手动提示到目标驱动自动化-13/16
笔记·学习·自动化
SL_staff2 小时前
JVS数字底座实践:如何复用企业文档能力快速构建知识类应用
java·数据库·程序员