Demand background
Requirements: In the microservice system built by SpringMVC, the database stores the date as a Long timestamp. The front-end used the default Long time before, but now the front-end framework changes to require the back-end to respond to the data, the Long time automatically changes to the standard time format (YYYY-MM-DD HH: MM: SS).
SQL > create table createTime (createTime); SQL > create table createTime (createTime); SQL > create table createTime (createTime);
Requirement 2: If the front-end framework does not handle this problem, when the JSON request received by the back-end is deserialized into an object, the value of String type will appear with Spaces before and after. Therefore, a unified processing method is needed. Execute the trim method on the received String attribute.
The solution
The default JSON framework for SpringMVC is Jackson, and you can also use FastJSON.
Jackson framework
Custom serialization
If your project uses the Jackson framework for JSON serialization, the recommended solution is to use the @jsonSerialize annotation, as shown in the following code:
@JsonSerialize(using = CustomDateSerializer.class)
private Long createTime;
@JsonSerialize(using = CustomDateSerializer.class)
private Long updateTime;
Copy the code
The following is an example of the CustomDateSerializer class:
public class CustomDateSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long aLong, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = newDate(aLong); jsonGenerator.writeString(sdf.format(date)); }}Copy the code
The benefits of such a scheme are as follows:
- Custom implementation classes can be reused
- CreateTime and updateTime are not limited to fields that need to be converted
The disadvantage is that all the fields that need to be converted need to be annotated, which is a bit of work
Of course, there are other unified treatment schemes, which are not described here.
Custom deserialization
It is also convenient to implement custom serialization on the Jackson framework by inheriting the SimpleModule class:
@Component
public class StringTrimModule extends SimpleModule {
public StringTrimModule(a) {
addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
String value = jsonParser.getValueAsString();
if (StringUtils.isEmpty(value)) {
return value;
}
returnvalue.trim(); }}); }}Copy the code
Fastjson framework
If this dependency appears in the project:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.262.</version>
</dependency>
Copy the code
Jackson @JsonSerialize does not have a trigger entry in Fastjson.
Custom serialization
Accordingly, there are configuration classes for fastjson, as shown in the following example:
/** * Uniform output is using fastJson **@return* /
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters(a) {
//convert Convert message object
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// Handle Chinese garbled characters
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
// Whether to format the returned JSON data
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
// Add value conversion processing for the specified field
fastJsonConfig.setSerializeFilters(new CustomerDateFilter());
// FastJson disables autoTypeSupport
fastJsonConfig.getParserConfig().setAutoTypeSupport(false);
fastConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastConverter);
}
Copy the code
Here you need to add fastjson handling of the field values (the code above has added this line), as in
// Add value conversion processing for the specified field
fastJsonConfig.setSerializeFilters(new CustomerDateFilter());
Copy the code
CustomerDateFilter is a self-implemented class with the following code:
public class CustomerDateFilter implements ValueFilter {
@Override
public Object process(Object object, String name, Object value) {
if (FieldConstants.CREATE_TIME.equalsIgnoreCase(name) || FieldConstants.UPDATE_TIME.equalsIgnoreCase(name)) {
// The property name is createTime, updateTime for conversion
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
if(value instanceof Long) {
Long time = (Long) value;
Date date = new Date(time);
return sdf.format(date);
} else {
returnvalue; }}returnvalue; }}Copy the code
This makes it convenient to treat createTime and updateTime fields that occur in all response objects, whether they are lists or individual objects. The disadvantage is that in addition to the field, if the whole system is not unified, you need to deal with separately.
SerializeFilter Custom serialization
SerializeFilter supports the following extended programming interfaces for customized serialization, which can be extended as required:
- PropertyPreFilter: Determines serialization based on the PropertyName.
- PropertyFilter: Determines serialization based on PropertyName and PropertyValue.
- NameFilter: Changes the Key. If the Key needs to be changed, the value returned by process can be changed.
- ValueFilter: modifies a Value.
- BeforeFilter: Add content first when serializing;
- AfterFilter: Adding content at the end of serialization;
Custom deserialization
FastJson provides serialization filters to implement custom serialization transformations, but does not provide deserialization filters to implement corresponding functions.
Solution: @jsonfield annotation
Back to the JSON String value trim operation, the official website supports @jsonField annotation attribute setting (fastJson version 1.2.36 or later) :
@JSONField(format="trim")
private String name;
Copy the code
When the JSON message is deserialized, the name attribute of the entity is automatically processed by the trim method.
This scheme only adds annotations one by one, which is a lot of work.
Solution: Implement the ObjectDeserializer interface
The ObjectDeserializer interface is used to implement custom deserialization. It works with the global Settings of ParserConfig to achieve the desired effect. The StringTrimDeserializer class is jointly created to handle String:
/ * * *@title: StringTrimDeserializer
* @description: Trim all String contents */
public class StringTrimDeserializer implements ObjectDeserializer {
@Override
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
// The logic for deserializing a JSON String is more complicated. On top of StringCodec, call trim on the result
Object obj = StringCodec.instance.deserialze(parser, type, fieldName);
if (obj instanceof String) {
String str = (String) obj;
return (T) str.trim();
}
return (T) obj;
}
@Override
public int getFastMatchToken(a) {
returnJSONToken.LITERAL_STRING; }}Copy the code
Accordingly, in HttpMessageConverters fastJsonHttpMessageConverters method and increase the String class deserialization Settings:
// Set the global deserialization rule for String: complete trim automatically
ParserConfig.getGlobalInstance().putDeserializer(String.class, new StringTrimDeserializer());
Copy the code
Parser.getlexer ().stringval () and trim instead of calling the stringCodec.instance method.
StringCodec is fastJson’s default String deserialization logic class. It handles the following types: String, StringBuffer, StringBuilder, etc., as well as a variety of collections and array structures. In order to deserialize String text, the implementation logic and scenarios are complicated. This time, we need to perform trim on the String, but we need to leave the complicated logic to StringCodec.
summary
Today it is record Json custom serialization and deserialization of practices, began to confirm before which is used in the engineering framework, can appear otherwise added @ JsonSerialize annotations, make the most of no effect, turn head a see framework is fastjson, no trigger entrance, of course, can not get the desired effect, A little advice. I hope it helps.