006-自定义枚举注解

自定义枚举注解

  • 一、业务需求描述
            • 1.问题描述
            • 2.解决方案
  • 二、创建一个描述注解
  • 三、创建一个枚举注解
  • 四、创建一个枚举
  • 五、创建一个配置文件
  • 六、场景实战
            • 1.在 @RequestParam 前面使用
            • 2.在非 Model 的实体类上使用
            • 3.在 @RequestBody 对应的实体类中使用
  • 七、效果展示

一、业务需求描述

1.问题描述

在字段使用 @ApiModelProperty 描述枚举字段含义,后续业务拓展,如果有新增加枚举值,每一个用到该枚举的字段的地方都要维护一遍,极其不方便,增加了维护成本。

2.解决方案

增加一个自定义枚举注解 @ApiPropertyEnum,来代替 @ApiModelProperty 。这样以后只需要维护对应的枚举类即可。

二、创建一个描述注解

主要功能:为了统一字段描述,用于映射枚举对应的字段,因为定义枚举字段因人而异

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface SwaggerDisplayEnum {String code() default "code";String desc() default "desc";}

三、创建一个枚举注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiPropertyEnum {// 字段名称String name() default "";// 字段简要描述String value() default "";boolean hidden() default false;// 标识字段是否必填boolean required() default  false;// 指定取值对应的枚举类Class<? extends Enum> enumClazz();
}

四、创建一个枚举

import com.xiaogang.annotation.SwaggerDisplayEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;/*** @Description: 模板业务类型枚举* @Author: hzg* @Date: 2024/9/5 13:52*/
@Getter
@AllArgsConstructor
@SwaggerDisplayEnum(code = "key", desc = "value")
public enum TemplateBusinessTypeEnum {ACQUISITION_TEMPLATE("1","收购订单模板"),SELL_TEMPLATE("2","销售订单模板"),LEASE_TEMPLATE("3","租赁单模板"),LEASE_ATR_TEMPLATE("4","租赁归还模板"),ALLOCATE_TEMPLATE("5","车辆调拨模板"),;String key;String value;}

五、创建一个配置文件

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.ApiPropertyEnum;
import com.ruoyi.common.annotation.SwaggerDisplayEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import springfox.documentation.builders.PropertySpecificationBuilder;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.Annotations;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.spi.service.ExpandedParameterBuilderPlugin;
import springfox.documentation.spi.service.ParameterBuilderPlugin;
import springfox.documentation.spi.service.contexts.ParameterContext;
import springfox.documentation.spi.service.contexts.ParameterExpansionContext;import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;/*** @Description: swagger 关于注解处理* @Auther: hzg* @Date: 2024/11/21 14:40* @version: 1.0*/
@Slf4j
@Configuration
public class SwaggerModelPropertyParameterConfig implements ModelPropertyBuilderPlugin, ParameterBuilderPlugin, ExpandedParameterBuilderPlugin {/*** 是否开启swagger*/@Value("${swagger.enabled}")private boolean enabled;@Overridepublic void apply(ModelPropertyContext context) {if (!enabled) {return;}// 为枚举字段设置注释descForModelEnumFields(context);}@Overridepublic void apply(ParameterContext context) {if (!enabled) {return;}// 为枚举字段设置注释descForMethodParameterEnumFields(context);}@Overridepublic void apply(ParameterExpansionContext context) {if (!enabled) {return;}// 为枚举字段设置注释descForMethodExpandedParameterEnumFields(context);}/*** 返回是否应根据给定的分隔符调用插件*/@Overridepublic boolean supports(DocumentationType documentationType) {return true;}/*** @Description: 针对 Model 里面字段枚举* @Author: hzg* @Date: 2024-11-21 16:57:23* @Params: [modelPropertyContext]* @Return: void*/private void descForModelEnumFields(ModelPropertyContext modelPropertyContext) {if (!modelPropertyContext.getBeanPropertyDefinition().isPresent()) {return;}Optional<ApiPropertyEnum> annotation = Optional.empty();// 找到 @ApiModelProperty 注解修饰的枚举类if (modelPropertyContext.getBeanPropertyDefinition().isPresent()) {annotation = Annotations.findPropertyAnnotation(modelPropertyContext.getBeanPropertyDefinition().get(), ApiPropertyEnum.class);}// 没有@ApiModelProperty 或者 notes 属性没有值,直接返回if (!annotation.isPresent()) {return;}// 生成需要拼接的取值含义描述内容String valueDesc = generateValueDesc(annotation.get());PropertySpecificationBuilder propertySpecificationBuilder = modelPropertyContext.getSpecificationBuilder();propertySpecificationBuilder.description(valueDesc);propertySpecificationBuilder.required(annotation.get().required());propertySpecificationBuilder.isHidden(annotation.get().hidden());}/*** @Description: 针对 非Model controller 方法请求参数【单个字段对象】枚举* @Author: hzg* @Date: 2024-11-21 16:58:35* @Params: [context]* @Return: void*/private void descForMethodParameterEnumFields(ParameterContext context) {Optional<ApiPropertyEnum> apiPropertyEnumOptional = context.resolvedMethodParameter().findAnnotation(ApiPropertyEnum.class);if (!apiPropertyEnumOptional.isPresent()) {return;}ApiPropertyEnum reference = apiPropertyEnumOptional.get();String desc = generateValueDesc(reference);if (StrUtil.isNotEmpty(reference.name())) {context.requestParameterBuilder().name(reference.name());}RequestParameterBuilder requestParameterBuilder = context.requestParameterBuilder();requestParameterBuilder.description(desc);requestParameterBuilder.required(reference.required());}/*** @Description: 针对 非Model controller 方法请求参数【实体对象】枚举* @Author: hzg* @Date: 2024-11-22 13:56:39* @Params: [context]* @Return: void*/private void descForMethodExpandedParameterEnumFields(ParameterExpansionContext context) {Optional<ApiPropertyEnum> apiPropertyEnumOptional = context.findAnnotation(ApiPropertyEnum.class);if (!apiPropertyEnumOptional.isPresent()) {return;}ApiPropertyEnum reference = apiPropertyEnumOptional.get();String desc = generateValueDesc(reference);RequestParameterBuilder requestParameterBuilder = context.getRequestParameterBuilder();requestParameterBuilder.description(desc);requestParameterBuilder.required(reference.required());context.getParameterBuilder().hidden(reference.hidden());}private String generateValueDesc(ApiPropertyEnum propertyReference) {Class<? extends Enum> rawPrimaryType = propertyReference.enumClazz();SwaggerDisplayEnum swaggerDisplayEnum = AnnotationUtils.findAnnotation(rawPrimaryType,SwaggerDisplayEnum.class);String enumFullDesc = Arrays.stream(rawPrimaryType.getEnumConstants()).filter(Objects::nonNull).map(enumConsts -> {assert swaggerDisplayEnum != null;Object fieldValue = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.code());Object fieldDesc = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.desc());return enumConsts + "(" + fieldValue + "," + fieldDesc + ")";}).collect(Collectors.joining(";"));return propertyReference.value() + "【" + enumFullDesc + "】";}}

六、场景实战

1.在 @RequestParam 前面使用
@ApiOperation(value = "查询8实体信息",tags = {"查询API"})
@GetMapping("/test1")
public TestDateTimeFormat test1(@ApiParam(value = "传ID", required = false, name = "id") String id,@ApiParam(value = "店铺状态") @RequestParam(name = "customerParticipantType", required = true) String customerParticipantType,@ApiPropertyEnum(value = "参数一",name = "param1",enumClazz = TemplateBusinessTypeEnum.class,required = true) @RequestParam(name = "param1", required = true) String param1){TestDateTimeFormat testDateTimeFormat = new TestDateTimeFormat();testDateTimeFormat.setName("xiaogang");testDateTimeFormat.setPhoneNumber("111111111111");testDateTimeFormat.setAddress("beijing");testDateTimeFormat.setBirthday(new Date());return testDateTimeFormat;
}
2.在非 Model 的实体类上使用
@ApiOperation(value = "查询7实体信息", tags = {"查询API"})
@GetMapping("/test1")
public TestJsonFormat test1(TestClass testDateTimeFormat) {TestJsonFormat testJsonFiled = new TestJsonFormat();testJsonFiled.setName("xiaogang");testJsonFiled.setPhoneNumber("111111111111");testJsonFiled.setAddress("beijing");testJsonFiled.setBirthday(new Date());return testJsonFiled;
}
@Data
@AllArgsConstructor
public class TestClass {@ApiPropertyEnum(value = "测试姓名", enumClazz = TemplateBusinessTypeEnum.class,required = true,hidden = false)private String name;private int age;private String address;}
3.在 @RequestBody 对应的实体类中使用

当然也可以直接在Response返回体实体对象中直接使用

@ApiOperation(value = "新增",tags = {"查询API"})
@PostMapping("/test2")
public void test2(@RequestBody TestDateTimeFormat testDateTimeFormat){log.info("实体类:{}",testDateTimeFormat);// 实体类:TestJsonFormat(name=小明, address=北京市, phoneNumber=123456789, birthday=Thu Oct 10 14:42:20 CST 2024)
}
@Data
@ApiModel(description = "日期实体")
public class TestDateTimeFormat {@ApiModelProperty(value = "姓名")private String name;@ApiModelProperty(value = "地址")private String address;@ApiPropertyEnum(value = "电话号码", enumClazz = TemplateBusinessTypeEnum.class,required = true)private String phoneNumber;@ApiModelProperty(value = "生日")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date birthday;}

七、效果展示

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

数据库表设计范式

华子目录 MYSQL库表设计&#xff1a;范式第一范式&#xff08;1NF&#xff09;第二范式&#xff08;2NF&#xff09;第三范式&#xff08;3NF&#xff09;三范式小结巴斯-科德范式&#xff08;BCNF&#xff09;第四范式&#xff08;4NF&#xff09;第五范式&#xff08;5NF&…

力扣刷题--21.合并两个有序链表

I am the best &#xff01;&#xff01;&#xff01; 题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2…

【java-Neo4j 5开发入门篇】-最新Java开发Neo4j

系列文章目录 前言 上一篇文章讲解了Neo4j的基本使用&#xff0c;本篇文章对Java操作Neo4j进行入门级别的阐述&#xff0c;方便读者快速上手对Neo4j的开发。 一、开发环境与代码 1.docker 部署Neo4j #这里使用docker部署Neo4j,需要镜像加速的需要自行配置 docker run --name…

三层交换机静态路由实验

1、前置知识 2、实验目的 3、实验器材&#xff1a; 3560-23PS交换机2台、主机4台、交叉线1根和直通网线4根。 4、实验规划及拓扑 实验要求&#xff1a; &#xff08;1&#xff09;在交换机A和交换机B上分别划分基于端口的VLAN&#xff1a; 交换机 VLAN 端口成员 交换机…

基于Java Springboot付费自习室管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

深度学习笔记24_天气预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 一、我的环境 1.语言环境&#xff1a;Python 3.9 2.编译器&#xff1a;Pycharm 3.深度学习环境&#xff1a;TensorFlow 2.10.0 二、GPU设置…

node报错:Error: Cannot find module ‘express‘

报错信息&#xff1a; Error: Cannot find module express 分析原因&#xff1a; 项目中需要express工具&#xff0c;但是import引入不进来&#xff0c;说明在这个项目中我们本没有对express工具包进行install&#xff0c;从我们项目中的package.json也可以看到&#xff08;并…

【课堂笔记】隐私计算实训营第四期:“隐语”可信隐私计算开源框架

“隐语”可信隐私计算开源框架 隐语架构一览隐语架构拆解产品层算法层PSI/PIR数据分析&#xff08;Data Analysis&#xff09;联邦学习&#xff08;Federated Learning&#xff09; 计算层混合编译调度——RayFedSPUHEUTEEUYACL 资源层KUSCIA 互联互通跨域管控 隐语架构一览 隐…

Halo 正式开源: 使用可穿戴设备进行开源健康追踪

在飞速发展的可穿戴技术领域&#xff0c;我们正处于一个十字路口——市场上充斥着各式时尚、功能丰富的设备&#xff0c;声称能够彻底改变我们对健康和健身的方式。 然而&#xff0c;在这些光鲜的外观和营销宣传背后&#xff0c;隐藏着一个令人担忧的现实&#xff1a;大多数这些…

Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化时代&#xff0c;…

嵌入式中利用QT实现服务器与客户端方法

大家好,今天主要给大家分享一下,如何使用QT中TCP协议进行传输控制,它是一种面向连接的,可靠的基于字节流的传输层控制协议。 第一:Linux中网络通信简介 TCP通信必须建立TCP连接,通信端分为客户端和服务端。服务端通过监听某个端口来监听是否有客户端连接进来,如果有连接…

网络安全,文明上网(6)网安相关法律

列举 1. 《中华人民共和国网络安全法》&#xff1a; - 这是中国网络安全的基本法律&#xff0c;于2017年6月1日开始实施。该法律明确了网络运营者的安全保护义务&#xff0c;包括采取数据分类、重要数据备份和加密等措施。 2. 《中华人民共和国数据安全法》&#xff1a; …

Vscode写markdown快速插入python代码

如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…

【前端】第12节:Vue3新特性

引入 说起 vue3 的新特性&#xff0c;就会不由自主想到 vue3 和 vue2 之间的差异&#xff0c;例如&#xff1a;双向绑定、根节点数量、生命周期、this 等等&#xff0c;详细可以见这篇文章&#xff08;参考&#xff09;—— vue2和vue3的差异整理&#xff08;轻松过度到vue3&a…

Linux 进程概念与进程状态

目录 1. 冯诺依曼体系结构2. 操作系统&#xff08;Operator System&#xff09;2.1 概念2.2 设计OS的目的2.3 系统调用和库函数概念 3. 进程概念3.1 描述进程 - PCB3.2 task_struct3.3 查看进程3.4 通过系统调用获取进程标识符PID&#xff0c; PPID3.5 通过系统调用创建fork 4.…

滑动窗口篇——如行云流水般的高效解法与智能之道(1)

前言&#xff1a; 上篇我们介绍了双指针算法&#xff0c;并结合具体题目进行了详细的运用讲解。本篇我们将会了解滑动窗口。滑动窗口是一种常用的算法技巧&#xff0c;主要用于处理子数组、子串等具有“窗口”特性的题目。柳暗花明&#xff0c;乃巧解复杂问题的高效之道。 一. …

网络安全-企业环境渗透2-wordpress任意文件读FFmpeg任意文件读

一、 实验名称 企业环境渗透2 二、 实验目的 【实验描述】 操作机的操作系统是kali 进入系统后默认是命令行界面 输入startx命令即可打开图形界面。 所有需要用到的信息和工具都放在了/home/Hack 目录下。 本实验的任务是通过外网的两个主机通过代理渗透到内网的两个主机。…

DB-GPT V0.6.2 版本更新:牵手libro社区、GraphRAG图谱构建能力增强等

DB-GPT V0.6.2版本现已上线&#xff0c;快速预览新特性&#xff1a; 新特性 1、DB-GPT 社区和 libro 社区共同发布 AWEL Notebook 功能 libro&#xff1a;灵活定制、轻松集成的 Notebook 产品方案。 社区地址&#xff1a;https://github.com/difizen/libro 使用教程&#xf…

GPT1.0 和 GPT2.0 的联系与区别

随着自然语言处理技术的飞速发展&#xff0c;OpenAI 提出的 GPT 系列模型成为了生成式预训练模型的代表。作为 GPT 系列的两代代表&#xff0c;GPT-1 和 GPT-2 虽然在架构上有着继承关系&#xff0c;但在设计理念和性能上有显著的改进。本文将从模型架构、参数规模、训练数据和…

本地部署与外部部署有何不同?

什么是本地部署&#xff1f; 本地部署&#xff08;通常缩写为“on-prem”&#xff09;是指在公司自己的设施或数据中心内托管的软件和基础设施。与基于云的解决方案不同&#xff0c;本地部署系统让企业对其数据、硬件和软件配置拥有完全的控制权。这种设置非常适合那些优先考虑…