文章目录
- 前言
- 实现项目启动时加载枚举值到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反射获取某个包中所有的枚举类,将它们存入列表。
@Slf4jpublic 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@Slf4jpublic class EnumServiceImpl implements EnumService { @Autowiredprivate RedisOperation redisOperation;@Overridepublic 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) -> //存入RedisredisOperation.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;}@Overridepublic String enumDesc() {return "操作类型";}@Overridepublic 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@Componentpublic class ApplicationInit implements ApplicationListener<ContextRefreshedEvent> {@Autowiredprivate EnumService enumService;@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {log.info("================开始初始化系统数据===========");log.info("开始加载JAVA枚举值列表");enumService.scanAndLoadEnumClassToRedis();log.info("加载枚举值列表完成");log.info("================初始化系统数据结束===========");}}
测试结果
-
上面的步骤完成后,就可以启动项目了,查看日志结果了:
-
日志成功打印之后,进入Redis可视化工具,可以看到Redis的枚举值已经存进去了,大功告成。