本文介绍了在SpringBoot项目中将默认的Jackson替换为阿里巴巴的FastJson。
1、原理说明
HttpMessageConverter的作用
先看HttpMessageConverter接口源码。
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, MediaType mediaType);
boolean canWrite(Class<?> clazz, MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
Http请求响应报文其实都是字符串,在Spring的处理过程中,一次请求报文和一次响应报文,分别被抽象为一个请求消息HttpInputMessage和一个响应消息HttpOutputMessage。
在请求进入对应Mapping()方法前,会根据@RequestBody注解选择对应HttpMessageConverter实现类来将请求参数解析到param变量中,因为这里的参数的类型的,选择使用StringHttpMessageConverter()类或者JsonbHttpMessageConverter(),它的canRead()方法返回true,然后read()方法会从请求中读出请求参数,绑定到Mapping()注解对应的方法param变量中。同理当执行Mapping()方法后,由于返回值标识了@ResponseBody,SpringMVC / SpringBoot将使用StringHttpMessageConverter的write()方法,将结果作为String值写入响应报文,当然,此时canWrite()方法返回true。
整个过程:
我们需要替换的便是HttpMessageConverter中默认Json解析器。
2、实现步骤
2.1 添加依赖
所有的都要去除spring-boot-starter-json依赖
<!-- Spring Boot web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
2.2 配置fastjson
2.2.1 方法一:重写configureMessageConverters()方法的方式
package com.smallthanks.psi.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author SmallThanks
* 使用FastJson替换原有的Jackson
*/
@SpringBootConfiguration
public class JsonConfig implements WebMvcConfigurer{
/**
* 第一种实现方式
* @param converters 转换器
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
// 0、定义一个convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 1、添加fastJson的配置信息
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastConverter);
}
}
2.2.1 方法一:注入bean方式
package com.smallthanks.psi.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author SmallThanks
* 使用FastJson替换原有的Jackson
*/
@SpringBootConfiguration
public class JsonConfig {
// 第二种实现方式和第一种一样
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
// 0、定义一个convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 1、添加fastJson的配置信息
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastConverter);
}
}
3、疑问解答
3.1 日期问题
如果想在全局使用一个格式返回,那么可以设置fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
如果使用@JSONField(format = "yyyy-MM-dd HH:mm:ss")修饰属性,那么返回我们指定的格式,有且只对当前的对象生效。其中JSONFiled中的name属性,是指定当前当前属性转成JSON后的key。
3.2 SerializerFeatures/序列化器功能
我们可以看到fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);这样的一句话,这句话是全局设定在将对象转为JSON中对于属性的规则,具体我们看下表。
同样我们也可以在对象的每一个属性上加一个注解@JSONField(serialzeFeatures="xxx")中指定一个属性单独的格式。
枚举名 | 作用 | 备注 |
---|---|---|
QuoteFieldNames | 输出key时是否使用双引号,默认为true | 已验证 |
UseSingleQuotes | 使用单引号而不是双引号,默认为false | 已验证 |
WriteMapNullValue | 是否输出值为null的字段,默认为false | 默认不输出null的key |
WriteEnumUsingToString | Enum输出name()或者original,也就是转为toString | 已验证 |
WriteEnumUsingName | enum值序列化为其Name,默认为true。其效果同上 | 已验证 |
UseISO8601DateFormat | Date使用ISO8601格式输出,默认为false。 | 已验证 |
WriteNullListAsEmpty | List字段如果为null,输出为[],而非null | 已验证 |
WriteNullStringAsEmpty | 字符类型字段如果为null,输出为”“,而非null | 已验证 |
WriteNullNumberAsZero | 数值字段如果为null,输出为0,而非null | 已验证 |
WriteNullBooleanAsFalse | Boolean字段如果为null,输出为false,而非null | 已验证 |
SkipTransientField | 如果是true,类中的Get方法对应的Field是transient, get方法有transient注解序列化时将会被忽略。默认为true | 不常用未验证 |
SortField | 排序输出 | 不知道是不是按照字母排序,验证未成功 |
WriteTabAsSpecial | 把\t做转义输出,默认为false | 已过时,不使用 |
PrettyFormat | 结果是否格式化,默认为false | 已验证,按照标准的格式格式化json |
WriteClassName | 序列化时写入class信息,反序列化是需用到 | 已验证 |
DisableCircularReferenceDetect | 消除对同一对象循环引用的问题,默认为false | 禁用循环引用检测(强烈建议禁用) |
WriteSlashAsSpecial | 对斜杠’/’进行转义 | 已验证 |
BrowserCompatible | 将中文都会序列化为\uXXXX格式,能兼容IE6,默认为false | IE 已经淘汰,基本没有 |
WriteDateUseDateFormat | 全局修改日期格式,默认为false | 默认格式yyyy-MM-dd HH:mm:ss |
NotWriteRootClassName | 不输出根class名称,随着WriteClassName使用, 不输出当前类的信息,输入属性中包含类的信息 | 已验证 |
DisableCheckSpecialChar | 禁止特殊字符检查 | 已过时不使用 |
BeanToArray | 将对象转为array输出 | 转为一个数组输出 |
WriteNonStringKeyAsString | key不是String的字段写为String | 也就是数字的字段加上"" |
NotWriteDefaultValue | 默认的值不输出 | 属性没有进行赋值操作不输出 |
BrowserSecure | 待补充 | 待补充 |
IgnoreNonFieldGetter | 忽略没有getter方法的属性 | 没有get字段不在序列化 |
WriteNonStringValueAsString | value字段不是String写为String | 也就是value数字的字段加上"" |
IgnoreErrorGetter | 忽略 getter 方法报错 | 目前不知道有什么用 |
WriteBigDecimalAsPlain | 使用 BigDecimal.toPlainString() 序列化 | 目前不知道有什么用 |
MapSortField | 对属性排序输出 | 目前测试出对map集合中的key排序 |
3.3、@JSONField中属性作用
名称 | 作用 | 默认值 |
---|---|---|
ordinal | 配置序列化和反序列化的顺序,作用好像不大 | 0 |
name | 序列化时候的key | "" |
format | 指定日期的格式,可以使用JSON.DEFFAULT_DATE_FORMAT | "" |
serialize | 是否序列化 | True |
deserialize | 是否反序列化 | True |
serialzeFeatures | 序列化的规则,如上表 | {} |
parseFeatures | 反序列化的规则,懒得做-。- | {} |
.... | 其他的(wo)不(ye)太(bu)重(hui)要的 | ... |