SpringBoot实现WebMvcConfigurationSupport导致⾃定义的J。。。
给理想留点时间,熬过低⾕,繁华⾃现。
⼀、场景:返回数据对象带有时间类型属性
返回数据结构如下:(ps:SpringBoot版本为2.0.3-RELEASE)
@Setter
@Getter
public class DateResponse implements Serializable {
private LocalDate localDate = w();
private LocalDateTime localDateTime = w();
private LocalTime localTime = w();
private Date date =new Date();
}
⼆、出现的问题
请求返回的数据如下:
{
"localDate":[
2020,
6,
springboot结构20
],
"localDateTime":[
2020,
6,
20,
11,
46,
55,
810000000
],
"localTime":[
11,
46,
55,
810000000
],
"date":1592624815810
}
Java8的时间类型都变成了数组,Date则变成了时间戳。这和我们期望的不符,我们期望能返回如下的结果:
{
"localDate":"2020-06-21",
"localDateTime":"2020-06-21 10:41:33",
"localTime":"10:41:33",
"date":"2020-06-21 10:41:33"
}
三、分析问题
官⽅⽂档⾥的介绍如下所⽰
Spring MVC已经为我们提供了⼀些默认的HttpMessageConverters 来对HTTP请求内容进⾏转换,但显然这些默认的Converters不是我们需要的。
继续往下看,发现Spring还提供了⼏种⽅法来让我们⾃定义Converter
按照上⾯说的,可以通过⾃定义Jackson2ObjectMapperBuilderCustomizer、ObjectMapper、Jackson2ObjectMapperBuilder、MappingJackson2HttpMessageConverter 等Bean来⾃定义转换格式。但是按照⽂档⾥⾯的解释,例如按照⾃定义ObjectMapper⽅式,会禁⽤ObjectMapper的所有⾃动配置。综合考虑,还是选择⾃定义MappingJackson2HttpMessageConverter的⽅式。
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper){
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =new MappingJackson2HttpMessageConverter(objectMapper()); return mappingJackson2HttpMessageConverter;
}
private ObjectMapper objectMapper(){
ObjectMapper objectMapper =new ObjectMapper();
// 不序列化null的属性
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
JavaTimeModule javaTimeModule =new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_DATE_TIME_F ORMAT)));
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_DATE_FORMAT)));
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_DATE_TIM E_FORMAT)));
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_DATE_FORMAT))); javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(Constants.DEFAULT_TIME_FORMAT))); isterModule(javaTimeModule).registerModule(new ParameterNamesModule());
objectMapper.setDateFormat(new SimpleDateFormat(Constants.DEFAULT_DATE_TIME_FORMAT));
return objectMapper;
}
static class Constants {
/**
* 默认⽇期时间格式
*/
public static final String DEFAULT_DATE_TIME_FORMAT ="yyyy-MM-dd HH:mm:ss";
/**
* 默认⽇期格式
*/
public static final String DEFAULT_DATE_FORMAT ="yyyy-MM-dd";
/**
* 默认时间格式
*/
public static final String DEFAULT_TIME_FORMAT ="HH:mm:ss";
}
通过如上的配置,我们可以得到我们期望的返回了。
但是,问题⼜来了。
如果我们在程序⾥继承了WebMvcConfigurationSupport, 那么我们得到的返回⼜会是像最开始的那样。这是为什么呢?
官⽅⽂档有这样的介绍:
仔细看第⼆段话,问题好像出现在WebMvcConfigurationSupport这⾥。我们调试⼀下程序来看看到底是什么情况。
没有继承WebMvcConfigurationSupport的时候,我们看看WebMvcConfigurationSupport⾥的Convert
ers有哪些。
没有继承WebMvcConfigurationSupport的时候,我们看看WebMvcConfigurationSupport⾥的Converters有哪些。
在如图所⽰的两个地⽅打上断点。
第⼀个断点我们可以得到如下信息(注意这个@5484):
这个messageConverters是WebMvcConfigurationSupport⾥的⼀个属性,Spring通过这个属性⾥的Converters来对HTTP请求数据进⾏转换。我们可以看到,下标为7的那个Converter就是我们上⾯⾃定义的Converter。所以这个时候,数据是按照我们定的格式返回的。
如果继承了WebMvcConfigurationSupport之后呢?
如上图所⽰,这些Bean的序号都是连着的,我们⾃定义的Converter根本没有加⼊进去。不过⽂档也说了,可以通过configureMessageConverters这个⽅法将我们⾃定义的Converter加⼊进去。我们来试⼀下。
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters){
converters.add(new MappingJackson2HttpMessageConverter(objectMapper()));
}
好了,这下messageConverters⾥⾯就⼀个我们⾃定义的Converter,发起请求,数据按照我们期待的格式返回了。但是会有个疑问,其余的那些Converter都没有了,会不会有什么影响。⽬前我也不知道会有什么影响>_<,但是看WebMvcConfigurationSupport的源码,发现了⼀个⽅法addDefaultHttpMessageConverters,这个⽅法在什么时候被调⽤呢?WebMvcConfigurationSupport还有另⼀个⽅法getMessageConverters,这个⽅法源码如下:
protected final List<HttpMessageConverter<?>>getMessageConverters(){
ssageConverters == null){
ssageConverters.isEmpty()){
this.ssageConverters);
}
}
ssageConverters;
}
这说明了,如果我们通过configureMessageConverters⽅法加⼊⾃定义的Converter,Spring提供的默认的Converters就不会加⼊到messageConverters⾥了(其实官⽅⽂档有这么⼀句话就说明了这个问题: However, unlike with normal MVC, you can supply only additional converters that you need (because Spring Boot uses the same mechanism to contribute its defaults).)。再往下看,发现了另⼀个⽅法extendMessageConverters,顾名思义,这个⽅法是扩展messageConverters的。那我们是不是可以实现extendMessageConverters这个⽅法来只加⼊我们⾃定义的Converter⽽不改变默认的配置呢。动⼿⼀试!
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){
//需要注释掉configureMessageConverters的实现
converters.add(new MappingJackson2HttpMessageConverter(objectMapper()));
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论