Spring MVC 默认的序列化工具是Jackson,但是项目中遇到两个问题:
问题1:值为null的字段默认会被序列化
这样的话返回给前端的数据就会包括实体类的全部字段,有些字段在mybatis的查询中故意没写的字段,还是会生成字段名:null 这样的值在JSON字符串中,浪费网络带宽。
问题2:LocalDateTime类型的日期序列化后空格变成“T”字母
一般如果是查询结果映射到实体类,实体类的日期类型为java.sql.Date
,字段上又有@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
这样的注解是不会出问题的。但如果查询的结果类型直接是hashmap,不做映射,序列化之后就有问题。比如日期输出的值为:2023-02-13T12:18:11
解决方法一,继续用Jackson
针对问题1
,在spring boot的配置文件中加一个配置项就可以了,如下:
spring.jackson.default-property-inclusion = non_null
针对问题2
,要新建一个配置类,如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.codehaus.jackson.annotate.JsonValue;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
@Configuration
public class LocalDateTimeSerializerConfig {
@Bean
public LocalDateTimeSerializer localDateTimeDeserializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer());
}
或者在SQL语句中,将日期类型的字段格式化为字符型字段。
解决方法二,改用FastJson
使用FastJson代替Spring默认的Jackson,上面的问题就不会出现了。网上有人说FastJson虽然速度快,使用方便,但是安全性没那么好,代码注释少,所以你也可以考虑一下是否采用这种方法。
我这里使用的是fastjson2,然后spring MVC 是6.0的配置,maven引入类库如下:
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.26</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
<version>2.0.26</version>
</dependency>
新建一个配置类,我项目中有一个MVC全局拦截器,所以就把代码加到拦截器中了,都是实现了WebMvcConfigurer 接口,代码如下:
package com.ezlcp.commons.config;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter;
//import com.ezlcp.commons.filter.WebContextFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/***
* @description: 添加Spring MVC 拦截器
* @author Elwin ZHANG
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 先注释掉,可能你没有到拦截器
//registry.addInterceptor(new WebContextFilter()).addPathPatterns("/**");
}
//保证StringHttpMessageConverter在FastJsonHttpMessageConverter前被调用
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.clear();
StringHttpMessageConverter converter = new StringHttpMessageConverter(
Charset.forName("UTF-8"));
converters.add(converter);
converters.add(getFastJsonHttpMessageConverter());
}
//构造 FastJson消息序列化
public FastJsonHttpMessageConverter getFastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
//WriteMapNullValue——–是否输出值为null的字段,默认为false
//WriteNullNumberAsZero—-数值字段如果为null,输出为0,而非null
//WriteNullListAsEmpty—–List字段如果为null,输出为[],而非null
//WriteNullStringAsEmpty—字符类型字段如果为null,输出为”“,而非null
//这是spring MVC 6.X的写法(将序列化和反序列的配置分开了)
//spring MVC 5.X的写法网上很多可以自己搜索一下,或看这个 https://www.jianshu.com/p/65e210623210
config.setWriterFeatures(
JSONWriter.Feature.WriteNullListAsEmpty,
JSONWriter.Feature.WriteNullBooleanAsFalse,
JSONWriter.Feature.WriteNullNumberAsZero,
JSONWriter.Feature.BrowserCompatible,
JSONWriter.Feature.BrowserSecure
);
config.setReaderFeatures(
JSONReader.Feature.AllowUnQuotedFieldNames,
JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue,
JSONReader.Feature.TrimString
);
converter.setFastJsonConfig(config);
List<MediaType> mediaTypes = new ArrayList<>(8);
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
mediaTypes.add(MediaType.MULTIPART_FORM_DATA);
mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
mediaTypes.add(MediaType.APPLICATION_JSON);
mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
converter.setSupportedMediaTypes(mediaTypes);
return converter;
}
}
网友评论