Java--业务场景:在Spring项目启动时加载Java枚举类到Redis中

news2024/11/28 7:39:21

文章目录

        • 前言
        • 实现项目启动时加载枚举值到Redis
          • 1. 定义EnumInterface接口
          • 2. 创建EnumDTO
          • 3. 创建ClassUtils工具类
          • 4. 创建EnumService接口
          • 5. 创建EnumServiceImpl
          • 6. 修改枚举类
          • 7. 创建ApplicationInit
        • 测试结果

前言
  • 新的一年即将来到,回首2023年,也是学习了许多,不断进步。今天带来的是项目中遇到的一个业务要求处理方法总结:项目具有很多的枚举类,而这些枚举类在前端页面中需要作为下拉框选项等组件被前端获取。为了后续获取枚举值更加方便快捷,我们在项目启动的时候将所有Java枚举类用一个hash存入Redis中,在提供一个接口,使得前端可以从Redis获取自己想要的枚举值。下文将讲解实现步骤。
实现项目启动时加载枚举值到Redis
1. 定义EnumInterface接口
  • 定义EnumInterface接口,实现该接口的枚举类会在后续被识别,在项目启动时加入redis
    public interface EnumInterface {
    
        String getCode();
    
        String getDesc();
     
        //枚举类描述 该值后续会与枚举类名拼接 成为Redis hash的key  
        String enumDesc();
      }
    
2. 创建EnumDTO
  • 创建EnumDTO,将存放每个枚举类对象,同一个枚举类的所有对象最终会放入同一个列表,作为Redis hash的value。
      @Data
      @ApiModel(value = "EnumDto", description = "【枚举值-枚举值DTO】")
      public class EnumDto implements Serializable {
    
          private static final long serialVersionUID = 1L;
      
          @ApiModelProperty(value = "枚举值类型-对应枚举值类名")
          private String typeEn;
      
          @ApiModelProperty(value = "枚举值类型-对应枚举值类名的desc描述信息")
          private String typeCh = "";
    
          @ApiModelProperty(value = "枚举值类型-对应枚举值的code值")
          private String code;
    
          @ApiModelProperty(value = "枚举值类型-对应枚举值的desc值")
          private String desc;
      
          @ApiModelProperty(value = "枚举值类型-对应枚举实例的名字")
          private String enumName;
    
      }
    
3. 创建ClassUtils工具类
  • 该类提供一个方法,通过Java反射获取某个包中所有的枚举类,将它们存入列表。
      @Slf4j
      public class ClassUtils {
          //为了方便管理,我们将枚举类放在同一个包下,这里写入自己项目中枚举类所在的包名。
          private static final String PACKAGE_NAME = "com.common.base.enums";
      
          public static List<Class<Enum>> getAllEnumClasses() throws ClassNotFoundException, IOException {
              List<Class<Enum>> list = new ArrayList<>();
              for (String className : getClassName(PACKAGE_NAME, true)) {
                  Class<?> clazz = Class.forName(className);
                  if (Enum.class.isAssignableFrom(clazz) && EnumInterface.class.isAssignableFrom(clazz)) {
                      list.add((Class<Enum>) clazz);
                  }
              }
              return list;
          }
          /**
           * 获取某包下的所有类
           * @param packageName  包名
           * @param childPackage 是否遍历子包
           */
          public static List<String> getClassName(String packageName, boolean childPackage) throws IOException {
              List<String> fileNames = null;
              ClassLoader loader = Thread.currentThread().getContextClassLoader();
              String packagePath = packageName.replace(".", "/");
              URL url = loader.getResource(packagePath);
              if (url != null) {
                  String type = url.getProtocol();
                  if (type.equals("file")) {
                      fileNames = getClassNameByFile(url.getPath(), childPackage);
                  }
              } else {
                  fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);
              }
              return fileNames;
          }
          /**
           * 从项目文件获取某包下所有类
           *
           */
          private static List<String> getClassNameByFile(String filePath, boolean childPackage) throws UnsupportedEncodingException {
              List<String> myClassName = new ArrayList<>();
              // 解决路径包含中文的情况
              filePath = java.net.URLDecoder.decode(filePath,"utf-8");
              File file = new File(filePath);
              boolean exists = file.exists();
              File[] childFiles = file.listFiles();
              assert childFiles != null;
              for (File childFile : childFiles) {
                  if (childFile.isDirectory()) {
                      if (childPackage) {
                          myClassName.addAll(getClassNameByFile(childFile.getPath(), childPackage));
                      }
                  } else {
                      String childFilePath = childFile.getPath();
                      if (childFilePath.endsWith(".class")) {
                          childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9,
                                  childFilePath.lastIndexOf("."));
                          childFilePath = childFilePath.replace("\\", ".");
                          myClassName.add(childFilePath);
                      }
                  }
              }
              return myClassName;
          }
      }
    
4. 创建EnumService接口
  • 创建EnumService接口,声明有关枚举类操作的接口
      public interface EnumService {
          /**
           * 扫描路径下的所有JAVA枚举类,并加载到redis缓存中
           */
          void scanAndLoadEnumClassToRedis();
      }
    
5. 创建EnumServiceImpl
  • 创建EnumService实现类EnumServiceImpl,实现scanAndLoadEnumClassToRedis方法,该方法实现将枚举值加载到Redis中
      @Service
      @Slf4j
      public class EnumServiceImpl implements EnumService {   
          @Autowired
          private RedisOperation redisOperation;
          @Override
          public void scanAndLoadEnumClassToRedis() {
              try {
                  //声明Redis中存放的数据结构
                  Map<String, List<EnumDto>> map = new HashMap<>();
                  //先删除原来的枚举类key,RedisKeyConstant.SYSTEM_ENUMS_CACHE_KEY 为存放缓存的key字符串,在常量类中自己定义
                  redisOperation.del(RedisKeyConstant.SYSTEM_ENUMS_CACHE_KEY);
                  //通过ClassUtils得到枚举类名,反射得到属性,填充属性到EnumDto中
                  ClassUtils.getAllEnumClasses().forEach(enumClass -> {
                      try {
                          EnumInterface[] enumInterfaces = (EnumInterface[]) enumClass.getMethod("values").invoke(new Object());
                          Arrays.stream(enumInterfaces).forEach(enumInterface -> {
                              EnumDto enumDto = new EnumDto();
                              enumDto.setCode(enumInterface.getCode());
                              enumDto.setTypeEn(enumClass.getName());
                              enumDto.setTypeCh(enumInterface.enumDesc());
                              enumDto.setDesc(enumInterface.getDesc());
                              enumDto.setEnumName(((Enum) enumInterface).name());
                              //hash的key:枚举值类名|枚举类描述信息
                              //hash的value:List<EnumDto>
                              String key = enumClass.getName() + "|" + enumInterface.enumDesc();
                              if (null == map.get(key)) {
                                  List<EnumDto> list = new ArrayList<>();
                                  list.add(enumDto);
                                  map.put(key, list);
                              } else {
                                  map.get(key).add(enumDto);
                              }
                          });
                      } catch (Exception e) {
                          log.error("加载JAVA枚举值失败", e);
                          redisOperation.del(RedisKeyConstant.SYSTEM_ENUMS_CACHE_KEY);
                          throw new ProcessException(CommonConstants.ENUM_PROCESSING_EXCEPTION, "加载JAVA枚举值到Reids中发生错误,请检查代码!");
                      }
                  });
                  map.forEach((key, val) -> 
                      //存入Redis
                      redisOperation.hset(RedisKeyConstant.SYSTEM_ENUMS_CACHE_KEY, key, val)
                  );
              } catch (Exception e) {
                  log.error("加载JAVA枚举值失败", e);
                  throw new ProcessException(CommonConstants.ENUM_PROCESSING_EXCEPTION, "加载JAVA枚举值到Reids中发生错误,请检查代码!");
              }
          }
      }
    
6. 修改枚举类
  • 让需要加载到Redis中的枚举类实现EnumInterface接口,记得重写enumDesc方法,给枚举类们加上描述,这个描述很重要,以下是一个例子。
      public enum OperationTypeEnum implements EnumInterface {
          UPDATE("update", "更新"),
          DELETE("delete", "删除"),
          ADD("add","增加"),
          GET("show","展示");
    
          private final String code;
          private final String desc;
    
          OperationTypeEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
          }
    
          public String getCode() {
            return code;
          }
        
          @Override
          public String enumDesc() {
            return "操作类型";
          }
    
          @Override
          public String getDesc() {
            return this.desc;
          }
        
          public static String getDesc(String code) {
            for (OperationTypeEnum publishEnum : OperationTypeEnum.values()) {
              if (publishEnum.getCode().equals(code)) {
                return publishEnum.getDesc();
              }
            }
            return null;
          }
    
          public static OperationTypeEnum getByCode(String code) {
            for (OperationTypeEnum examSourceTypeEnum : OperationTypeEnum.values()) {
              if (examSourceTypeEnum.getCode().equals(code)) {
                return examSourceTypeEnum;
              }
            }
            return null;
          }
      }
    
7. 创建ApplicationInit
  • ContextRefreshedEvent是Spring内置的上下文更新事件,该事件会在ApplicationContext被初始化或者更新时发布。
      /**
       * 枚举值初始化
       * 系统启动的时候,将枚举值全部刷新一遍
       */
       @Slf4j
       @Component
       public class ApplicationInit implements ApplicationListener<ContextRefreshedEvent> {
           @Autowired
           private EnumService enumService;
           @Override
           public void onApplicationEvent(ContextRefreshedEvent event) {
              log.info("================开始初始化系统数据===========");
              log.info("开始加载JAVA枚举值列表");
              enumService.scanAndLoadEnumClassToRedis();
              log.info("加载枚举值列表完成");
              log.info("================初始化系统数据结束===========");
           }
       }
    
测试结果
  • 上面的步骤完成后,就可以启动项目了,查看日志结果了:
    在这里插入图片描述

  • 日志成功打印之后,进入Redis可视化工具,可以看到Redis的枚举值已经存进去了,大功告成。
    在这里插入图片描述

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

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

相关文章

GEE中Landsat、Sentinel、Modis主要数据集区别

一、Landsat 1. Collection 1/2 的区别 Collection 2 是Landsat Level 1 数据的又一次重大再处理&#xff0c;显著提高了绝对地理定位精度。 Collection1Collection2时间跨度1972~2021底1972~至今数据等级level 1level1&#xff1a;1972~2021底 level2&#xff1a;1982~至今 …

MyBatisPlus学习笔记四-扩展功能

1、代码生成器 1.1、官方的1 1.3、官方的2-idea插件 1.3、非官方的-idea插件 2、静态工具 先查询&#xff0c;再分组 3、逻辑删除 4、枚举处理器 5、JSON处理器

ELK之Filebeat安装配置及日志抓取

一、Filebeat是什么 轻量型日志采集器 无论您是从安全设备、云、容器、主机还是 OT 进行数据收集,Filebeat 都将为您提供一种轻量型方法,用于转发和汇总日志与文件,让简单的事情不再繁杂。 Filebeat 随附可观测性和安全数据源模块,这些模块简化了常见格式的日志的收集、解…

Nsis打包Unity Exe文件(通用)

Nsi 脚本 !include "MUI2.nsh"#使用现代UI Unicode true #使用Unicode !define EXENAME "exeName" #定义常量 exe名称 !define SHORTCUT "快捷方式名称" #定义桌面快捷方式的中文名称Name ${EXENAME} #安装程序的title OutFile "${EXENAME…

银行数据仓库体系实践(1)--银行数据仓库简介

银行数据仓库简介 数据仓库之父比尔&#xff08;Bill Inmon&#xff09;在1991年出版的“Building the Data Warehouse”&#xff08;《建立数据仓库》&#xff09;一书中所提出的定义被广泛接受&#xff1a;数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的&a…

如何使用Entity Framework查询Mysql数据库 并实现多表联查

简介 &#x1f340;通过依赖注入的方式&#xff0c;使用ORM工具Entity Framework查询Mysql数据库中的数据&#xff0c;并实现多表联查 假设我们有一个user用户表&#xff0c;其中occupationid对应的就是下面职业表中的id 职业表Occupations 现在我们需要查出用户的职业是什么…

隐秘而精湛:反射物镜用于激光烧蚀质谱系统

激光烧蚀电感耦合等离子体质谱技术 激光烧蚀电感耦合等离子体质谱 &#xff08;LA-ICP-MS&#xff09; 因其灵敏度和概念简单性而被认为是固体材料成分分析最通用的方法之一。自 1985 年 A. Gray 进行首次可行性研究以来&#xff0c;在仪器进步和智能调谐和校准策略概念的推动…

【IDEA相关问题】全局搜索快捷键ctrl+shift+f与win10输入法简繁体切换冲突

解决方案如下&#xff1a; 1. 打开Windows设置&#xff0c;选择【时间和语言】&#xff0c;接着选择【语言】 2. 选择中文&#xff08;简体&#xff0c;中国&#xff09;——【选项】 3. 找到【微软拼音】——【选项】 4. 选择【按键】进入下一步设置界面 5. 在按键设置里即可…

Github 2024-01-16 Python开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-16统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目10HTML项目1 精心策划的Python资源列表 创建周期&#xff1a;3490 天开发语言&#xff1a;Python…

【LabVIEW FPGA入门】FPGA中的数学运算

数值控件选板上的大部分数学函数都支持整数或定点数据类型&#xff0c;但是需要请注意&#xff0c;避免使用乘法、除法、倒数、平方根等函数&#xff0c;此类函数比较占用FPGA资源&#xff0c;且如果使用的是定点数据或单精度浮点数据仅适用于FPGA终端。 1.整数运算 支持的数…

性能测试jmeter

参考up主 啥时当叫兽的个人空间-啥时当叫兽个人主页-哔哩哔哩视频 IMBA_RAILGUN的个人空间-IMBA_RAILGUN个人主页-哔哩哔哩视频 大丫头胖的个人空间-大丫头胖个人主页-哔哩哔哩视频 选的这些怎么添加 在一个列表里面 方法调用${__time(YMD)} 两个下划线&#xff0c;后跟函数…

Cpp多线程(一)

一、基本概念 1、程序是一段静态代码&#xff1b;进程是正在运行的程序&#xff1b;线程则是程序内部的执行路径。 上面这张图就解释了线程和多线程的意义。 2、若一个程序在同一时间执行多个线程&#xff0c;便是支持多线程的。一个进程中的多个线程共享相同的内存单元/内存…

MS2660:L1 频段卫星导航射频前端低噪声放大器芯片

MS2660 是一款具有高增益、低噪声系数的低噪声放 大器&#xff08;LNA&#xff09;芯片&#xff0c;支持 L1 频段多模式全球卫星定位&#xff0c;可 以应用于 GPS、北斗二代、伽利略、Glonass 等 GNSS 导航 接收机中。芯片采用先进工艺制造&#xff0c;封装采用 2 mm 2 mm …

【latex】参考文献排版前移,在最前面引用\usepackage{url}

【LaTeX】参考文献排版前移&#xff0c;在最前面引用\usepackage{url} 写在最前面完整解决步骤请教申申latex编译报错解决方案 写在最前面 参考文献从21开始排版前移了 解决方案&#xff1a;在最前面加一行 \usepackage{url}完整解决步骤 请教申申 申申yyds&#xff01;&am…

HarmonyOS—构建第一个ArkTS应用(Stage模型)

创建ArkTS工程 构建第一个页面 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发&#xff0c;选择模板“Empty Ability”&am…

推荐几款IDEA插件,助你玩转Mybatis开发

在软件开发的征程中&#xff0c;MyBatis 框架一直是 Java 开发者中的首选&#xff0c;其简洁的 SQL 映射和强大的灵活性使其成为持久层框架的瑰宝。然而&#xff0c;在我们开发过程中&#xff0c;很多人都曾面对过一个相对繁琐的问题&#xff1a;如何高效而准确地将数据库表映射…

element的el-select组件数据过多使用分页

一、代码实现 1. 单个下拉框 <template><div><!-- 为了启用远程搜索&#xff0c;需要将filterable和remote设置为true&#xff0c;同时传入一个remote-method。remote-method为一个Function&#xff0c;它会在输入值发生变化时调用&#xff0c;参数为当前输入…

Ceph应用管理

目录 资源池 Pool 管理 创建 CephFS 文件系统 MDS 接口 服务端操作 客户端操作 创建 Ceph 块存储系统 RBD 接口 创建 Ceph 对象存储系统 RGW 接口 OSD 故障模拟与恢复 资源池 Pool 管理 我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool…

代码随想录算法训练营29期|day 21 任务以及具体安排

530.二叉搜索树的最小绝对差 力扣题目链接(opens new window) 给你一棵所有节点为非负值的二叉搜索树&#xff0c;请你计算树中任意两节点的差的绝对值的最小值。 示例&#xff1a; 提示&#xff1a;树中至少有 2 个节点。 class Solution {TreeNode pre;// 记录上一个遍历的…

C++ 数论相关题目(约数)

1、试除法求约数 主要还是可以成对的求约数进行优化&#xff0c;不然会超时。 时间复杂度根号n #include <iostream> #include <vector> #include <algorithm>using namespace std;int n;vector<int> solve(int a) {vector<int> res;for(int i…