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,再以其资源作为标签页的图标

自定义静态资源规则

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

yaml 复制代码
#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配置方式如下:
ini 复制代码
# 改变路径匹配策略:
# 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;
}

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

ini 复制代码
# 开启基于请求参数的内容协商功能。 默认参数名: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);

编写配置

yaml 复制代码
#新增一种媒体类型
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

相关推荐
ajsbxi6 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
StayInLove24 分钟前
G1垃圾回收器日志详解
java·开发语言
对许28 分钟前
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“
java·log4j
无尽的大道32 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
小鑫记得努力41 分钟前
Java类和对象(下篇)
java
binishuaio1 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE1 小时前
【Java SE】StringBuffer
java·开发语言
老友@1 小时前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose
颜淡慕潇1 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
wrx繁星点点1 小时前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式