Java:Springboot和React中枚举值(数据字典)的使用
目录
- 1、开发中的需求
- 2、实现效果
- 3、后端代码
- 4、前端代码
- 5、接口数据
- 6、完整代码
- 7、参考文章
1、开发中的需求
开发和使用过程中,通常会涉及四个角色:数据库管理员、后端开发人员、前端开发人员、浏览者
- 数据库使用int类型的数值进行存储(eg: 0、1、2)
- Java代码使用enum枚举类型的对象进行逻辑判断(eg: SexEnum.UNKOWN SexEnum.MAN、SexEnum.WOMAN)
- 接口返回枚举值的字符串形式用于必要的逻辑判断(eg: UNKOWN、MAN、WOMAN)
- 显示给用户查看(eg: 未知、男性、女性)
使用方 | 数值类型 | 用途 | 示例 |
---|---|---|---|
数据库 | int数值 | 存储 | 0、1、2 |
后端代码 | Enum枚举类 | 逻辑判断 | SexEnum.UNKOWN SexEnum.MAN、SexEnum.WOMAN |
前端代码 | string常量字符串 | 逻辑判断 | UNKOWN、MAN、WOMAN |
用户视图 | string字符串 | 查看 | 未知、男性、女性 |
假设:
1、如果后端返回数字,数字本身没有很直观的意思,不便于前端人员检查问题,如果书写错误,同样会导致不容易发现的问题。
2、如果后端返回用户友好的字符串,前端如果需要做逻辑判断就很不好,毕竟不知道产品经理什么时候会把显示的内容修改掉,比如:男性 改为 男
3、如果后端返回枚举类型的常量字符串,那每次需要显示的时候,都必须做一个映射转换,前端人员也很苦恼
综上:
后端同时返回 枚举字符串 和 用户友好的字符串 比较好,既方便前端人员做逻辑判断,也方便给用户展示;
一般情况下,枚举类型统一在后端维护,如果需要修改,也只需要修改一个地方就可以
如果,前端也需要使用枚举值进行逻辑判断,那么前端也需要和后端约定好的映射关系自己定义好枚举,可以直接使用常量字符串作为枚举,前端显示的值可以和后端约定好,什么数值,显示什么字符串
同时,需要给前端返回一个枚举映射关系表,用于下拉选择等业务
2、实现效果
1、列表页
- 顶部筛选类型由接口返回,接口增加类型后,前端代码不用修改,直接生效
- 列表
性别
列,直接显示后端返回sexLabel
的字段 - 列表
颜色
列,由于前端需要根据不同的值,做一些逻辑判断,所以前端代码也需要做好枚举,做逻辑判断,此时需要注意默认值
,预防后端增加类型之后,前端代码增加容错
2、添加页
性别
和颜色
都使用后端返回的配置数据即可,后端增加类型数据之后,前端无需修改代码
3、后端代码
配合MyBatis-Plus使用,可以很容易进行数据库和代码之间的转换
定义3个值,由后端代码统一维护
code # 用于数据库存储
value # 用于后端和前端的逻辑判断
label # 用户展示给用户
如果有其他属性,也可以增加
先定义一个通用的枚举接口
package com.example.demo.enums;/*** 字典枚举接口*/
public interface IDictEnum {Integer getCode();String getLabel();String name();// @JsonValue // 标记响应json值default String getValue() {return this.name();}
}
定义枚举类
package com.example.demo.enums;import com.baomidou.mybatisplus.annotation.EnumValue;/*** 性别枚举*/
public enum SexEnum implements IDictEnum {/*** 男性*/MAN(1, "男性"),/*** 女性*/WOMEN(2, "女性");/*** 存储值*/@EnumValue // 配置 mybatis-plus 使用 标记数据库存的值是 codeprivate final Integer code;/*** 显示值*/private final String label;SexEnum(Integer code, String label) {this.code = code;this.label = label;}@Overridepublic Integer getCode() {return this.code;}@Overridepublic String getLabel() {return this.label;}
}
自动扫描枚举类
package com.example.demo.config;import com.example.demo.vo.EnumVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 枚举配置类*/
@Slf4j
@Component
public class DictEnumConfig {// 通同匹配private static final String RESOURCE_PATTERN = "/**/*Enum.class";// 扫描的包名private static final String BASE_PACKAGES = "com.example.demo.enums";private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();@Bean(name = "enumConfig")public Map<String, List<EnumVO>> enumConfig() {Map<String, List<EnumVO>> enumMap = new HashMap<>();try {// 根据classname生成class对应的资源路径,需要扫描的包路径//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +String pattern = ClassUtils.convertClassNameToResourcePath(BASE_PACKAGES) + RESOURCE_PATTERN;// 获取classname的IO流资源Resource[] resources = resourcePatternResolver.getResources(pattern);// MetadataReaderFactory接口 ,MetadataReader的工厂接口。允许缓存每个MetadataReader的元数据集MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);for (Resource resource : resources) {if (resource.isReadable()) {// 通过class资源(resource)生成MetadataReaderMetadataReader reader = readerFactory.getMetadataReader(resource);// 获取class名String className = reader.getClassMetadata().getClassName();Class<?> clz = Class.forName(className);if (!clz.isEnum()) {continue;}// 将枚举类名首字母转小写,去掉末尾的EnumenumMap.put(clz.getSimpleName(), this.enumToList(clz));}}} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return enumMap;}public List<EnumVO> enumToList(Class<?> dictEnum) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {List<EnumVO> list = new ArrayList<>();Method valuesMethod = dictEnum.getMethod("values");Object[] values = (Object[]) valuesMethod.invoke(null);for (Object obj : values) {EnumVO enumVO = new EnumVO();BeanUtils.copyProperties(obj, enumVO);list.add(enumVO);}return list;}
}
4、前端代码
前端定义一个全局的变量,来存储数据字典,可以在应用初始化前就请求接口获取数据,确保后续组件中正常使用
import http from "../api/index.js";/*** 全局静态数据*/
export const globalData = {SexEnum: [],ColorEnum: [],
};// 初始化
export async function initGlobalData() {const res = await http.get("/getEnumConfig");for (const key in globalData) {globalData[key] = res[key];}
}// === getter ===
export function getSexEnumFilterOptions() {console.log(globalData);return [{ value: "", label: "全部" }, ...globalData.SexEnum];
}export function getSexEnumOptions() {return globalData.SexEnum;
}export function getColorEnumOptions() {return globalData.ColorEnum;
}
前端需要进行逻辑判断,可自行枚举
/*** 颜色枚举,前端代码需要逻辑判断*/
export const ColorEnum = {// 红色RED: 'RED',// 绿色GREEN: 'GREEN',// 蓝色BLUE: 'BLUE',
};export const ColorEnumOptions = [{// 红色value: ColorEnum.RED,color: 'error',},{// 绿色value: ColorEnum.GREEN,color: 'success',},{// 蓝色value: ColorEnum.BLUE,color: 'processing',},
];export function getColorEnumColor(value) {return (ColorEnumOptions.find((item) => item.value === value)?.color || 'default');
}
5、接口数据
直接返回value和label字段,便于直接对接element和antd UI组件库,不需要再进行数据转换
获取枚举配置
GET http://localhost:8080/getEnumConfig{"ColorEnum": [{"value": "RED","label": "红色"},{"value": "GREEN","label": "绿色"},{"value": "BLUE","label": "蓝色"}],"SexEnum": [{"value": "MAN","label": "男性"},{"value": "WOMEN","label": "女性"}]
}
前端提交数据
POST http://localhost:8080/addUser
Content-Type: application/json{"name": "Steve","sex": "WOMEN"
}
前端获取数据
GET http://localhost:8080/getUserList[{"id": 21,"name": "Steve","sex": "WOMEN","color": null,"sexLabel": "女性","colorLabel": ""}
]
sexLabel 为方便前端显示数据而增加的字段
6、完整代码
后端代码:https://github.com/mouday/spring-boot-demo/SpringBoot-Enum
前端代码:https://gitee.com/mouday/react-enum
7、参考文章
- 看看人家在接口中使用枚举类型的方式,那叫一个优雅!
- Spring IoC资源管理之ResourceLoader
- 通过Spring包扫描的形式将枚举以字典的形式返回
- MyBatis-Plus:通用枚举
- 用反射的方法获取枚举值(数据字典)
相关文章:

Java:Springboot和React中枚举值(数据字典)的使用
目录 1、开发中的需求2、实现效果3、后端代码4、前端代码5、接口数据6、完整代码7、参考文章 1、开发中的需求 开发和使用过程中,通常会涉及四个角色:数据库管理员、后端开发人员、前端开发人员、浏览者 数据库使用int类型的数值进行存储(e…...

git撤回 不小心 commit 进去的文件
我时候 我们可能讲一下不想提交的文件 不小心commit了进去 我们可以通过 git reset HEAD~来撤回刚才的添加记录...
qt之movetothread理解
基础概念 qt的下线程qthread,每个线程都有自己的事件循环exec。对象的线程上下文,每个对象都有自己的线程上下文,怎么理解呢,就是该对象在哪个线程创建,其线程上下文就是谁。每个qobject对象在创建时都有包含线程成员…...

深入剖析:垃圾回收你真的了解吗?
小熊学Java:https://www.javaxiaobear.cn/ 本文我们重点剖析 JVM 的垃圾回收机制。关于 JVM 垃圾回收机制面试中主要涉及这三个考题: JVM 中有哪些垃圾回收算法?它们各自有什么优劣? CMS 垃圾回收器是怎么工作的?有哪…...

ue5 物理场的应用
cable mat wpo particle 流体粒子 choas 破损 刚体 布料 cloud abp blueprint riggedbody 体积雾 毛发 全局的 局部的 非均匀的 连续变化的 也可以多个叠加 从全局 到 范围 除了vector还有scalar的值也就是0--1的黑白灰的值 但是最终输出的值的类型还是取决于这个 一…...

移动零00
题目链接 移动零 题目描述 注意点 将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序必须在不复制数组的情况下原地对数组进行操作 解答思路 采用双指针的思路,左指针指向已移动零的数组的尾部,右指针指向为移动零的数组的头部&…...
go初识iris框架(四) -框架设置操作
前言 iris(1) iris(2) iris(3) 框架设置操作 当我们的一个路径是xxx/user/info,xxx/user/login,xxx/user/register的时候,我们发现前面都有一个user,我们如果用/{data:string}这样的话这样导致我们的路径是灵活的,所以我们得用其他方法 这里我们的路径是以anime为…...
python基础语法(二)
目录 注释注释的语法注释行文档字符串 注释的规范 输入输出和用户的交互通过控制台输出通过控制台的输入 注释 注释的语法 注释行 python的注释:使用#开通的行都是注释 # 这是一行注释C语言的注释:使用//的都是注释 // 这是一行注释文档字符串 使用三引号引起来的称为文档…...

从本地到Gitee:一步步学习文件上传及解决常见报错问题
🙂博主:小猫娃来啦 🙂文章核心:一步步学习文件上传及解决常见报错问题 文章目录 安装git进入gitee官网,登录账号新建仓库先打开git命令行上传本地资源到仓库第一步:git init第二步:git add .第三…...

idea2018修改大小写提示(敏感)信息
操作步骤如下: File > Settings > Editor > Code Completion > Code Completion(默认是首字母,选为none将不区分大小写)...
Quartz.Net调度框架简介
Quartz.Net是一个功能强大的开源任务调度框架,它可以在C#应用程序中实现灵活、可靠的任务调度和定时作业。它的主要作用是允许开发人员按照预定的时间表执行各种任务,例如定期生成报表、发送电子邮件、备份数据等。 在C#中使用Quartz.Net进行配置、开发…...

HarmonyOS/OpenHarmony(Stage模型)应用开发组合手势(一)连续识别
组合手势由多种单一手势组合而成,通过在GestureGroup中使用不同的GestureMode来声明该组合手势的类型,支持连续识别、并行识别和互斥识别三种类型。 .GestureGroup(mode:GestureMode, …gesture:GestureType[]) mode:必选参数,为G…...
Redis --- 位图
目录 背景 结构 存取方式 统计和查找 背景 开发过程中,会有布尔类型的存储,比如记录一个用户一年365天的签到情况,如果每天都要有一个布尔变量,多个用户,亦或者使用k-v形式,上亿用户的话这个存储量是惊…...

自然语言处理-词向量模型-Word2Vec
通常数据的维度越高,能提供的信息也就越多,从而计算结果的可靠性就更值得信赖 如何来描述语言的特征呢,通常都在词的层面上构建特征,Word2Vec就是要把词转换成向量 假设现在已经拿到一份训练好的词向量,其中每一个词都…...
List知识总结
ArrayList: 1 ArrayList扩容底层用到的是;System.arraycopy. 2 扩容的长度计算;int newCapacity oldCapacity (oldCapacity >> 1);,旧容量 旧容量右移1位,这相当于扩容为原 来容量的(int)3/2. 3 ArrayList<String…...
代码随想录day32
122.买卖股票的最佳时机 II ● 力扣题目链接 ● 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 ● 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 ● 注意:你不能同…...

2.8 PE结构:资源表详细解析
在Windows PE中,资源是指可执行文件中存放的一些固定不变的数据集合,例如图标、对话框、字符串、位图、版本信息等。PE文件中每个资源都会被分配对应的唯一资源ID,以便在运行时能够方便地查找和调用它们。PE文件中的资源都被组织成一个树形结…...
Python数据类型的相互转换
简单数据类型之间的转换 1.字符串如果是数字的,转换为int类型 a "10" a int(a) print(a) 2.数字类型转换成bool类型 a 10 a bool(a) print(a) 只有0才是false,其他值是True 复杂数据类型之间的转换 list:列表 tuple&…...

阿里云云主机免费试用三个月
试用链接如下: 阿里云云产品免费试用 云主机 费用试用三个月,每月750小时 实例规格 1核(vCPU) 2 GiB S6 系列机型 适用搭建网站等场景 网络带宽 1M 公网固定网络带宽 云盘40 GiB 真香!!!!!&…...

OpenHarmony 使用 ArkUI Inspector 分析布局
● 摘要:视图的嵌套层次会影响应用的性能,开发者应该移除多余的嵌套层次,缩短组件刷新耗时。本文会介绍如何使用 ArkUI Inspector 工具分析布局,提示应用响应性能。 ● 关键字:列举本文相关的关键字:OpenH…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...