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可以看到本次请求的全部信息如下图。
在这里插入图片描述

报文的组成

粗略的来讲报文可以分为如下几块:

  1. 请求行:请求方法、请求URL、协议版本
    在这里插入图片描述
  2. 请求头
    在这里插入图片描述
  3. 消息体
    在这里插入图片描述

URL、URI、URN之间的关系

URI:Uniform Resource Identifier,统一资源标识符,能够唯一的标识网上的一个资源,只要在世界的任何一个有网络的地方,发起请求,就可以拿到这个图片,这个URI具有唯一性。那什么是URL呢?

URI有两种形式

  1. URL,Uniform Resource Locator,统一资源定位符,描述了一台特定服务器上某个资源的特定位置。例如上面的链接就是一个统一资源定位符:
  2. URN,Uniform Resource Name,统一资源名,作为特定内容的唯一名称,与资源所在位置无关。也就是说,我可以给一份文档定义一个URN,不管你把这个文档放到哪里,有多少个URL,但是都只有唯一个URN。举个例子,因特网标准文档 RFC 3986不管存在哪个服务器上,都可以用唯一的URN来命名

详情参考:https://zhuanlan.zhihu.com/p/352490927

以上是关于DIV对象到响应报文的序列化规则(fastJson替换jackSon)的主要内容,如果未能解决你的问题,请参考以下文章

阿里巴巴开源的 JSON 解析库 Fastjson 被曝高危漏洞,官方已发布安全公告

Fastjson对复杂对象进行序列化

Flask 数据json序列化(四)

fastjson不能处理静态对象吗

com.alibaba.fastjson.JSON对类对象的序列化与反序列化

fastjson中怎么把java对象转化为json对象