描述
springboot
项目中,在application.properties
中配置了spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
,在我的理解中,如果接口接口返回中有Date
类型字段,应该默认返回的是如2023-03-13 01:02:03
这种格式的,但是实际发现是个long
时间戳(或者其他格式的时间)。那么,问题出在哪里了呢。
复现
问题定位
google了一下,发现是@EnableWebMvc
影响的。但是为什么会影响到,不太理解。所以得翻翻代码。
@EnableWebMvc
这个注解会@Import(DelegatingWebMvcConfiguration.class)
,DelegatingWebMvcConfiguration
继承WebMvcConfigurationSupport
。这就导致@EnableAutoConfiguration
自动加载类时忽略了WebMvcAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 此时已经有了WebMvcConfigurationSupport,所以 WebMvcAutoConfiguration 不会加载了
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
正常场景下,WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#configureMessageConverters(List<HttpMessageConverter<?>> converters) 会引入 converts,但是此时因为没加载,所以没引入。然后走了WebMvcConfigurationSupport#addDefaultHttpMessageConverters(this.messageConverters),这里是加入了默认的converts。默认的不会使用全局配置,所以全局配置没生效。
解决
@Configuration
@Slf4j
public class JacksonConfig implements WebMvcConfigurer {
@Autowired
private ObjectMapper objectMapper;
/**
* @EnableWebMvc 使用该注解后,需要手动配置 addInterceptors() 和 addResourceHandlers()
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("JacksonConfig");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}).addPathPatterns("/**")
.excludePathPatterns("/swagger-ui.html")
.excludePathPatterns("/null/**")
.excludePathPatterns("/swagger-resources/**")
.excludePathPatterns("/swagger/**")
.excludePathPatterns("/webjars/**")
.excludePathPatterns("/v2/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 填充全局 objectMapper
* https://stackoverflow.com/questions/45734108/spring-boot-not-using-configured-jackson-objectmapper-with-enablewebmvc
* @param converters
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.stream().filter(p -> p instanceof MappingJackson2HttpMessageConverter)
.map(p -> (MappingJackson2HttpMessageConverter)p).forEach(p -> p.setObjectMapper(objectMapper));
WebMvcConfigurer.super.extendMessageConverters(converters);
}
}
验证
这里格式符合要求了,时区还有点问题。在加个配置就好了
spring.jackson.time-zone=GMT+8
结论
@EnableWebMvc
这个注解影响到jackson
配置,说实话真没想到。以往看源码也是扫一眼就完事,没仔细看。没考虑到相互之间的影响。目前,其实我对于为啥使用这个注解也表示不太理解,常用的可以通过实现WebMvcRegistrations
和WebMvcConfigurer
来解决。