background
1.1 problem
Spring Boot When dealing with serialization and deserialization of objects , By default, the built-in JackSon To configure . Use the frame default , We usually face the following problems :
- Date Return date format ( It is not recommended to use Date, But old projects should be compatible ), with T, Such as 2018-05-15T24:59:59:
- LocalDate The returned Date object is an array ( The framework inherits WebMvcConfigurationSupport);
- LocalDateTime Time conversion failed ;
- Defines the date type , Such as LocalDate, Front end docking (post/get), If you pass in a date string ("2022-05-05"), Will be submitted to the String Convert to LocalDate Failure ;
- return long Type data , front end js There is accuracy problem , Conversion required ;
- Some special objects need special business transformation , Such as encryption and decryption ;
1.2 Solution
For the above problems , There are many solutions . Because the underlying framework uniformly configures different implementation modes of interception classes , There will still be differences , This article mainly explains that in different configuration scenarios , Customize Jackson Some considerations for configuration and reasons for differentiation :
In order to solve special objects ( Such as date ) Serialization and deserialization of , Common schemes are as follows :
- For a particular specific object , Use annotations on objects , Such as :
@JsonSerialize(using= JsonDateSerializer.class)
private Date taskEndTime;
@ApiModelProperty(value = " Inspection date ")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate checkDate;
- Re actualize WebMvcConfigurer Interface , Customize JackSon To configure .
- Inherit WebMvcConfigurationSupport class , Customize JackSon To configure .
1.3 In particular
- programme 1 The pattern of , Annotate the corresponding variable , It can solve the problem , But the code is seriously duplicated , Not elegant ;
- Realization WebMvcConfigurer Interface and inheritance WebMvcConfigurationSupport class , yes Spring Boot It provides two modes for developers to make unified global configuration classes , Notice the difference between the two modes , See the following chapters for details ( Two different modes , Improper use , The configuration will not take effect );
Customize Jackson
JackSon Configuration instructions
Customize a Jackson Configuration information , Need to know Jackson Some configuration standards for , Such as :


// Ignored in deserialization json There is but Java Object does not exist
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
// The date format defaults to yyyy-MM-dd'T'HH:mm:ss.SSSZ , For example, if a class has private Date date; This date attribute , Serialized as :{"date" : 1413800730456}, If not true, Then for {"date" : "2014-10-20T10:26:06.604+0000"}
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
// Ignore the value... When serializing null Properties of
mapper.setSerializationInclusion(Include.NON_NULL);
// Ignore properties with default values
mapper.setDefaultPropertyInclusion(Include.NON_DEFAULT);
// Beautify the output
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// Allow serialization of empty POJO class
// ( Otherwise, an exception will be thrown )
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// hold java.util.Date, Calendar Output to digital ( Time stamp )
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Don't throw an exception when you encounter an unknown property
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// mandatory JSON An empty string ("") Convert to null The object is worth :
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// stay JSON It is allowed that C/C++ Comments on styles ( Nonstandard , Default disabled )
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// Allow field names without quotes ( Nonstandard )
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// Single quotation marks are allowed ( Nonstandard )
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// Mandatory escape is not ASCII character
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
// Wrap the content into a JSON attribute , The attribute name is from @JsonRootName Annotation assignment
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
// Serializing enumerations starts with toString() To output , Default false, That is to say, by default name() To output
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
// serialize Map When the key Sort operations , Default false
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);
// serialize char[] Time and space json Array output , Default false
mapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true);
View Code Realization WebMvcConfigurer Interface
Rewrite a ObjectMapper, Replace the system default bean, You can implement the interface in post Request mode , Object serialization and deserialization define the configuration information .
Rewrite Jackson after , It doesn't deal with get When asked , Serialization of special objects such as dates ; in the light of get request , Write the serialization rule function of the object , By implementing addFormatters() Interface , Scalable support ;
To write LocalDateTime Conversion function
/**
* java 8 LocalDateTime converter
*
* @author wangling
*/
public class LocalDateTimeFormatter implements Formatter<LocalDateTime> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return LocalDateTime.parse(text, formatter);
}
@Override
public String print(LocalDateTime object, Locale locale) {
return formatter.format(object);
}
}
To write LocalDate Conversion function
/**
* java 8 localDate converter
*
* @author wangling
*/
public class LocalDateFormatter implements Formatter<LocalDate> {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
return LocalDate.parse(text, formatter);
}
@Override
public String print(LocalDate object, Locale locale) {
return formatter.format(object);
}
}
To write Jackson To configure
Write a custom ObjectMapper bean object , Set priority to replace default bean.
/**
* Project global configuration class
*
* @author wangling
* @date 2022/06/10
*/
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());
registry.addFormatterForFieldType(LocalDateTime.class, new LocalDateTimeFormatter());
}
@Bean
@Primary
public ObjectMapper ObjectMapper() {
String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
String dateFormat = "yyyy-MM-dd";
String timeFormat = "HH:mm:ss";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JavaTimeModule javaTimeModule = new JavaTimeModule();
// serialize
javaTimeModule.addSerializer(
LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
javaTimeModule.addSerializer(
LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
javaTimeModule.addSerializer(
LocalTime.class,
new LocalTimeSerializer(DateTimeFormatter.ofPattern(timeFormat)));
javaTimeModule.addSerializer(
Date.class,
new DateSerializer(false, new SimpleDateFormat(dateTimeFormat)));
// Deserialization
javaTimeModule.addDeserializer(
LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
javaTimeModule.addDeserializer(
LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern(dateFormat)));
javaTimeModule.addDeserializer(
LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(timeFormat)));
javaTimeModule.addDeserializer(Date.class, new DateDeserializers.DateDeserializer() {
@SneakyThrows
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext dc) {
String text = jsonParser.getText().trim();
SimpleDateFormat sdf = new SimpleDateFormat(dateTimeFormat);
return sdf.parse(text);
}
});
javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
javaTimeModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}
WebMvcConfigurationSupport class
To write Jackson To configure
Rewrite Jackson after , It doesn't deal with get When asked , Serialization of special objects such as dates ; in the light of get request , Write the serialization rule function of the object , By implementing addFormatters() Interface , Scalable support ;


/**
* Project global configuration class
*
* @author wangling
* @date 2022/06/10
*/
@Configuration
public class MvcInterceptorConfig extends WebMvcConfigurationSupport {
@Override
protected void addFormatters(FormatterRegistry registry) {
// be used for get Global format date conversion
registry.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());
registry.addFormatterForFieldType(LocalDateTime.class, new LocalDateTimeFormatter());
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// Replace the frame default JackSon To configure be used for post Global format date conversion ,long Turn the string
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter =
new MappingJackson2HttpMessageConverter();
jackson2HttpMessageConverter.setObjectMapper(ObjectMapper());
// Based on order , First, execute the customized
converters.add(0, jackson2HttpMessageConverter);
}
private ObjectMapper ObjectMapper() {
String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
String dateFormat = "yyyy-MM-dd";
String timeFormat = "HH:mm:ss";
ObjectMapper objectMapper = new ObjectMapper();
// Ignore empty Bean turn json Error of
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// Ignore stay json There is... In the string , But there is no corresponding attribute in the object , Prevent mistakes .
// for example json There are more fields in the data , There is no such field in the object . If you set true, Throw an exception , Because the field does not correspond to ;false Then ignore the extra fields , The default value is null, Deserialize other fields successfully
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JavaTimeModule javaTimeModule = new JavaTimeModule();
// serialize
javaTimeModule.addSerializer(
LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
javaTimeModule.addSerializer(
LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
javaTimeModule.addSerializer(
LocalTime.class,
new LocalTimeSerializer(DateTimeFormatter.ofPattern(timeFormat)));
javaTimeModule.addSerializer(
Date.class,
new DateSerializer(false, new SimpleDateFormat(dateTimeFormat)));
// Deserialization
javaTimeModule.addDeserializer(
LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
javaTimeModule.addDeserializer(
LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern(dateFormat)));
javaTimeModule.addDeserializer(
LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(timeFormat)));
javaTimeModule.addDeserializer(Date.class, new DateDeserializers.DateDeserializer() {
@SneakyThrows
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext dc) {
String text = jsonParser.getText().trim();
SimpleDateFormat sdf = new SimpleDateFormat(dateTimeFormat);
return sdf.parse(text);
}
});
javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
javaTimeModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}
View CodeWebMvcConfigurer And WebMvcConfigurationSupport Related knowledge
Basic knowledge points
Spring Of WebMvcConfigurer
Interfaces provide many ways for developers to customize SpringMVC Configuration of .
WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware. More and more customized configurations are supported ,WebMvcConfigurerAdapter There are ways , This class also has . This kind of annotation content is translated : This is to provide MVC Java config The main classes configured behind . Usually by putting @EnableWebMvc Added to the application @Configuration Class . Another more advanced option is to extend directly from this class and rewrite methods as needed , Remember to add subclasses @Configuration, Rewrite with @Bean We should also add @Bean.
Precautions for use
- Realization WebMvcConfigurer: Will not cover WebMvcAutoConfiguration Configuration of
- Realization WebMvcConfigurer+ annotation @EnableWebMvc: Will be covered WebMvcAutoConfiguration Configuration of
- Inherit WebMvcConfigurationSupport: Will be covered WebMvcAutoConfiguration Configuration of
- Inherit DelegatingWebMvcConfiguration: Will be covered WebMvcAutoConfiguration Configuration of
Recommended use mode
- It's not necessary , It's best to avoid WebMvcConfigurer,WebMvcConfigurationSupport Use... Simultaneously in a project ;
- Intercept configuration for security , Recommended for the project WebMvcConfigurer Interface for global configuration ;
- date , It is suggested to use LocalDate, Replace historical Date data type ;