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

news/2024/5/9 19:05:16

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

本系列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.mrgr.cn/p/80142624

相关文章

vue实现录音并转文字功能,包括PC端web,手机端web

vue实现录音并转文字功能&#xff0c;包括PC端&#xff0c;手机端和企业微信自建应用端 不止vue&#xff0c;不限技术栈&#xff0c;vue2、vue3、react、.net以及原生js均可实现。 原理 浏览器实现录音并转文字最快捷的方法是通过Web Speech API来实现&#xff0c;这是浏览器…

Abaqus压电材料分析

404Abaqus-Material: Piezoelectric behavior 压电本构方程:压电材料行为定义所需:密度(optional) 线弹性-刚度矩阵(S_ijkl or D_ijkl) Piezoelectric-压电应变常数矩阵 Dielectric(electric permittivity)-介电常数矩阵压电材料的主要特性参数压电常数: 压电常数是衡量材料压电…

力扣-54. 螺旋矩阵

1.题目 题目地址(54. 螺旋矩阵 - 力扣(LeetCode)) https://leetcode.cn/problems/spiral-matrix/ 题目描述 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。示例 1:输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]…

更易使用,OceanBase开发者工具 ODC 4.2.4 版本升级

亲爱的朋友们&#xff0c;大家好&#xff01;我们的ODC&#xff08;OceanBase Developer Center &#xff09;再次迎来了重要的升级V 4.2.4&#xff0c;这次我们诚意满满&#xff0c;从五个方面为大家精心打造了一个更加易用、贴心&#xff0c;且功能更强的新版本&#xff0c;相…

Redis基本命令

目录 一、包含String、Set数据类型的基本命令 1、添加一个键值对 2、获取key所关联的字符串值 3、同时设置多个key-value 4、获取多个key对应的值 运行结果 5、将给定的value追加到原值的末尾 追加后效果 6、删除单个key 7、同时删除多个key 8、查询包含某个字符的k…

ROS学习--添加依赖相关问题

在自定义话题接口时,步骤如下:新建msg文件夹,并在文件夹下新建xxx.msg 在xxx.msg下编写消息内容并保存 在CmakeLists.txt添加依赖和msg文件目录 在package.xml中添加xxx.msg所需的依赖 编译功能包即可生成python与c++头文件其中在CmakeLists.txt中添加依赖和msg文件目录时需…

小程序 rich-text 解析富文本 图片过大时如何自适应?

在微信小程序中&#xff0c;用rich-text 解析后端返回的数据&#xff0c;当图片尺寸太大时&#xff0c;会溢出屏幕&#xff0c;导致横向出现滚动 查看富文本代码 图片是用 <img 标签&#xff0c;所以写个正则匹配一下图片标签&#xff0c;手动加上样式即可 // content 为后…

界面组件DevExpress Blazor UI v23.2 - 支持.NET 8、全新的项目模版

DevExpress Blazor UI组件使用了C#为Blazor Server和Blazor WebAssembly创建高影响力的用户体验&#xff0c;这个UI自建库提供了一套全面的原生Blazor UI组件&#xff08;包括Pivot Grid、调度程序、图表、数据编辑器和报表等&#xff09;。 DevExpress Blazor控件目前已经升级…

Unity入门实践小项目

必备知识点 必备知识点——场景切换和游戏退出 必备知识点——鼠标隐藏锁定相关 必备知识点——随机数和Unity自带委托 必备知识点——模型资源的导入 实践项目 需求分析 UML类图 代码和资源导入 开始场景 场景装饰 拖入模型和添加脚本让场景动起来 开始界面 先用自己写的GUI…

ios上架驳回记录

原文 Review Environment Submission ID: b097ac72-b1de-4abe-b5a9-81f507bb7e64 Review date: April 25, 2024 Version reviewed: 1.2.3 Guideline 4.3(a) - Design - Spam We noticed your app shares a similar binary, metadata, and/or concept as apps submitted to th…

卡诺图学习

目录1、最小项2、最小项与卡诺图之间转换卡诺图根据最小项填写卡诺图根据逻辑函数填写卡诺图3、卡诺图化简方法 1、最小项逻辑函数表达式可以使用其最小项相加来表示最小项的定义 一个函数的某个乘积项包含了函数的全部变量,其中每个变量都以原变量或反变量的形式出现,且仅出…

SpringBoot---------整合Redis

目录 第一步&#xff1a;引入依赖 第二步&#xff1a;配置Redis信息 第三步&#xff1a;选择Spring Data Redis进行操作Redis数据库 ①操作String类型数据&#xff08;用的少&#xff09; ②操作Object类型数据&#xff08;重要&#xff01;&#xff01;&#xff01;&#x…

jdk版本冲突,java.lang.UnsupportedClassVersionError: JVMCFRE003

主要是编辑器所用的jdk版本和项目用的不一致导致的&#xff0c;虽然编译通过了&#xff0c;但是运行是会报错 选好后点击Apply点击ok&#xff0c;然后重新编译一遍项目就可以了

ESP32引脚笔记

ESP32引脚笔记 ESP32建议使用的引脚 可参考下图Euno开发板引脚模拟输入可采用: 32、33、34、35、36、39 数字输出可采用: 上图右侧引脚 SPI : mosi-23, miso-19, clk-18, cs-5 IIC: scl-22, sda-21仅输入引脚 GPIO34~39是GPIs–仅输入的管脚。这些引脚没有内部上拉或下拉电阻。…

pip成功安装gdal的whl文件后,PyCharm仍报错No module named ‘osgeo’

在根据网上的教程,成功pip install 对应的whl文件后,发现PyCharm仍然显示无法调用osgeo。 出现这样的问题,首先关注自己使用的环境,例如我使用的环境是(见下图)但当我打算卸载gdal库后,发现gdal安装的环境地址和我使用的环境地址不同(如下图)啊,原来是安装gdal的环境…

池化整合多元数据库,zData X 一体机助力证券公司IT基础架构革新

引言 近期&#xff0c;云和恩墨 zData X 多元数据库一体机&#xff08;以下简称 zData X&#xff09;在某证券公司的OA、短信和CRM业务系统中成功上线&#xff0c;标志着其IT基础架构完成从集中式存储向池化高性能分布式存储的转变。zData X 成功整合了该证券公司使用的达梦、O…

12 c++版本的坦克大战

前言 呵呵 这大概是 大学里面的 c 贪吃蛇了吧 有一些 面向对象的理解, 但是不多 这里 具体的实现 就不赘述, 仅仅是 发一下代码 以及 具体的使用 坦克大战 #include<iostream> #include<windows.h> #include<conio.h> #include<ctime> #include…

HarmonyOS ArkUI实战开发—状态管理

一、状态管理 在声明式UI编程框架中&#xff0c;UI是程序状态的运行结果&#xff0c;用户构建了一个UI模型&#xff0c;其中应用的运行时的状态是参数。当参数改变时&#xff0c;UI作为返回结果&#xff0c;也将进行对应的改变。这些运行时的状态变化所带来的UI的重新渲染&…

计算机Windows系统优化小知识

本文涉及计算机Windows系统优化小知识,介绍了注册表、虚拟内存、常用优化工具目录目录什么是注册表优化优化工具什么是注册表注册表是保存所有系统设置数据的存储器。注册表保存了 Windows 运行所需的各种参数和设置,以及应用程序相关的所有信息。从 Windows启动开始,到用户…

CUDA和CUDNN版本切换

介绍了cuda和cudnn版本切换的方法,以及设置环境变量的坑0 背景 在用不同框架做深度学习时,难免会遇到需要不同版本的cuda和cudnn版本的情况,如果把原来版本的卸载掉重新安装新版本,则会影响其它框架的使用,最好的方法是在主机上安装多个版本的cuda和cudnn,需要用到哪种就…