为什么这么做? 为了springboot 注解属性转换字典方便一点(使用缓存的方式在Springboot 启动时获取字典数据)
在启动时会扫描com.vehicle.manager.core.enumerate包下的所有枚举(包括类中的内部枚举),并取出对应属性以json的方式存入redis
目录结构如下:
- RedisUtil可以在RedisUtil获取
- Springboot 项目启动时的处理都可以参考这个方式
package com.vehicle.manager.core.enumerate;
import com.alibaba.fastjson.JSON;
import com.vehicle.manager.core.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* @author zr 2024/3/15
*/
@Component
@Order(1) // 确保在其他 Bean 初始化之前执行
@Slf4j
public class EnumScanner implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private ApplicationContext applicationContext;
private StringRedisTemplate redisTemplate;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext().equals(applicationContext)) {
this.redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
scanEnums();
}
}
public void scanEnums() {
// String dicDataStr = RedisUtil.StringOps.get("dicData");
// if (ObjectUtils.isNotEmpty(dicDataStr)){
// return;
// }
String packageName = "com.vehicle.manager.core.enumerate"; // 替换成你要扫描的包路径
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AssignableTypeFilter(Enum.class));
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(packageName);
HashMap<String, Map<String, String>> dicData = new HashMap<>();
for (BeanDefinition candidateComponent : candidateComponents) {
String className = candidateComponent.getBeanClassName();
// 这里可以对枚举类进行处理,比如输出类名或者其他操作
// log.info("Found enum class: " + className);
Class<?> enumClass = null;
try {
enumClass = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (enumClass.isEnum()) {
Map<String,String> dic = new LinkedHashMap();
Object[] enumConstants = enumClass.getEnumConstants();
for (Object enumConstant : enumConstants) {
// log.info("enumConstant",enumConstant);
dic.put(enumConstant.toString(),getDesc(enumConstant));
}
String simpleName = enumClass.getSimpleName();
String key = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
dicData.put(key,dic);
}
// dicData.put(key, JSON.toJSONString());
}
RedisUtil.StringOps.set("dicData", JSON.toJSONString(dicData));
}
private static String getDesc(Object enumConstant) {
try {
Field descField = enumConstant.getClass().getDeclaredField("desc");
descField.setAccessible(true);
String methodName = "get" + descField.getName().substring(0, 1).toUpperCase() + descField.getName().substring(1);
Method getDescMethod = enumConstant.getClass().getMethod(methodName);
return (String) getDescMethod.invoke(enumConstant);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
存入redis中的数据结构如下:
- json中的key为枚举的名称首字母小写
- 当然用redis的hash结构存储更好,当时开发时没有考虑到,有需要的可以自己改造