DIV对象到响应报文的序列化规则(fastJson替换jackSon)
Posted 张子行的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DIV对象到响应报文的序列化规则(fastJson替换jackSon)相关的知识,希望对你有一定的参考价值。
前言
这段时间在公司实习,学到的一些新的知识点特此分享给大家
我们在开发springBoot项目的时候直接加上上面的注解就可以很方便序列化传输JSON对象,那么底层的实现原理又是怎么样的呢?其实这个和我们的消息转换器有关。springBoot在实现@RequestBody、@ReponseBody的时候默认集成的是jackson的序列化,也就是说我们的springBoot默认为我们封装好了序列化的逻辑,我们只要拿来用就好了,但是我们的水平怎能局限与会用呢?我们更应该学会去扩展代码,而不是局限于使用别人写好的代码。
@ReponseBody:负责将对象序列化为响应报文
@RequestBody:负责将报文序列化为对象
实现思路
在springBoot项目中我们可以自己去实现WebMvcConfigurer接口来扩展我们自己的Mvc逻辑,其中我们可以去重写configureMessageConverters方法来添加我们自己的消息转换器,但是其中可能会出现一些问题(有可能我们添加的自定义消息转换器失效)。
实现详解
市面上有很多序列化的产品,看懂了本文以后还想自定义扩展消息转换器基本没有太大问题了。就拿阿里巴巴的fastJson举例。代码中注释写的很全。
@Configuration
public class returnConfig implements WebMvcConfigurer {
/**
* 配置序列化器为:fastjson
* springboot默认集成:jackson
* @param converters
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
/**
* 先移除jackson转换器,springBoot1.x可以不排除
* 解决springboot默认使用MappingJackson2HttpMessageConverter的问题
*/
for (int i = converters.size() - 1; i >= 0; i--) {
if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
converters.remove(i);
}
}
//1.需要定义一个convert转换消息的对象;
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
/**
* 1、WriteNullListAsEmpty :List字段如果为null,输出为[],而非null
* 2、WriteNullStringAsEmpty : 字符类型字段如果为null,输出为"",而非null
* 3、DisableCircularReferenceDetect :消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
* 4、WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
* 5、WriteMapNullValue:是否输出值为null的字段,默认为false。
*/
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.BrowserCompatible,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.WriteNullBooleanAsFalse);
// 设置编码
fastJsonConfig.setCharset(Charset.forName("UTF-8"));
/**
* 返回Date类型的数据转换为yyyy-MM-dd HH:mm:ss格式
*/
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
/**
* BigInteger类型的数据输出为String类型
*/
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
/**
* long类型的数据输出为String类型
*/
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
/**
* 支持驼峰命名规则
*/
serializeConfig.setPropertyNamingStrategy(PropertyNamingStrategy.CamelCase);
fastJsonConfig.setSerializeConfig(serializeConfig);
//支持哪种类型的数据进行转换
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON);
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastMediaTypes.add(MediaType.TEXT_html);
fastMediaTypes.add(MediaType.MULTIPART_FORM_DATA);
//4.在convert中添加配置信息.
fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
//5.将convert添加到converters当中.
converters.add(fastJsonHttpMessageConverter);
converters.add(stringHttpMessageConverter);
converters.add(byteArrayHttpMessageConverter);
}
}
后端返回的数据内容
效果
即使后端中List类型的数据为null前端接收到的也是 [] 而不是 null …,因为我们DIV了 @ReponseBody 使用的消息转换器,详情看上文中的配置
自定义转换器失效问题
其中默认springBoot为我们集成了如下一些转换器,图中圈记的即为我们的@ReponseBody、@RequestBody注解使用的转换器,但是注意看存储这些转换器的是一个ArrayList,在我们@RequestBody生效的时候,必定要遍历此ArrayList,但是这个遍历顺序就不能保证了,有可能遍历到springBoot默认的消息转换器然后就生效了,这就会导致我们自定义的消息转换器失效。为了防止这种情况出现,我们在配置的时候应该先移除MappingJackson2HttpMessageConverter。
@JsonIgnore失效问题
自定义转换器会导致@JsonIgnore、@JsonProperty注解失效的问题,我们都将jackSon替换为fastJson了,在看看@JsonProperty注解是谁麾下的 ?@JsonProperty 为 jackSon下面的注解,当然会失效咯!
附录
什么是报文?就拿本文中的测试用的 localhost:8891/user/testOut 请求来说,按F12点进去NetWork可以看到本次请求的全部信息如下图。
报文的组成
粗略的来讲报文可以分为如下几块:
- 请求行:请求方法、请求URL、协议版本
- 请求头
- 消息体
URL、URI、URN之间的关系
URI:Uniform Resource Identifier,统一资源标识符,能够唯一的标识网上的一个资源,只要在世界的任何一个有网络的地方,发起请求,就可以拿到这个图片,这个URI具有唯一性。那什么是URL呢?
URI有两种形式:
- URL,Uniform Resource Locator,统一资源定位符,描述了一台特定服务器上某个资源的特定位置。例如上面的链接就是一个统一资源定位符:
- URN,Uniform Resource Name,统一资源名,作为特定内容的唯一名称,与资源所在位置无关。也就是说,我可以给一份文档定义一个URN,不管你把这个文档放到哪里,有多少个URL,但是都只有唯一个URN。举个例子,因特网标准文档 RFC 3986不管存在哪个服务器上,都可以用唯一的URN来命名
以上是关于DIV对象到响应报文的序列化规则(fastJson替换jackSon)的主要内容,如果未能解决你的问题,请参考以下文章
阿里巴巴开源的 JSON 解析库 Fastjson 被曝高危漏洞,官方已发布安全公告