错误使用@EnableWebMvc带来的配置失效问题
@EnableWebMvc带来的一些坑
最近在出于一些原因在项目中使用了@EnableWebMvc这个注解,但没有正确使用,后来发现Java对象中时间类的序列化格式出现了问题,变成了一个数字的list(形如[2022, 12, 21]),前端无法读取导致系统无法正常运行。
通过查看@EnableWebMvc的源码,可以发现该注解就是为了引入一个DelegatingWebMvcConfiguration 配置类,而DelegatingWebMvcConfiguration又继承于WebMvcConfigurationSupport。也就是说,如果我们使用@EnableWebMvc就相当于导入了WebMvcConfigurationSupport类,这个时候,Spring Boot的自动装配就不会发生了,我们能用的,只有WebMvcConfigurationSupport提供的若干个配置。在自动配置类 WebMvcAutoConfiguration 上有条件注解
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
那若是我们需要自己定制一些项目的设置,可以通过以下方式
@EnableWebMvc + extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
extends WebMvcConfigurationSupport,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
extends WebMvcConfigurationAdapter/WebMvcConfigurer,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot的@EnableAutoConfiguration中的设置
其实官方也说明了
Spring Boot 默认提供Spring MVC 自动配置,不需要使用@EnableWebMvc注解
如果需要配置MVC(拦截器、格式化、视图等)请使用添加@Configuration并实现WebMvcConfigurer接口.不要添加@EnableWebMvc注解。
@EnableWebMvc 只能添加到一个@Configuration配置类上,用于导入Spring Web MVC
所以当我们真的需要修改这些配置类的某些内容,比如说默认主页、序列化格式等,最好以override的方式进行,只对想修改的方法进行覆盖,这样其他方法功能不受影响。
回到项目中,问题出现的原因就在于与序列化相关的类没有被正常加载,只调用了最基本的GET方法。在这种情况下,除了使用正确的方式使用@EnableWebMvc之外,我们还可以自定义新的配置类来加载对象的序列化器,来达到一样的效果。
配置接口的序列化器
@Configuration
public class AWebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
/*
boolean flag = false;
for (HttpMessageConverter converter : converters){
if (converter instanceof FastJsonHttpMessageConverter) {
flag = true;
break;
}
}
*/
converters.removeIf(httpMessageConverter -> httpMessageConverter instanceof FastJsonHttpMessageConverter);
// 需要重新加入jackson的转换器,该处的objectMapper已经在配置中注册了
ObjectMapper objectMapper = new ObjectMapper();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 1111 HH-mm-ss");
objectMapper.setDateFormat(simpleDateFormat);
converters.add(0, new MappingJackson2HttpMessageConverter(objectMapper));
ObjectMapper objectMapper2 = new ObjectMapper();