Spring后端直接用枚举类接收参数,自定义通用枚举类反序列化器

在使用枚举类做参数时,一般会让前端传数字,后端将数字转为枚举类,当枚举类很多时,很可能不知道这个code该对应哪个枚举类。能不能后端直接使用枚举类接收参数呢,可以,但是受限。
Spring反序列默认使用的是Jacskon,反序列化枚举类时,可以根据枚举类的name或ordinal属性进行反序列化,这是因为Jacskon内置了EnumDeserializer,它可以根据name或ordinal属性进行反序列化。

public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException{if (p.hasToken(JsonToken.VALUE_STRING)) {return _fromString(p, ctxt, p.getText());}// But let's consider int acceptable as well (if within ordinal range)if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {if (_isFromIntValue) {// 根据namereturn _fromString(p, ctxt, p.getText());}// 根据ordinalreturn _fromInteger(p, ctxt, p.getIntValue());}if (p.isExpectedStartObjectToken()) {return _fromString(p, ctxt,ctxt.extractScalarFromObject(p, this, _valueClass));}return _deserializeOther(p, ctxt);}

比如我们有一个接口:

    @PostMapping("/product")@ResponseBodypublic void product(@RequestBody Product product) {System.out.println(product.getStatus());System.out.println("ok");}public class Product {private Status status;private String name;// getter and setter
}public enum Status {ON_LINE(1000, "在线"),OFF_LINE(2000, "下线");private int code;private String desc;Status(int code, String desc) {this.code = code;this.desc = desc;}
}

PostMan请求
在这里插入图片描述

这两种写法都可以。
status使用数字方式,只能是0或1,即枚举类的ordinal值.但是这种方式和我们的使用习惯不同,我们一般会自定义code,而不是使用ordinal。如果向根据自定义code反序列化枚举类,该如何实现呢?

参照Spring的方式,大概思路应该是自定义一个反序列化器,然后再需要使用自定义反序列化器的对象上加上@JsonDeserialize以覆盖Spring默认使用的EnumDeserializer。

自定义枚举类反序列化器

public class StatusDeser extends JsonDeserializer<Status> {@Overridepublic Status deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {final int code = p.getIntValue();return Status.getByCode(code);}
}

给Status增加一个getByCode,且指定反序列化器。

@JsonDeserialize(using = StatusDeser.class)
public enum Status {ON_LINE(1000, "在线"),OFF_LINE(2000, "下线");private int code;private String desc;Status(int code, String desc) {this.code = code;this.desc = desc;}public static Status getByCode(int code) {final Status[] values = Status.values();for (int i = 0; i < values.length; i++) {if (values[i].code == code) {return values[i];}}throw new RuntimeException("不合法的code值");}
}

此时就可以这样传值了
在这里插入图片描述
注意,如果直接使用枚举类做接收参数,接口和body应该这样写

    @PostMapping("/status")@ResponseBodypublic void status(@RequestBody Status status) {System.out.println(status);System.out.println("ok");}

在这里插入图片描述

统一处理枚举类

上面自定义的反序列化器可以处理某一种枚举,如果枚举很多,每写一个枚举类都要写一个与之对应的反序列化器,有点麻烦,而且一旦忘记写或不知道要写就麻烦了。如何对枚举类做统一处理呢?可以让枚举类都继承一个接口,我们的反序列化器对接口类型处理。

定义统一接口

public interface BaseEnum {Integer getCode();
}

统一接口中有一个返回code值的方法,前端传这个code值,我们根据这个code值反序列化出对应的枚举对象。

定义统一反序列化器

因为我们的接口下可以有多种实现类枚举,那我们在反序列化的时候要反序列化成哪种枚举类呢?怎么在运行时知道我们的目标枚举类呢?这个时候要使用StdDeserializer和ContextualDeserializer。
StdDeserializer中有目标对象类型,ContextualDeserializer可以在反序列化时获取目标对象类型信息。两者结合就可以在运行时获取到目标对象类型信息,动态创建反序列化器。
在这里插入图片描述

public class BaseEnumDeserial extends StdDeserializer<BaseEnum> implements ContextualDeserializer {protected BaseEnumDeserial(Class<?> vc) {super(vc);}// Jackson通过反射创建BaseEnumDeserial对象,这个对象不会用于正真的反序列化,因为它没有真实的类信息// 真正用于反序列化的对象会通过createContextual重新创建public BaseEnumDeserial() {this(BaseEnum.class);}@Overridepublic BaseEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {// 反序列目标对象继承自BaseEnum且是枚举类型if (BaseEnum.class.isAssignableFrom(_valueClass) && Enum.class.isAssignableFrom(_valueClass)) {final int code = p.getIntValue();BaseEnum[] enumConstants = (BaseEnum[]) _valueClass.getEnumConstants();for (int i = 0; i < enumConstants.length; i++) {if (code == enumConstants[i].getCode()) {return enumConstants[i];}}}return null;}@Overridepublic JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {// 从上下文获取目标对象类型final Class<?> rawClass = ctxt.getContextualType().getRawClass();// new出来的反序列化器不用我们缓存,一种类型的反序列化器的createContextual方法只会执行一次,执行后的结果Jackson自己会缓存return new BaseEnumDeserial(rawClass);}
}

注意,有的地方文章使用property获取目标对象类型,只有在枚举类作为其他对象的属性被反序列化时,property才有值,如果时直接反序列化枚举对象,则property是null,所以还是直接从上下文中取类型比较好。

// property可能为null
final Class<?> rawClass = property.getType().getRawClass();

枚举类改造

// 反序列器加在接口上,就不用在每个枚举类上加了
@JsonDeserialize(using = BaseEnumDeserial.class)
public interface BaseEnum {Integer getCode();
}
// 实现BaseEnum 接口
public enum Status implements BaseEnum {ON_LINE(1000, "在线"),OFF_LINE(2000, "下线");private int code;private String desc;Status(int code, String desc) {this.code = code;this.desc = desc;}// 删除了getByCode方法@Overridepublic Integer getCode() {return code;}
}

定义接口

    @PostMapping("/product")@ResponseBody// 枚举类在其他对象中public void product(@RequestBody Product product) {System.out.println(product.getStatus());System.out.println("ok");}@PostMapping("/status")@ResponseBody// 直接反序列化枚举类public void status(@RequestBody Status status) {System.out.println(status);System.out.println("ok");}

在这里插入图片描述
此时,就可以前端传数字,后端直接用枚举类型接收,不用再做数字到枚举类型的转化了。改造之后,下面这种方式就不行了,只能使用code反序列化,而不能使用name反序列化了。
在这里插入图片描述

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

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

相关文章

投资学 01 定义,投资

02. 03. 3.1 直接投资&#xff1a;使用方和提供方是一个人

yolov8模型在Xray图像中关键点检测识别中的应用【代码+数据集+python环境+GUI系统】

yolov8模型在X yolov8模型在Xray图像中关键点检测识别中的应用【代码数据集python环境GUI系统】 1.背景意义 X射线是一种波长极短、穿透能力极强的电磁波。当X射线穿透物体时&#xff0c;不同密度和厚度的物质会吸收不同程度的X射线&#xff0c;从而在接收端产生不同强度的信号…

WordPress建站钩子函数及使用

目录 前言&#xff1a; 使用场景&#xff1a; 一、常用的wordpress钩子&#xff08;动作钩子、过滤器钩子&#xff09; 1、动作钩子&#xff08;Action Hooks&#xff09; 2、过滤器钩子&#xff08;Filter Hooks&#xff09; 二、常用钩子示例 1、添加自定义 CSS 和 JS…

实战OpenCV之直方图

基础入门 直方图是对数据分布情况的图形表示&#xff0c;特别适用于图像处理领域。在图像处理中&#xff0c;直方图通常用于表示图像中像素值的分布情况。直方图由一系列矩形条&#xff08;也被称为bin&#xff09;组成&#xff0c;每个矩形条的高度表示某个像素值&#xff08;…

信息安全工程师(8)网络新安全目标与功能

前言 网络新安全目标与功能在当前的互联网环境中显得尤为重要&#xff0c;它们不仅反映了网络安全领域的最新发展趋势&#xff0c;也体现了对网络信息系统保护的不断加强。 一、网络新安全目标 全面防护与动态应对&#xff1a; 目标&#xff1a;建立多层次、全方位的网络安全防…

微服务常见面试题总结

文章目录 1 概念1.1 你对微服务是怎么理解的1.2 微服务带来了哪些挑战&#xff1f;1.3 说下微服务有哪些组件&#xff1f;&#x1f525; 2 注册中心2.1 注册中心有什么用&#xff1f;&#x1f525;2.2 SpringCloud可以选择哪些注册中心&#xff1f;2.3 说下Eureka 和 Nacos的区…

java日志框架之Log4j

文章目录 一、Log4j简介二、Log4j组件介绍1、Loggers (日志记录器)2、Appenders&#xff08;输出控制器&#xff09;3、Layout&#xff08;日志格式化器&#xff09; 三、Log4j快速入门四、Log4j自定义配置文件输出日志1、输出到控制台2、输出到文件3、输出到数据库 五、Log4j自…

【Docker】基于Dockerfile创建携带最新cuda版本以及与其配套的cudnn环境的ubuntu20.04镜像

基于Dockerfile创建携带最新cuda版本以及与其配套的cudnn环境的ubuntu20.04镜像 最近涉及到一个在 x86 上机器上使用英伟达GPU资源做加速计算的项目&#xff0c;包括模型推理加速和编解码加速。 为了保持两个模块开发cuda环境的一致性&#xff0c;故构建该基础镜像。 编写Docke…

WPF自定义Dialog模板,内容用不同的Page填充

因为审美的不同&#xff0c;就总有些奇奇怪怪的需求&#xff0c;使用框架自带的对话框已经无法满足了&#xff0c;这里记录一下我这边初步设计的对话框。别问为啥要用模板嵌套Page来做对话框&#xff0c;问就是不想写太多的窗体。。。。 模板窗体&#xff08;XAML&#xff09;…

植物大战僵尸【源代码分享+核心思路讲解】

植物大战僵尸已经正式完结&#xff0c;今天和大家分享一下&#xff0c;话不多说&#xff0c;直接上链接&#xff01;&#xff01;&#xff01;&#xff08;如果大家在运行这个游戏遇到了问题或者bug&#xff0c;那么请私我谢谢&#xff09; 大家写的时候可以参考一下我的代码思…

如何在堆和栈上分别创建一个`QObject`子类对象

在堆上创建QObject子类对象的例子 在Qt中&#xff0c;QObject是许多Qt类和对象的基类&#xff0c;提供了对象模型的核心功能&#xff0c;如信号和槽机制、事件处理等。当一个QObject对象在堆上创建时&#xff0c;意味着这个对象是通过new操作符在堆&#xff08;heap&#xff0…

基于单片机的智能校园照明系统

由于校园用电量较大&#xff0c;本设计可以根据实际环境情况的改变&#xff0c;实现实时照明的控制。本设计以单片机芯片为控制芯片&#xff0c;热释电传感器采集教室中学生出入的信息&#xff0c;并把信息传递给单片机芯片&#xff0c;单片机芯片根据传感器传递过来的信息来控…

【STL】 set 与 multiset:基础、操作与应用

在 C 标准库中&#xff0c;set 和 multiset 是两个非常常见的关联容器&#xff0c;主要用于存储和管理具有一定规则的数据集合。本文将详细讲解如何使用这两个容器&#xff0c;并结合实例代码&#xff0c;分析其操作和特性。 0.基础操作概览 0.1.构造&#xff1a; set<T&…

Project Online 专业版部署方案

目录 前言 1. 部署前的准备 1.1. 硬件和软件要求 1.2. 网络和安全性要求 1.3. 用户角色和权限 2. 注册和订阅 Project Online 专业版 2.1. 访问 Office 365 管理中心 2.2. 订阅 Project Online 2.3. 激活服务 3. 初始配置 3.1. 创建 Project Online 实例 3.2. 配置基…

聚簇索引和非聚簇索引的定义和区别

1.聚簇索引&#xff1a; 也叫聚集索引、主键索引&#xff0c;是将索引和数据放在一起&#xff0c;聚簇索引的 BTree 的叶子节点存放的是实际数据&#xff0c;所有完整的用户记录都存放在主键索引的 BTree 的叶子节点里&#xff1b;找到索引也就找到了数据。数据行的物理顺序与…

【深度学习】(1)--神经网络

文章目录 深度学习神经网络1. 感知器2. 多层感知器偏置 3. 神经网络的构造4. 模型训练损失函数 总结 深度学习 深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向。 从上方的内容包含结果&#xff0c;我们可以知道&#xff0c;在学习深度学…

Android 开发高频面试题之——Flutter

Android开发高频面试题之——Java基础篇 flutter高频面试题记录 Flutter1. dart中的作用域与了解吗2. dart中. .. ...分别是什么意思?3. Dart 是不是单线程模型?如何运行的?4. Dart既然是单线程模型支持多线程吗?5. Future是什么6. Stream是什么7. Flutter 如何和原生交互…

身份安全风险不断上升:企业为何必须立即采取行动

在推动安全AI 模型的过程中&#xff0c;许多组织已转向差异隐私。但这种旨在保护用户数据的工具是否阻碍了创新&#xff1f; 开发人员面临一个艰难的选择&#xff1a;平衡数据隐私或优先考虑精确结果。差分隐私可以保护数据&#xff0c;但通常以牺牲准确性为代价——对于医疗保…

基于51单片机的手环设计仿真

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;DHT11温湿度采集温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器模拟水位传感器检测水位&#xff0c;通过LCD1602显示信息&#xff0c;然后在程序里设置好是否…

C++/CLI编程知识点小记

1.前言 本篇博文并非详细的C/CLI教程&#xff0c;仅是博主就学习和实践总结的部分知识点记录。 第一次接触C/CLI是2017年了&#xff0c;用C编写底层库&#xff0c;C/CLI编写wrapper层&#xff0c;在C#项目中进行调用&#xff0c;开发应用。 2.内容 C/CLI是一种混合编程&…