①未使用全局jackson设置:测试form data传参
前端->后端 @DateTimeFormat OK
后端->前端- @JsonFormat OK
②未使用全局jackson设置:测试json传参(使用@ResbonseBody反序列化)
前端->后端 @DateTimeFormat 失效
后端->前端 @JsonFormat OK,同时@JsonFormat前端->后端反序列化也生效
主要解决以下几个全局性问题
①@Requestbody @Responsebody默认使用的是jackson序列化,反序列化,但是其默认常常无法满足我们的需求,如日期,时间类型常常需要使用@JsonFormat @DateTimeFormat等注解来实现标准yyyy-MM-dd HH:mm:ss字符串与日期时间的转换。
② 常用的Long类型雪花ID 字段常常加@JsonSerialize(using = ToStringSerializer.class),将Long序列化为字符串,避免精度丢失;
③全局null字段不序列化等自定义设置等
/**
* 后端->前端全局序列化设置:
* 全局Long转String,LocalDateTime LocalDate LocalTime java.util.Date序列化与反序列化
* 可以通过实现WebMvcConfigurer接口
* @author majun
* @since 2020-08-21
*/
@Configuration
//@Primary
public class JacksonSerializerConfig implements WebMvcConfigurer {
private static final String PATTERN="yyyy-MM-dd HH:mm:ss";
private static final String TIME_ZONE="GMT+8";
@Override
public void extendMessageConverters(List> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = converter.getObjectMapper();
objectMapper.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//关闭日期序列化为时间戳的功能
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//关闭序列化的时候没有为属性找到getter方法,报错
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//序列化的时候序列对象的所有属性
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
//空值不序列化
//objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//序列化空对象不抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//关闭反序列化的时候,没有找到属性的setter报错
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//反序列化未知属性不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//自定义序列化:key-序列化字段类型,value-序列化所用对象,支持自定义及Jackson自带序列化器
SimpleModule module = new SimpleModule();
String[] patternArr = PATTERN.split(" ");
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(PATTERN)));
module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(patternArr[0])));
module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(patternArr[1])));
module.addSerializer(Date.class, new DateSerializer(false,new SimpleDateFormat(PATTERN)));
module.addSerializer(Long.class, ToStringSerializer.instance);
//自定义反序列化:key-序列化字段类型,value-序列化所用对象,支持自定义及Jackson自带序列化器
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(PATTERN)));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(patternArr[0])));
module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(patternArr[1])));
module.addDeserializer(Date.class, new DateDeserializers.DateDeserializer(){
@SneakyThrows
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext ctxt){
String text = jsonParser.getText().trim();
SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);
return sdf.parse(text);
}
});
objectMapper.registerModule(module);
converters.add(0, converter);
}
}
以上方式会出现使用@RequestBody String params接收前端的application/json参数出现序列化错误,解决方案:
将springboot自动配置的MappingJackson2HttpMessageConverter找到进行再设置。
/**
* 后端->前端全局序列化设置:
* 全局Long转String,LocalDateTime LocalDate LocalTime java.util.Date序列化与反序列化
* 可以通过实现WebMvcConfigurer接口
* @author majun
* @since 2020-08-21
*/
@Configuration
//@Primary
public class JacksonSerializerConfiguration implements WebMvcConfigurer {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
@Value("${spring.jackson.time-zone:GMT+8}")
private String timeZone;
@Override
public void extendMessageConverters(List> converters) {
for (HttpMessageConverter> cvt : converters) {
if (cvt instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter converter= (MappingJackson2HttpMessageConverter) cvt;
enhanceConvertor(converter);
}
}
}
private void enhanceConvertor(MappingJackson2HttpMessageConverter converter) {
ObjectMapper objectMapper = converter.getObjectMapper();
objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone));
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//关闭日期序列化为时间戳的功能
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//关闭序列化的时候没有为属性找到getter方法,报错
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//序列化的时候序列对象的所有属性
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
//空值不序列化
//objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//序列化空对象不抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//关闭反序列化的时候,没有找到属性的setter报错
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
//反序列化未知属性不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//自定义序列化:key-序列化字段类型,value-序列化所用对象,支持自定义及Jackson自带序列化器
SimpleModule module = new SimpleModule();
String[] patternArr = pattern.split(" ");
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(patternArr[0])));
module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(patternArr[1])));
module.addSerializer(Date.class, new DateSerializer(false,new SimpleDateFormat(pattern)));
//module.addSerializer(Long.class,ToStringSerializer.instance); // 会将mybatisplus 分页返回的total也转成字符串导致flutter问题
// 自定义序列化:long长度超过18位则认为是雪花ID,转为string,否则为数字,
module.addSerializer(Long.class, new JsonSerializer() {
@Override
public void serialize(Long aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String str = String.valueOf(aLong);
if (str.length()>=18) {
jsonGenerator.writeString(str);
}else {
jsonGenerator.writeNumber(aLong);
}
}
});
//自定义反序列化:key-序列化字段类型,value-序列化所用对象,支持自定义及Jackson自带序列化器
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern)));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(patternArr[0])));
module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(patternArr[1])));
module.addDeserializer(Date.class, new DateDeserializers.DateDeserializer(){
@SneakyThrows
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext ctxt){
String text = jsonParser.getText().trim();
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.parse(text);
}
});
objectMapper.registerModule(module);
}
}