当前位置: 首页 > news >正文

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、列表页

  1. 顶部筛选类型由接口返回,接口增加类型后,前端代码不用修改,直接生效
  2. 列表性别 列,直接显示后端返回sexLabel的字段
  3. 列表颜色 列,由于前端需要根据不同的值,做一些逻辑判断,所以前端代码也需要做好枚举,做逻辑判断,此时需要注意默认值 ,预防后端增加类型之后,前端代码增加容错

在这里插入图片描述
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、参考文章

  1. 看看人家在接口中使用枚举类型的方式,那叫一个优雅!
  2. Spring IoC资源管理之ResourceLoader
  3. 通过Spring包扫描的形式将枚举以字典的形式返回
  4. MyBatis-Plus:通用枚举
  5. 用反射的方法获取枚举值(数据字典)

相关文章:

Java:Springboot和React中枚举值(数据字典)的使用

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

git撤回 不小心 commit 进去的文件

我时候 我们可能讲一下不想提交的文件 不小心commit了进去 我们可以通过 git reset HEAD~来撤回刚才的添加记录...

qt之movetothread理解

基础概念 qt的下线程qthread&#xff0c;每个线程都有自己的事件循环exec。对象的线程上下文&#xff0c;每个对象都有自己的线程上下文&#xff0c;怎么理解呢&#xff0c;就是该对象在哪个线程创建&#xff0c;其线程上下文就是谁。每个qobject对象在创建时都有包含线程成员…...

深入剖析:垃圾回收你真的了解吗?

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

ue5 物理场的应用

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

移动零00

题目链接 移动零 题目描述 注意点 将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序必须在不复制数组的情况下原地对数组进行操作 解答思路 采用双指针的思路&#xff0c;左指针指向已移动零的数组的尾部&#xff0c;右指针指向为移动零的数组的头部&…...

go初识iris框架(四) -框架设置操作

前言 iris(1) iris(2) iris(3) 框架设置操作 当我们的一个路径是xxx/user/info,xxx/user/login,xxx/user/register的时候,我们发现前面都有一个user,我们如果用/{data:string}这样的话这样导致我们的路径是灵活的&#xff0c;所以我们得用其他方法 这里我们的路径是以anime为…...

python基础语法(二)

目录 注释注释的语法注释行文档字符串 注释的规范 输入输出和用户的交互通过控制台输出通过控制台的输入 注释 注释的语法 注释行 python的注释:使用#开通的行都是注释 # 这是一行注释C语言的注释:使用//的都是注释 // 这是一行注释文档字符串 使用三引号引起来的称为文档…...

从本地到Gitee:一步步学习文件上传及解决常见报错问题

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

idea2018修改大小写提示(敏感)信息

操作步骤如下&#xff1a; File > Settings > Editor > Code Completion > Code Completion&#xff08;默认是首字母&#xff0c;选为none将不区分大小写&#xff09;...

Quartz.Net调度框架简介

Quartz.Net是一个功能强大的开源任务调度框架&#xff0c;它可以在C#应用程序中实现灵活、可靠的任务调度和定时作业。它的主要作用是允许开发人员按照预定的时间表执行各种任务&#xff0c;例如定期生成报表、发送电子邮件、备份数据等。 在C#中使用Quartz.Net进行配置、开发…...

HarmonyOS/OpenHarmony(Stage模型)应用开发组合手势(一)连续识别

组合手势由多种单一手势组合而成&#xff0c;通过在GestureGroup中使用不同的GestureMode来声明该组合手势的类型&#xff0c;支持连续识别、并行识别和互斥识别三种类型。 .GestureGroup(mode:GestureMode, …gesture:GestureType[]) mode&#xff1a;必选参数&#xff0c;为G…...

Redis --- 位图

目录 背景 结构 存取方式 统计和查找 背景 开发过程中&#xff0c;会有布尔类型的存储&#xff0c;比如记录一个用户一年365天的签到情况&#xff0c;如果每天都要有一个布尔变量&#xff0c;多个用户&#xff0c;亦或者使用k-v形式&#xff0c;上亿用户的话这个存储量是惊…...

自然语言处理-词向量模型-Word2Vec

通常数据的维度越高&#xff0c;能提供的信息也就越多&#xff0c;从而计算结果的可靠性就更值得信赖 如何来描述语言的特征呢&#xff0c;通常都在词的层面上构建特征&#xff0c;Word2Vec就是要把词转换成向量 假设现在已经拿到一份训练好的词向量&#xff0c;其中每一个词都…...

List知识总结

ArrayList: 1 ArrayList扩容底层用到的是&#xff1b;System.arraycopy. 2 扩容的长度计算&#xff1b;int newCapacity oldCapacity (oldCapacity >> 1);&#xff0c;旧容量 旧容量右移1位&#xff0c;这相当于扩容为原 来容量的(int)3/2. 3 ArrayList<String…...

代码随想录day32

122.买卖股票的最佳时机 II ● 力扣题目链接 ● 给定一个数组&#xff0c;它的第 i 个元素是一支给定股票第 i 天的价格。 ● 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;。 ● 注意&#xff1a;你不能同…...

2.8 PE结构:资源表详细解析

在Windows PE中&#xff0c;资源是指可执行文件中存放的一些固定不变的数据集合&#xff0c;例如图标、对话框、字符串、位图、版本信息等。PE文件中每个资源都会被分配对应的唯一资源ID&#xff0c;以便在运行时能够方便地查找和调用它们。PE文件中的资源都被组织成一个树形结…...

Python数据类型的相互转换

简单数据类型之间的转换 1.字符串如果是数字的&#xff0c;转换为int类型 a "10" a int(a) print(a) 2.数字类型转换成bool类型 a 10 a bool(a) print(a) 只有0才是false&#xff0c;其他值是True 复杂数据类型之间的转换 list&#xff1a;列表 tuple&…...

阿里云云主机免费试用三个月

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

OpenHarmony 使用 ArkUI Inspector 分析布局

● 摘要&#xff1a;视图的嵌套层次会影响应用的性能&#xff0c;开发者应该移除多余的嵌套层次&#xff0c;缩短组件刷新耗时。本文会介绍如何使用 ArkUI Inspector 工具分析布局&#xff0c;提示应用响应性能。 ● 关键字&#xff1a;列举本文相关的关键字&#xff1a;OpenH…...

如何利用libui-node生态构建跨平台桌面应用:Proton-Native和Vuido深度解析

如何利用libui-node生态构建跨平台桌面应用&#xff1a;Proton-Native和Vuido深度解析 【免费下载链接】libui-node Node bindings for libui, an awesome native UI library for Unix, OSX and Windows 项目地址: https://gitcode.com/gh_mirrors/li/libui-node libui-…...

产品竞争策略方法论:构建“差异化 + 结构化 + 系统化”的竞争优势

目录 一、问题与背景 二、本文将系统讲解 三、产品竞争的本质与底层逻辑 3.1 竞争的本质 3.2 竞争的三层结构(必须理解) 3.3 IoT竞争的特殊性 四、IoT产品竞争结构模型(核心框架) 4.1 五层竞争模型(核心体系) 4.2 竞争演进路径 五、五大竞争策略模型(核心方法…...

ue5 血条 渲染方形的分辨率 血条缩放的问题

项目设置中将Resize PIE Window to Output Resolution直接搜索Resize PIE Window to Output Resolution勾选即可...

意法半导体权力交接:从博佐蒂到谢里的战略延续与挑战

1. 从Bozotti到Chery&#xff1a;一场静水深流的权力交接在半导体这个以技术迭代和资本狂热著称的行业里&#xff0c;权力更迭往往伴随着戏剧性的股价波动、战略急转弯或是人事地震。然而&#xff0c;2018年5月31日&#xff0c;当意法半导体&#xff08;STMicroelectronics NV&…...

图解CA注意力机制:用Keras一步步拆解‘宽高分离池化’,理解位置信息如何嵌入通道注意力

图解CA注意力机制&#xff1a;用Keras拆解‘宽高分离池化’的视觉密码 当我们谈论注意力机制时&#xff0c;脑海中往往会浮现SE&#xff08;Squeeze-and-Excitation&#xff09;模块的通道加权画面。但今天要探讨的CA&#xff08;Coordinate Attention&#xff09;机制&#xf…...

DeepSeek R1模型API接入全流程(含鉴权失效应急手册):企业级生产环境已验证

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek R1模型API接入全流程&#xff08;含鉴权失效应急手册&#xff09;&#xff1a;企业级生产环境已验证 DeepSeek R1 是当前高性能开源大语言模型之一&#xff0c;其官方 API 提供稳定、低延迟的…...

HoRain云--Lua元表:解锁高级编程技巧

&#x1f3ac; HoRain云小助手&#xff1a;个人主页 &#x1f525; 个人专栏: 《Linux 系列教程》《c语言教程》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个超棒的服务器购买网站&#xff0c;性价比超高&#xff0c;大内存超划算&#xff01;…...

用surf( )函数绘制三维曲面图

在“用plot3( )函数绘制三维曲线图”中&#xff0c;实现了三维曲线的绘制&#xff0c;得到了一个类似面包圈形状的旋转曲面&#xff0c;很喜欢这个造型&#xff0c;就想到是不是可以直接绘制出曲面&#xff0c;而不只是用曲线方式绘制出看起来像曲面的图形。一看参考书&#xf…...

百度网盘Mac版加速插件:突破下载限制的实用方案

百度网盘Mac版加速插件&#xff1a;突破下载限制的实用方案 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 对于经常使用百度网盘的Mac用户来说&#x…...

MemOS:为AI智能体构建统一记忆操作系统,提升长期对话与RAG性能

1. 项目概述&#xff1a;MemOS&#xff0c;为AI智能体装上“记忆大脑” 如果你正在开发基于大语言模型的AI智能体&#xff0c;或者在使用RAG&#xff08;检索增强生成&#xff09;技术&#xff0c;那么你一定遇到过这个核心痛点&#xff1a; 对话上下文太短&#xff0c;智能体…...