Jackson 2.x 系列【31】Spring Boot 集成之字典回写

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

本系列Spring Boot 版本 3.2.4

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

文章目录

    • 1. 场景描述
    • 2. 案例演示
      • 2.1 修改枚举
      • 2.2 定义注解
      • 2.3 自定义序列化器
      • 2.4 自定义装饰器
      • 2.5 配置
      • 2.6 测试

1. 场景描述

例如,用户对象中的性别字段,一般在数据库都是使用数值表示,枚举类如下:

public enum GenderEnum {MAN(1, "男"),WOMAN(2, "女");GenderEnum(int code, String desc) {this.code = code;this.desc = desc;}private int code;private String desc;public static String getDesc(int code) {for (GenderEnum c : GenderEnum.values()) {if (c.getCode() == code) {return c.getDesc();}}return null;}public int getCode() {return code;}public String getDesc() {return desc;}public void setCode(int code) {this.code = code;}public void setDesc(String desc) {this.desc = desc;}
}

用户对象如下:

@Data
@ToString
public class PersonVO implements Serializable {Long id;String username;@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")Date birthday;Integer gender;

返回前端示例如下:

 {"id": "1699657986705854464","username": "jack","birthday": "2024-04-23 14:21:54","gender": 1}

这时,需要将数值类型翻译为对应的描述,例如性别1应该翻译为。和上篇的数据脱敏一样,后端可以在数据库查询或者反序列化返回Http响应时进行处理。
在这里插入图片描述

2. 案例演示

演示需求:将性别编码值翻译后,返回给前端。

示例:

 {"id": "1699657986705854464","username": "jack","birthday": "2024-04-23 14:21:54","gender": 1,"genderText":"男"}

2.1 修改枚举

定义一个公共的枚举接口,定义一个根据编码值获取对应描述的方法:

public interface CommonEnum {/*** 根据编码值获取描述*/String getDescription(int code);
}

GenderEnum 实现公共枚举接口,并实现其方法,这里枚举类相当于一本字典,根据编码值可以翻译为描述字符串,实际开发时,也可以使用数据库或者缓存,建立专门的字典表进行维护:

public enum GenderEnum implements CommonEnum {MAN(1, "男"),WOMAN(2, "女");GenderEnum(int code, String desc) {this.code = code;this.desc = desc;}private int code;private String desc;@Overridepublic String getDescription(int code) {for (GenderEnum c : GenderEnum.values()) {if (c.getCode() == code) {return c.getDesc();}}return "";}public int getCode() {return code;}public String getDesc() {return desc;}public void setCode(int code) {this.code = code;}public void setDesc(String desc) {this.desc = desc;}
}

2.2 定义注解

定义一个字典注解,这里使用枚举类作为字典:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@JacksonAnnotationsInside
public @interface Dict {/*** 指定后缀* 翻译后的属性名称:添加了注解的属性名+指定后缀*/String suffix() default "Text";/*** 字典使用枚举(实际开发可以使用数据库或者缓存)*/Class<? extends CommonEnum> using();
}

2.3 自定义序列化器

自定义序列化器执行翻译写出操作:

public class DictJsonSerializer extends StdSerializer<Object> {private CommonEnum commonEnum;protected DictJsonSerializer() {super(Object.class);}protected DictJsonSerializer( CommonEnum commonEnum) {super(Object.class);this.commonEnum = commonEnum;}/*** 序列化*/@Overridepublic void serialize(Object code, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {// 获取枚举对应的翻译值并写出String description =commonEnum.getDescription(Integer.parseInt(code.toString()));jsonGenerator.writeString(description);}
}

2.4 自定义装饰器

自定义Bean对象序列化装饰器,解析添加了@Dict注解的属性,据此新建一个虚拟属性:

public class DictBeanSerializerModifier extends BeanSerializerModifier {public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {// 1. 创建新的属性集合List<BeanPropertyWriter> newBeanProperties = CollUtil.newArrayList(beanProperties);// 2. 循环所有属性for (BeanPropertyWriter propertyWriter : beanProperties) {// 3. 获取注解 @DictDict annotation = propertyWriter.getAnnotation(Dict.class);if (annotation == null) {annotation = propertyWriter.getContextAnnotation(Dict.class);}if (annotation != null) {// 4. 新建一个虚拟属性(名称为:添加了注解的属性名+指定后缀)NameTransformer transformer = NameTransformer.simpleTransformer("", annotation.suffix());BeanPropertyWriter newProperty = propertyWriter.rename(transformer);CommonEnum commonEnum = null;Class<? extends CommonEnum> using = annotation.using();// 5. 获取枚举示例(无法反射,所以直接 IF 判断)if (GenderEnum.class.isAssignableFrom(using)) {commonEnum = GenderEnum.MAN;}// 6. 设置虚拟属性的序列化器newProperty.assignSerializer(new DictJsonSerializer(commonEnum));newBeanProperties.add(newProperty);}}return newBeanProperties;}
}

2.5 配置

添加Spring配置类,注册自定义的ObjectMapper,并设置BeanSerializerModifier

@Configuration
public class ObjectMapperConfig {@Bean@PrimaryObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {ObjectMapper objectMapper = builder.createXmlMapper(false).build();SerializerFactory serializerFactory = objectMapper.getSerializerFactory().withSerializerModifier(new DictBeanSerializerModifier());objectMapper.setSerializerFactory(serializerFactory);return objectMapper;}
}

2.6 测试

用户类添加翻译注解:

@Data
@ToString
public class PersonVO implements Serializable {Long id;String username;@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")Date birthday;@Dict(using = GenderEnum.class)Integer gender;

访问测试接口:

    @RequestMapping("/test")public PersonVO test() {PersonVO vo = new PersonVO();vo.setId(1699657986705854464L);vo.setUsername("jack");vo.setBirthday(new Date());vo.setGender(2);return vo;}

返回结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/3651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gitflow实操以及代码审查Pull Request操作

1.背景 之前一直有用过gitflow&#xff0c;但是一直没有归纳技术&#xff0c;另一方面也是每个团队用到的gitflow都不一致。而最近做项目要用gitflow&#xff0c;趁此机会分享一下gitflow的操作。 2.gitflow介绍 用git一直有一个问题&#xff0c;就是怎么保证代码稳定性&…

服务器如何开启远程连接?

服务器开启远程连接是网络管理中一项重要的功能。通过远程连接&#xff0c;用户可以在任何地方远程访问服务器&#xff0c;从而进行管理、维护和监控等操作。远程连接的开启可以为工作提供便利性和效率&#xff0c;但同时也带来了安全风险。确保远程连接的安全性和可靠性是至关…

RPC的介绍和架构发展

RPC概念&#xff1a; RPC是远程过程调用协议&#xff0c;是一种不需要了解底层网络技术&#xff0c;调用远程计算机服务。 RPC框架的组成&#xff1a; 图1 当总项目的数据量、访问量不断提高&#xff0c;就把他分成多个服务&#xff0c;减轻单体机器的压力。分开的ABC服务之…

python高阶函数:zip()

概述与基本用法 zip() 是 Python 内置函数之一&#xff0c;用于将多个可迭代对象打包成一个元组序列&#xff0c;然后返回一个迭代器。它可以接受任意数量的可迭代对象作为参数&#xff0c;并将它们的元素按顺序一一对应地打包成元组。 以下是 zip() 函数的基本用法&#xff…

【前端】vue3树形组件使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、树形组件简介二、树形组件使用三、总结 前言 随着开发语言及人工智能工具的普及&#xff0c;使得越来越多的人学习使用vue前端工具&#xff0c;本文主要介…

iOS - 多线程-GCD-队列组

文章目录 iOS - 多线程-GCD-队列组1. 队列组1.1 基本使用步骤 iOS - 多线程-GCD-队列组 开发过程中&#xff0c;有时候想实现这样的效果 多个任务并发执行所有任务执行完成后&#xff0c;进行下一步处理&#xff08;比如回到主线程刷新UI&#xff09; 1. 队列组 可以使用GC…

npm安装时一直idealTree:npm: sill idealTree buildDeps卡住不动

npm安装时一直idealTree:npm: sill idealTree buildDeps卡住不动 解决步骤&#xff1a; 1.去以下的目录中删掉.npmrc文件&#xff08;只在C:\User.npmrc&#xff09; 2.清除缓存&#xff0c;使用npm cache verify 不要用npm cache clean --force&#xff0c;容易出现npm WAR…

【C++】:构造函数和析构函数

目录 前言一&#xff0c;构造函数1.1 什么是构造函数1.2 构造函数的特性1.3 总结 二&#xff0c;析构函数2.1 什么是析构函数2.2 析构函数的特性2.3 总结 前言 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何…

深度学习中的子空间、线性变换和矩阵概念应用

1.表示子空间 在深度学习中&#xff0c;“不同的表示子空间”通常是指模型通过不同的参数&#xff08;例如权重矩阵&#xff09;将输入数据映射到不同的高维空间&#xff0c;这些空间被称为表示子空间。每个子空间都能够捕获输入数据中不同的特征或模式。以下是一些详细解释&am…

新手Pytorch入门笔记-transforms.Compose()

我使用的图片是上图&#xff0c;直接下载即可 transforms.Compose 是PyTorch中的一个实用工具&#xff0c;用于创建一个包含多个数据变换操作的变换对象。这些变换操作通常用于数据预处理&#xff0c;例如图像数据的缩放、裁剪、旋转等。使用transforms.Compose 可以将多个数据…

广工电工与电子技术实验报告-8路彩灯循环控制电路

实验代码 module LED_water (clk,led); input clk; output [7:0] led; reg [7:0] led; integer p; reg clk_1Hz; reg [7:0] current_state, next_state; always (posedge clk) begin if(p25000000-1)begin …

接口测试和Mock学习路线(上)

一、接口测试和Mock学习路线-第一阶段&#xff1a; 掌握接口测试的知识体系与学习路线掌握面试常见知识点之 HTTP 协议掌握常用接口测试工具 Postman掌握常用抓包工具 Charles 与 Fiddler结合知名产品实现 mock 测试与接口测试实战练习 1.接口协议&#xff1a; 需要先了解 O…

微服务组件-反向代理(Nginx)

微服务组件-反向代理(Nginx) Nginx 基本概念 1、nginx是什么&#xff1f; ①、Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器同时也提供了IMAP/POP3/SMTP服务。它是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&a…

Java | Leetcode Java题解之第50题Pow(x,n)

题目&#xff1a; 题解&#xff1a; class Solution {public double myPow(double x, int n) {long N n;return N > 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);}public double quickMul(double x, long N) {if (N 0) {return 1.0;}double y quickMul(x, N / 2);retu…

【UE5】蓝图通信方式

目录 1、直接通信 2、getAllActorsOfClass 3、getAllActorsOfClassWithTag 4、通过射线检测 5、接口 6、事件分发器 7、SpawnActor 8、调用控制台命令 9、关卡蓝图中直接调用 创建两个Actor蓝图 1、直接通信 场景中 2、getAllActorsOfClass 3、getAllActorsOfClassWit…

学习Rust第14天:HashMaps

今天我们来看看Rust中的hashmaps&#xff0c;在 std::collections crate中可用&#xff0c;是存储键值对的有效数据结构。本文介绍了创建、插入、访问、更新和迭代散列表等基本操作。通过一个计算单词出现次数的实际例子&#xff0c;我们展示了它们在现实世界中的实用性。Hashm…

故障诊断 | 基于迁移学习和SqueezeNet 的滚动轴承故障诊断(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 将一维轴承振动信号转换为二维尺度图&#xff08;时频谱图&#xff09;&#xff0c;并使用预训练网络应用迁移学习对轴承故障进行分类。 迁移学习显著减少了传统轴承诊断方法特征提取和特征选择所花费的时间&#xff…

Coursera: An Introduction to American Law 学习笔记 Week 02: Contract Law

An Introduction to American Law 本文是 https://www.coursera.org/programs/career-training-for-nevadans-k7yhc/learn/american-law 这门课的学习笔记。 文章目录 An Introduction to American LawInstructors Week 02: Contract LawKey Contract Law TermsSupplemental Re…

C语言笔试题之计数质数

计数质数 实例要求 给定整数 n &#xff0c;返回 所有小于非负整数 n 的质数的数量&#xff1b;示例&#xff1a; 实例分析 1、要计算小于非负整数 n 的质数的数量&#xff0c;可以使用埃拉托斯特尼筛法&#xff1b;2、这个算法通过标记素数的倍数来找出所有的素数&#x…

RTK负载(4K可见光+高分热成像+超广角+激光测距)四光AI智能识别跟踪吊舱技术详解

无人机光电吊舱的RTK负载&#xff08;4K可见光高分热成像超广角激光测距&#xff09;AI智能识别跟踪吊舱技术是一种高度集成和先进的无人机观测系统。系统结合了无人机的飞行能力和光电吊舱的多功能传感器&#xff0c;通过集成RTK&#xff08;实时动态差分定位&#xff09;技术…