
springboot提供了大量的自动配置类,对于springmvc而言,通过配置application.yml设置一些参数就可以实现比较自适应的配置了。如果需要详细配置,就必须了解如何在springboot的环境下添加自己的配置、并选择是否仍然使用springboot的自动配置项。
主要配置类和注解
springmvc的一切配置源于配置类WebMvcConfigurationSupport
,该类实现了ApplicationContextAware
、ServletContextAware
这两个接口,即同时注入了spring上下文和servlet上下文。具体可以参考类注释。
注解@EnableWebMvc
导入了这个配置类:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
复制代码
DelegatingWebMvcConfiguration
是WebMvcConfigurationSupport
的子类:
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
// ...
}
复制代码
该类实现了多个WebMvcConfigurer
的配置,通过添加Autowired
注解在setConfigurers
方法上,注入了系统中启用到的所有WebMvcConfigurer
组件,然后按序执行每个实例的配置方法。其顺序由spring容器注入时决定,注解@Order
可以影响到注入时目标组件的顺序,比如WebMvcAutoConfiguration
中的静态内部类WebMvcAutoConfigurationAdapter
就标注了@Order(0)
,表示该组件排在列表的首位。
springboot的mvc自动配置
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration { ... }
复制代码
通过标注上的三个@Conditional
注解,该类实现了web环境中的自动配置。
WebMvcAutoConfigurationAdapter
是其静态内部类,该类真正提供了springboot mvc自动配置的能力,通过引入的ResourceProperties
与WebMvcProperties
两个属性配置类,该类能够根据application.yml中定义的各种springmvc配置来实现自定义自动配置。
比如该类下的configureMessageConverters
方法:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> converters
.addAll(customConverters.getConverters()));
}
复制代码
该类默认导入了多个根据HTTP媒体类型来区分的消息转换器,根据具体的媒体类型来确定选择哪一个与之匹配的转换器。
如何添加自定义的配置
添加自定义消息转换器
默认的消息转换器中包含了Jackson的转换器:MappingJackson2HttpMessageConverter
,但是该类无法实现日期格式的通用转换(通常使用的日期字符串格式为yyyy-MM-dd HH:mm:ss
,但是Jackson无论是对Date
还是LocalDateTime
都没有使用到这一种格式),所以就必须使用自定义的WebMvcConfigurer
,然后覆盖configureMessageConverters
方法,添加上自己的配置:
/**
* @author Gmw
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
gen.writeString(formatter.format(value));
}
});
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getText();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return formatter.parse(value);
} catch (ParseException e) {
throw ExceptionAdvice.error("日期格式错误,要求格式:yyyy-MM-dd HH:mm:ss");
}
}
});
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(javaTimeModule);
// 未使用EnableWebMvc注解,清空掉springboot自动配置的一大串默认转换器
converters.clear();
converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
}
}
复制代码
要注意的是,该配置类未标注@EnableWebMvc
注解,所以springboot的mvc自动配置类也会生效。
注意这一段代码:
// 未使用EnableWebMvc注解,清空掉springboot自动配置的一大串默认转换器
converters.clear();
converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
复制代码
因为在DelegatingWebMvcConfiguration
中,添加转换器的实现如下:
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.configureMessageConverters(converters);
}
复制代码
而WebMvcConfigurerComposite
中的实现如下:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configureMessageConverters(converters);
}
}
复制代码
每一个WebMvcConfigurer
配置组件的操作都是对传入的入参converters
进行增减操作。而springboot提供的自动配置类被标注为@Order(0)
,即在执行到我们自己写的方法中时,入参的converters
已经具有了默认提供的多种转换器,如果不清理到这些默认转换器,就不能保证我们自己添加的转换器生效,具体代码参考:
- 负责处理请求体反序列化为对象的
AbstractMessageConverterMethodArgumentResolver
- 负责处理响应体序列化的
AbstractMessageConverterMethodProcessor
添加其他配置
覆盖WebMvcConfigurer提供的方法即可实现其他配置比如添加视图处理器、静态资源处理器、CORS跨域处理器等等。
原创文章,作者:睿达君,如若转载,请注明出处:https://zrrd.net.cn/2164.html