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

news2024/12/23 8:17:57

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

本系列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;

    @Override
    public 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;
    }

    /**
     * 序列化
     */
    @Override
    public 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. 获取注解 @Dict
            Dict 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
    @Primary
    ObjectMapper 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.coloradmin.cn/o/1627921.html

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

相关文章

总结一下背包里的顺序和是否逆序

1.对于01背包而言&#xff0c;一维压缩态只能物品到背包且需要逆序 2.对应多重背包而言&#xff0c;组合数物品到背包&#xff0c;排列数背包到物品&#xff0c;且都需要正序

军工单位安全内网文件导出,怎样做到严密的安全管控?

军工单位是指承担国家下达的军事装备、产品研制、生产计划任务的企、事业单位&#xff0c;主要包括电子工业部、航空工业总公司、航天工业总公司、兵器工业总公司、核工业总公司、船舶工业总公司、中国工程物理研究院及各省国防工业办公室等。 军工单位的特点主要体现在以下几个…

光伏无人机:巡检无人机解决巡检难题

随着科技的飞速发展&#xff0c;无人机技术已经广泛应用于各个领域&#xff0c;其中光伏无人机在解决光伏电站巡检难题方面发挥了重要作用。光伏无人机以其高效、精准、安全的特点&#xff0c;为光伏电站的巡检工作带来了革命性的变革。 光伏电站通常位于广阔的户外场地&#x…

【问题实操】银河高级服务器操作系统实例分享,配置hugepages启动异常

1.问题现象 某运营商国产服务器操作系统项目&#xff0c;部署Kylin-Server-0524-aarch64服务器系统&#xff0c;内核从4.19.90-24.4升级到4.19.90-25.14。在grub中配置huagepages大页内存后&#xff0c;系统在内核启动阶段黑屏&#xff0c;只显示一个光标。grub配置如下图&…

AI大模型探索之路-训练篇5:大语言模型预训练数据准备-词元化

系列文章目录&#x1f6a9; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据…

什么样的内外网文档摆渡,可以实现安全高效传输?

内外网文档摆渡通常指的是在内网&#xff08;公司或组织的内部网络&#xff09;和外网&#xff08;如互联网&#xff09;之间安全地传输文件的过程。这个过程需要特别注意安全性&#xff0c;因为内网往往包含敏感数据&#xff0c;直接连接内网和外网可能会带来安全风险。因此会…

12.接口自动化学习-Yaml学习

1.配置文件作用 配置文件项目角度&#xff1a; &#xff08;1&#xff09;现成的应用–第三方组件 mysql–数据库–my.conf tomcat–web服务器–server.xml 修改&#xff1a;连接数/端口 redis–缓存服务器–redis.conf 修改配置 jemeter–压测工具–jemeter.properties–修改…

linux支持vGPU方案

1&#xff0c;查询gpu型号&#xff1a;lspci | grep "NVIDIA\|VGA" PCI Devices 2&#xff0c;下载驱动 官方驱动 | NVIDIA 3&#xff0c;安装 sudo sh NVIDIA-Linux-x86_64-440.118.02.run -no-x-check -no-nouveau-check -no-opengl-files参数说明&#xff1a; …

网盘——进入文件夹

本文主要讲解网盘的文件操作中进入文件夹的部分&#xff0c;具体实现步骤如下&#xff1a; 1、具体步骤如下&#xff1a; A、客户端发送进入文件夹的请求&#xff08;该请求包含目录信息以及要进入的文件夹名字&#xff09; B、服务器收到该请求之后&#xff0c;服务器首先判…

基于springboot的考勤管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

C#基础之数组

数组 文章目录 数组1、概念2、数组的声明3、数组的使用思考1 找出随机数中的最大值&#xff0c;最小值思考2 数组值前后交换思考3 输入成绩&#xff0c;比较出最大、最小值思考4 生成一个5X5的花格子 二维数组交错数组 1、概念 数组是存储一组相同类型数据的集合 数组分为一维…

【嵌入式AI开发】轻量级卷积神经网络MobileNetV1网络详解

传统卷积神经网络,内存需求大、运算量大导致无法在移动设备以及嵌入式设备上运行。模型研究得初衷就是服务于社会,应用到实际生活中,让深度学习技术服务于生活。 万物互联时代,智能终端部署模型到本地,不需连接因特网/云服务器,在边缘终端进行边缘计算。保障数据隐私,不…

【数据结构】三、栈和队列:2.顺序栈共享栈(顺序栈的初始化,判空,进栈,出栈,读取栈顶,顺序栈实例)

文章目录 1.顺序栈1.1初始化1.2判空1.3进栈1.4出栈1.5读取栈顶1.6销毁栈❗1.7顺序栈c实例 2.共享栈2.1初始化2.2判满 1.顺序栈 用顺序存储实现的栈 顺序栈的缺点&#xff1a;栈的大小不可变。 #define MaxSize 10 //定义栈中元素的最大个数 typedef struct{ElemType data[…

IDEA 中如何通过连接数据库自动生成代码

目录 1、IDEA 中安装 MyBatisX 插件 2、点击 IDEA 右侧的 database 数据库按钮&#xff0c;点击新建数据源 Data Source 3、编辑数据库连接信息 4、选择你要生成代码的数据库表 5、编辑你代码生成的基本路径以及一些配置项 6、选择annotation&#xff1a;mybatis-plus3&a…

美国洛杉矶站群服务器如何提高网站排名?

美国洛杉矶站群服务器怎么样?美国洛杉矶站群服务器如何提高网站排名?Rak部落小编为您整理发布美国洛杉矶站群服务器如何提高网站排名? 美国洛杉矶站群服务器可以通过以下几种方式帮助提高网站排名&#xff1a; - **提升网站性能**&#xff1a;美国站群服务器通常配备高速CPU…

eclipse导入工程提示Project has no explicit encoding set

eclipse导入工程提示Project has no explicit encoding set 文章目录 eclipse导入工程提示Project has no explicit encoding set一、Eclipse的工程导入二、可能的问题1.在工程名下有黄色叹号 一、Eclipse的工程导入 用Eclipse的导入可以将原有工程导入到新环境中 具体方法是&…

phpstorm 设置变量,自动补全代码

效果 进入设置->实时模板->PHP->添加 添加动态模板->完善写法 定义->选择PHP->应用就行

OpenStack云计算(十四)——综合演练手动部署OpenStack,

本项目的项目实训可以完全参考教材配套讲解的详细步骤实施&#xff0c;总体来说实训工作量较大&#xff0c;可根据需要选做&#xff0c;重点观看配套的微课视频。 项目实训一 【实训题目】 搭建OpenStack云平台基础环境 【实训目的】 掌握OpenStack基础环境的安装和配置方…

mysql8.0免安装版windows

1.下载 MySQL下载链接 2.解压与新建my.ini文件 解压的路径最好不要有中文路径在\mysql-8.0.36-winx64文件夹下新建my.ini文件&#xff0c;不建data文件夹(会自动生成) [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录(尽量用双斜杠\\,单斜杠\可能会报错) basedirD:\…

如何在vue3+vite中优雅的使用iconify图标

前言 从Vue2迁移到Vue3&#xff0c;在使用上有着很大的差别。本文的话主要是针对图标的使用差别上进行分析&#xff0c;同时给出基于iconify图标库中unplugin-icons的用法。这里特殊说明一下&#xff1a;其实element-plus中用到的图标也是基于iconify图标库的&#xff0c;在我们…