SpringBoot3框架,Web开发(上)

web场景,默认配置:

  1. 包含了 ContentNegotiatingViewResolver 和 BeanNameViewResolver 组件,方便视图解析
  2. 默认的静态资源处理机制: 静态资源放在 static 文件夹下即可直接访问
  3. 自动注册Converter ,GenericConverter,Formatter 组件,适配常见数据类型转换格式化需求
  4. 支持 HttpMessageConverters ,可以方便返回 json等数据类型
  5. 注册 MessageCodesResolver,方便国际化及错误消息处理
  6. 支持 静态 index.html
  7. 自动使用ConfigurableWebBindingInitializer,实现消息处理、数据绑定、类型转化、数据校验等功能

Web开发的方式

  • 如果想保持 boot mvc 的默认配置 ,并且自定义更多的 mvc 配置,如:interceptors , formatters , view controllers 等。可以使用@Configuration注解添加一个 WebMvcConfigurer 类型的配置类,并不要标注 @EnableWebMvc
  • 如果想保持 boot mvc 的默认配置,但要自定义核心组件实例,比如:RequestMappingHandlerMapping, RequestMappingHandlerAdapter, 或ExceptionHandlerExceptionResolver,给容器中放一个 WebMvcRegistrations 组件即可
  • 如果想全面接管 Spring MVC,@Configuration 标注一个配置类,并加上 @EnableWebMvc注解,实现 WebMvcConfigurer 接口

web开发有三种方式:

方式 用法 效果
全自动 直接编写控制器逻辑 全部使用自动配置默认效果
手自一体 @Configuration + 配置WebMvcConfigurer+配置 WebMvcRegistrations 不要标注 @EnableWebMvc 保留自动配置效果 手动设置部分功能 定义MVC底层组件
全手动 @Configuration + 配置WebMvcConfigurer 标注 @EnableWebMvc 禁用自动配置效果 全手动设置

如果有定制化需求,给容器中写一个配置类,在配置类上加上@Configuration注解,并不要标注@EnableWebMvc,让这个配置类实现WebMvcConfigurer接口,就可以实现手自一体的效果

WebMvcAutoConfiguration

  • WebMvcAutoConfiguration会给项目配置两个Filter:
    1. HiddenHttpMethodFilter :用于页面表单提交Rest请求(GET、POST、PUT、DELETE)
    2. FormContentFilter: 表单内容Filter,GET(数据放URL后面)、POST(数据放请求体)请求可以携带数据,PUT、DELETE 的数据会被忽略。配置了FormContentFilter 后PUT、DELETE的数据就不会被忽略
  • WebMvcAutoConfiguration给容器中放了WebMvcConfigurer组件,给SpringMVC添加各种定制功能(用手自一体方式开发时会派上用场)
    1. WebMvcConfigurer接口提供了SpringMVC底层的所有组件入口
    2. 所有的功能最终会和配置文件进行绑定
      1. WebMvcProperties:和 spring.mvc配置绑定
      2. WebProperties:和 spring.web 配置绑定

静态资源

静态资源规则

  • 规则一:访问: /webjars/**路径就去 classpath:/META-INF/resources/webjars/下找资源.
  • 规则二:访问: /**路径就去 静态资源默认的四个位置找资源
    • classpath:/META-INF/resources/
    • classpath:/resources/
    • classpath:/static/
    • classpath:/public/
  • 规则三:静态资源默认都有缓存规则的设置
    • 如果浏览器访问了一个静态资源,会将其缓存,如果服务器中这个资源没有发生变化,下次访问时,可以直接使用其浏览器中的该静态资源的缓存,而不用给服务器发请求。
    • 有几个关于缓存的配置(直接通过配置文件spring.web
      • cachePeriod:缓存周期,即多久不用找服务器再请求该静态资源。默认没有缓存周期,以秒为单位。
      • cacheControl:HTTP缓存,即会存储与请求相关联的响应,并将存储的响应复用于后续请求
      • useLastModified:是否使用最后一次修改的资源,配合HTTP缓存使用,默认为true。即以最后一次修改资源的时间和使用其缓存资源进行对比,来判断是否要再次请求。

欢迎页规则

欢迎页规则在 WebMvcAutoConfiguration 中进行了定义:

  1. 静态资源目录下找 index.html
  2. 没有就在 templates下找index模板页

Favicon

Favicon是代表浏览器标签页的图标的,浏览器会到服务器静态资源目录下找 favicon.ico,再以其资源作为标签页的图标

自定义静态资源规则

在配置文件中自定义静态资源规则:

java 复制代码
#1、spring.web:
# 1.配置国际化的区域信息
# 2.静态资源策略(开启、处理链、缓存)

#开启静态资源映射规则
spring.web.resources.add-mappings=true

#设置缓存
spring.web.resources.cache.period=3600
##缓存详细合并项控制,覆盖period配置:
## 浏览器第一次请求服务器,服务器告诉浏览器此资源缓存7200秒,7200秒以内的所有此资源访问不用发给服务器请求,7200秒以后发请求给服务器
spring.web.resources.cache.cachecontrol.max-age=7200
## 共享缓存
spring.web.resources.cache.cachecontrol.cache-public=true
#使用资源 last-modified 时间,来对比服务器和浏览器的资源是否相同没有变化。相同返回 304
spring.web.resources.cache.use-last-modified=true

#自定义静态资源文件夹位置
spring.web.resources.static-locations=classpath:/a/,classpath:/b/,classpath:/static/

#2、 spring.mvc
## 2.1. 自定义webjars路径前缀
spring.mvc.webjars-path-pattern=/wj/**
## 2.2. 静态资源访问路径前缀
spring.mvc.static-path-pattern=/static/**

在配置类中自定义静态资源规则:(第一种写法)

java 复制代码
@Configuration//这是一个配置类
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//保留以前规则
//自己写新的规则。
registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/a/","classpath:/b/")
                .setCacheControl(CacheControl.maxAge(1180, TimeUnit.SECONDS));
    }
}

(第二种写法)

java 复制代码
@Configuration //这是一个配置类,给容器中放一个 WebMvcConfigurer 组件,就能自定义底层
public class MyConfig  /*implements WebMvcConfigurer*/ {

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                registry.addResourceHandler("/static/**")
                        .addResourceLocations("classpath:/a/", "classpath:/b/")
                        .setCacheControl(CacheControl.maxAge(1180, TimeUnit.SECONDS));
            }
        };
    }

}

容器中只要有一个 WebMvcConfigurer 组件。配置的底层行为都会生效

  1. WebMvcAutoConfiguration 是一个自动配置类,它里面有一个 EnableWebMvcConfiguration
  2. EnableWebMvcConfiguration继承于 DelegatingWebMvcConfiguration,这两个都生效
  3. DelegatingWebMvcConfiguration利用 DI 把容器中 所有 WebMvcConfigurer 注入进来
  4. 当调用 DelegatingWebMvcConfiguration的方法配置底层规则,而DelegatingWebMvcConfiguration调用所有 WebMvcConfigurer的配置底层方法。

路径匹配

Ant风格路径用法(AntPathMatcher)

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

  • *:表示任意数量的字符。
  • ?:表示任意一个字符
  • ****:**表示任意数量的目录。
  • {}:表示一个命名的模式占位符
  • \]:表示**字符集合**,例如\[a-z\]表示小写字母,\[a-z\]+表示任意个小写字符

PathPatternParser

PathPatternParser比起Ant,效率更高,兼容 AntPathMatcher语法,并支持更多类型的路径模式,即使用PathPatternParser路径匹配时还能继续使用Ant的语法规则,但是有一点有改变:

  • PathPatternParser用**表示任意层目录时**,** 只能将**放在最末尾
  • 如果要将**放在路径中间而不是末尾,需要将路径匹配改回Ant,改回Ant配置方式如下:
java 复制代码
# 改变路径匹配策略:
# ant_path_matcher 老版策略;
# path_pattern_parser 新版策略;
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
  • SpringBoot3默认是PathPatternParser的匹配规则

内容协商

内容协商能让一套系统适配多端数据返回

多端内容适配

  • SpringBoot 多端内容适配
    • 基于请求头内容协商 :(默认开启)
      • 客户端向服务端发送请求,携带HTTP标准的Accept请求头
        • Accept : application/jsontext/xmltext/yaml
        • 服务端根据客户端请求头期望的数据类型 进行动态返回
    • 基于请求参数内容协商:(需要开启)
      • 发送请求 GET /projects/spring-boot?format=json
      • 匹配到 @GetMapping("/projects/spring-boot")
      • 根据参数协商 ,优先返回 json 类型数据【需要开启参数匹配设置
      • 发送请求 GET /projects/spring-boot?format=xml,优先返回 xml 类型数据

如果要返回xml数据格式:

  • 导入支持写出xml内容的依赖:
XML 复制代码
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
  • 在对应实体类上标注@JacksonXmlElement注解:
java 复制代码
@JacksonXmlRootElement  // 可以写出为xml文档
@Data
public class Person {
private Long id;
private String userName;
private String email;
private Integer age;
}

开启基于请求参数的内容协商:

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

内容协商原理

可以通过定制HttpMessageConverter类来实现多端内容协商,通过编写WebMvcConfigurer提供的configureMessageConverters底层,来修改底层的MessageConverter,以实现定制多端内容协商。

  • @ResponseBody注解由HttpMessageConverter处理
    • 请求来到DispatcherServlet的doDispatch方法进行处理
    • 在HandlerMapping中校验成功后,来到HandlerAdapter,利用HandlerAdapter调用handler方法(使用反射的方法invokeHandlerMethod()来执行目标方法)
    • 目标方法执行之前,准备好了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler
      • HandlerMethodArgumentResolver:参数解析器,确定目标方法的每个参数值
      • HandlerMethodReturnValueHandler:返回值处理器,确定目标方法的返回值怎么处理
    • invokeAndHandler方法真正执行目标方法,目标方法执行完成,会返回返回值对象
    • 找到返回值处理器HandlerMethodReturnValueHandler
    • 最终找到RequestResponseBodyMethodProcessor,能处理标注了@RequestBody注解的方法
    • RequestResponseBodyMethodProcessor调用writeWithMessageConverters,利用MessageConverter将返回值写出去
  • HttpMessageConverter会先进行内容协商
    • 遍历所有的MessageConverter,找到目标内容类型的数据
    • 要返回json形式的数据的话,MappingJackson2HttpMessageConverter支持写出json数据,最后写出数据

几种默认HttpMessageConverters

WebMvcAutoConfiguration提供几种默认HttpMessageConverters

  • EnableWebMvcConfiguration通过 addDefaultHttpMessageConverters添加了默认的MessageConverter;如下:
    • ByteArrayHttpMessageConverter: 支持字节数据读写
    • StringHttpMessageConverter: 支持字符串读写
    • ResourceHttpMessageConverter:支持资源读写
    • ResourceRegionHttpMessageConverter: 支持分区资源写出
    • AllEncompassingFormHttpMessageConverter:支持表单xml/json读写
    • MappingJackson2HttpMessageConverter: 支持请求响应体Json读写

系统提供默认的MessageConverter 功能有限,仅用于json或者普通返回数据。额外增加新的内容协商功能,必须增加新的HttpMessageConverter

自定义内容返回

以导入yaml格式为例:

  • 导入依赖
XML 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
  • 将要返回的对象以yaml形式写出
java 复制代码
      	Person person = new Person();
        person.setId(1L);
        person.setUserName("张三");
        person.setEmail("aaa@qq.com");
        person.setAge(18);

        //取消文档的开始标记(disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER))
        YAMLFactory factory = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
        ObjectMapper mapper = new ObjectMapper(factory);

        String s = mapper.writeValueAsString(person);

编写配置

java 复制代码
#新增一种媒体类型
spring.mvc.contentnegotiation.media-types.yaml=text/yaml

配置类方式

自定义Converter

java 复制代码
public class MyYamlHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    private ObjectMapper objectMapper = null;
    public MyYamlHttpMessageConverter(){
//告诉SpringBoot这个MessageConverter支持哪种媒体类型
super(new MediaType("text","yaml", Charset.forName("UTF-8")));
        YAMLFactory factory = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
        this.objectMapper = new ObjectMapper(factory);

    }
    @Override
    protected boolean supports(Class<?> clazz) {//是否支持指定类型的转化
//可以在方法内进行类型判断,返回相应的true和false
return true;
    }

    @Override//指定请求中的数据如何转化
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override//指定响应中的数据如何转化
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try (OutputStream body = outputMessage.getBody()){
            this.objectMapper.writeValue(body,o);
        }
    }
}

最后在WebMvcConfigurer配置类中配置其Converter即可

java 复制代码
@Bean
public WebMvcConfigurer webMvcConfigurer(){
    return new WebMvcConfigurer() {
        @Override //配置一个能把对象转为yaml的messageConverter
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters{
            converters.add(new MyYamlHttpMessageConverter());
        }
    };
}

配置步骤:

  • 配置媒体类型支持:
  • 编写对应的HttpMessageConverter,要告诉Boot这个支持的媒体类型
  • 把MessageConverter组件加入到底层
    • 容器中放一个WebMvcConfigurer 组件,并配置底层的MessageConverter
相关推荐
一只叫煤球的猫37 分钟前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9651 小时前
tcp/ip 中的多路复用
后端
bobz9651 小时前
tls ingress 简单记录
后端
皮皮林5512 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友2 小时前
什么是OpenSSL
后端·安全·程序员
bobz9653 小时前
mcp 直接操作浏览器
后端
前端小张同学5 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook5 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康6 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在6 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net