Spring Cloud 序列化和反序列化过程定制(Jackson)

2023-10-30

    现在都是基于Spring Cloud Feign进行微服务的调用,并且序列化的过程都封装完成的。只是自己可以定制序列化的方式,但是为了调用的时候能方便的找到问题所在等,基本都会使用json(Jackson等)方式的序列化【虽然性能比较差】。但是最近在项目上使用的时候,自己的需求是根据不同的类型(或者枚举),入参和出参会传入不同的子类,但是在接口的定义上只能使用父类进行接收。当反序列化完成后,在Controller层拿到的数据就只有父类公共的字段,而子类特有的字段在序列化时直接进行丢弃了。

    当然我完全可以用一个比较宽泛的类,放入比较全的字段,只是不同类型,有的字段可能为空,只是自己完全不想那样处理,但是处理的时候发现还是费了好多力气,于是简单记录一下定制序列化和反序列化的过程。

调用的接口:

@PostMapping("checkChain")
public CheckResultDTO checkChain(@RequestBody CheckChainDTO... checkChains);

入参对象:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonDeserialize(using = CheckChainDTOJsonDeserializer.class)
public class CheckChainDTO {

    /**
     * 验证类型
     */
    private CheckTypeEnum checkTypeEnum;

    /**
     * 入参
     */
    private CheckRequestDTO checkRequestDTO;
}

具体不同的CheckTypeEnum,会对应自己的CheckRequestDTO子类,比如(如果不自己处理的话,Spring Cloud的反序列化完成后,就会丢弃CheckRequestSkuDTO自己特有的属性skuCodeList):

public class CheckRequestSkuDTO extends CheckRequestDTO {
    /** sku编码集合 */
    private List<SkuInfoDTO> skuCodeList;
}

当然出参也是一样的,所以我是在提供feign的maven包时也提供了反序列化的过程,则进行忽略,只是两个过程都需要反序列化定制。

 

首先,先看一下项目上使用的设置Jackson为项目的序列化、反序列化方式,相信在网上也能copy到很多。如下:

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {

    private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    @Autowired
    private HttpMessageConverters httpMessageConverters;

    /**
     * MappingJackson2HttpMessageConverter 实现了HttpMessageConverter 接口,
     * httpMessageConverters.getConverters() 返回的对象里包含了MappingJackson2HttpMessageConverter
     *
     * @return
     */
    @Bean
    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
        return new MappingJackson2HttpMessageConverter(new JacksonMapper());
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.addAll(httpMessageConverters.getConverters());
    }

    public static class JacksonMapper extends ObjectMapper {
        public JacksonMapper() {
            super();
            this.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
            this.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
            this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            this.setSerializationInclusion(JsonInclude.Include.NON_NULL);

            SimpleModule simpleModule = new SimpleModule();
            //Long 类型转成 String
            simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
            simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
            simpleModule.addSerializer(long.class, ToStringSerializer.instance);
            //日期格式化
            simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
            simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
            simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
            simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
            simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
            simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

            // 定制自己的序列化方式
            simpleModule.addDeserializer(CheckChainDTO.class, new CheckChainDTOJsonDeserializer());
            registerModule(simpleModule);
        }
    }
}

 

那么我们在设置自己的序列化方式时,如上:

// 定制自己的序列化方式
simpleModule.addDeserializer(CheckChainDTO.class, new CheckChainDTOJsonDeserializer());

当然,Jackson提供了注解的方式,简单的实现,如上面直接在需要定制序列化的类上面添加的注解:

@JsonDeserialize(using = CheckChainDTOJsonDeserializer.class)

 

具体的反序列化过程类如下,枚举上直接定义了入参和出参的对应类型:

@Slf4j
public enum CheckTypeEnum {
    /** SKU检查 */
    SKU(CheckRequestSkuDTO.class, SkuResultDTO.class);

    /** 请求入参类型 */
    public final Class<? extends CheckRequestDTO> clazz;

    /** 返回值类型 */
    public final Class<? extends ResultDTO> resultClazz;

    CheckTypeEnum(Class<? extends CheckRequestDTO> clazz, 
                  Class<? extends ResultDTO> resultClazz) {
        this.clazz = clazz;
        this.resultClazz = resultClazz;
    }
}
@Slf4j
public class CheckChainDTOJsonDeserializer extends JsonDeserializer<CheckChainDTO> {
    @Override
    public CheckChainDTO deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
        try {
            final String checkTypeEnumStr = node.get("checkTypeEnum").asText();
            final CheckTypeEnum checkTypeEnum = CheckTypeEnum.valueOf(checkTypeEnumStr);

            final String checkRequestDTOStr = node.get("checkRequestDTO").toString();

            final CheckRequestDTO checkRequestDTO = JSONUtil.deserializeObject(checkRequestDTOStr, checkTypeEnum.clazz);
            return new CheckChainDTO(checkTypeEnum, checkRequestDTO);
        } catch (Exception e) {
            log.error("检查接口调用链路异常:" + e);
            buildException(PARAMETER_MATCH_EXCEPTION);
        }
        return null;
    }
}

这样在项目使用的时候数据就不会丢失了,再根据具体的枚举类型,强转为对应的子类就可以了。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Cloud 序列化和反序列化过程定制(Jackson) 的相关文章

  • 构建Java Web应用实验

    1 创建负责下载WAR文件的镜像 1 创建一个目录fetcher 保存相关的配置信息和内容 在 后输入mkdir fetcher cd fetcher命令 然后按Enter键 创建fetcher目录并进入该目录 示例代码如下 root xi

随机推荐

  • 知识追踪实战:lstm+ Multi-head Attention注意力机制的学生做题成绩预测实战

    项目视频讲解 知识追踪实战 lstm Multi head Attention注意力机制的学生做题成绩预测实战 哔哩哔哩 bilibili from collections import Counter import torch from
  • 小程序蓝牙亲身总结

    问题 1 小程序蓝牙搜索能不能搜到手机设备 2 如何判断蓝牙是否打开 3 搜索指定设备 4 开发者工具和 Android 上获取到的deviceId为设备 MAC 地址 iOS 上则为设备 uuid 因此deviceId不能硬编码到代码中
  • 前端框架 (一)zTree 从数据库中动态加载树形菜单

    这几天做动态菜单用到了这个插件 目前用的很广泛的一个开源框架 最新发布的QUI框架就是用这个插件开发的菜单部分 因此还是很值得深入研究和学习 通过使用感觉功能很丰富 好多函数不用自己开发和编写 官网上有很详尽的API可以参考 用着算顺手但学
  • ASP.NET 与ASP.NET Core区别--概念及特征比对

    随着 NET的发展 NET Core对跨平台支持得越来越好 ASP NET Core能运行在Windows macOS 或 Linux 上 这就意味着ASP NET Core开发的网站 可以在除了Windows之外的平台运行 而且ASP N
  • 每天读一遍,不久你就会变

    在平凡枯燥简单的工作中 做无可取代的人 再烦 也别忘记微笑 再急 也要注意语气 再苦 也别忘坚持 再累 也要爱自己 低调做人 你会一次比一次稳健 高调做事 你会一次比一次优秀 成功的时候不要忘记过去 失败的时候不要忘记还有未来 有望得到的要
  • cadence allegro番外:制作含热风焊盘、反焊盘的过孔

    前言 需要先参考下列文章 padstack editor制作过孔 cadence allegro番外 制作flash焊盘 在以上文章中 已经制作了一个可用于两层板的过孔 但是在多层板中 过孔是需要链接或避让负电层的 因此需要在过孔中添加热风
  • 麒麟v10 curl报错:SSLv3_client_method version OPENSSL_1_1_0 not define

    curl及yum大致错误 usr bin cmake3 relocation error usr lib64 libcurl so 4 symbol SSLv3 client method version OPENSSL 1 1 0 not
  • 【STM32 学习】电源解析(VCC、VDD、VREF+、VBAT)

    VCC 电源电压 GND 电源供电负电压 通常接地 VDD 模块工作正电压 VSS 模块工作负电压 VREF ADC参考正电压 VREF ADC参考负电压 VBAT 电池或其他电源供电 VDDA 模拟供电正电压 VSSA 模拟供电负电压 一
  • c++11:动态内存与智能指针

    为了更容易 同时也更安全 地使用动态内存 新的标准库提供了两种智能指针 smart pointer 类型来管理动态对象 智能指针的行为类似常规指针 重要的区别是它负责自动释放所指向的对象 新标准库提供的这两种智能指针的区别在于管理底层指针的
  • CV::Mat数据拷贝 memcpy 踩坑

    1 cv mat 初始化 cv Mat img1 h w CV 8UC3 cv Mat img1 h w CV 8UC3 data 一般cv mat 初始化后数据内存 data 段都是连续的 可以用isContinuous 函数判断存储是否
  • Git克隆、拉取最新代码、上传代码到远程仓库

    文章目录 工作区 暂存区 版本库 1 提交代码到仓库 2 pull拉取最新代码 3 克隆 拉取代码 解决冲突 4 git 关联仓库并上传代码 5 关联已有仓库并提交代码 6 git记住某个仓库的账号密码 工作区 暂存区 版本库 工作区 就是
  • sqli-labs靶场Less-15

    1 访问首页 Less 15 index php 这里的传参点是表单中的uname passwd 判断是否是数字形传参 判断是否有单引号闭合 判断是否是双引号闭合 判断是否单引号 括号闭合 判断是否是双引号 括号闭合 如果以上都不适 哪以上
  • type object ‘Path‘ has no attribute ‘home‘

    报错 根据堆栈定位 是matplotlib init py文件里面562行位置报错的问题 讲道理 应该没有问题来着 进入到matplotlib init py文件 然后悬停Path和home 发现 emmm 文件居然不一样 好的 在我尝试更
  • OpenCV缺陷检测

    新手上路 欢迎高手指点 原图 OpenCV缺陷检测代码 An highlighted block include head h int main Mat img imread image 1204 bmp assert im data if
  • python是面向对象还是面向过程的

    Python虽然是解释型语言 但从设计之初就已经是一门面向对象的语言 对于Python来说一切皆为对象 正因为如此 在Python中创建一个类和对象是很容易的 当然如果习惯面向过程或者函数的写法也是可以的 Python并不做硬性的限制 Py
  • python连接sqlsever_使用Python连接到Microsoft SQL Server

    我试图通过python连接到SQL以在Microsoft SQL服务器上的某些SQL数据库上运行一些查询 从我的在线研究和在这个论坛上 最有前途的图书馆似乎是pyodbc 所以我做了以下代码 import pyodbc conn pyodb
  • 【C#学习笔记】Hello World

    using System namespace ConsoleApplication class Program static void Main string args Console Write Hello World Console R
  • Class.forName()用法详解

    一 CLASS类概念 Class也是一个Java类 保存的是与之对应Java类的meta信息 元信息 用来描述这个类的结构 比如描述一个类有哪些成员 有哪些方法等 一般在反射中使用 详细解释 Java 源程序 java 文件 在经过 Jav
  • mysql 查询不出结果_mysql 执行查询SQL 一直执行不出结果

    今天执行一个mysql 语句 一直在 执行 执行了5分钟了 还是没有出来结果 每个组织下包括 同级或者下级的 注册店铺数 查询 历史每一天的每个组织下的当天存在的门店数 select dt time startDate o brand id
  • Spring Cloud 序列化和反序列化过程定制(Jackson)

    现在都是基于Spring Cloud Feign进行微服务的调用 并且序列化的过程都封装完成的 只是自己可以定制序列化的方式 但是为了调用的时候能方便的找到问题所在等 基本都会使用json Jackson等 方式的序列化 虽然性能比较差 但