web场景,默认配置:
- 包含了 ContentNegotiatingViewResolver 和 BeanNameViewResolver 组件,方便视图解析
- 默认的静态资源处理机制: 静态资源放在 static 文件夹下即可直接访问
- 自动注册 了 Converter ,GenericConverter,Formatter 组件,适配常见数据类型转换 和格式化需求
- 支持 HttpMessageConverters ,可以方便返回 json等数据类型
- 注册 MessageCodesResolver,方便国际化及错误消息处理
- 支持 静态 index.html
- 自动使用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:
HiddenHttpMethodFilter
:用于页面表单提交Rest请求(GET、POST、PUT、DELETE)FormContentFilter
: 表单内容Filter,GET(数据放URL后面)、POST(数据放请求体)请求可以携带数据,PUT、DELETE 的数据会被忽略。配置了FormContentFilter
后PUT、DELETE的数据就不会被忽略WebMvcAutoConfiguration给容器中放了
WebMvcConfigurer
组件,给SpringMVC添加各种定制功能(用手自一体方式开发时会派上用场)
WebMvcConfigurer接口提供了SpringMVC底层的所有组件入口
所有的功能最终会和配置文件进行绑定
- WebMvcProperties:和
spring.mvc
配置绑定- 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 中进行了定义:
- 在静态资源目录下找 index.html
- 没有就在 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 组件。配置的底层行为都会生效
- WebMvcAutoConfiguration 是一个自动配置类,它里面有一个
EnableWebMvcConfiguration
EnableWebMvcConfiguration
继承于DelegatingWebMvcConfiguration
,这两个都生效DelegatingWebMvcConfiguration
利用 DI 把容器中 所有WebMvcConfigurer
注入进来- 当调用
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/json
、text/xml
、text/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