在开发过程中经常遇到既需要维护枚举来完成各种条件判断,又需要维护数据字典供前端使用,维护数据字典的另一个用处是可以修改数据字典的 label 而无需调整代码,但是这种两边维护的方式非常浪费人力资源,甚至有时部署程序忘了维护数据字典导致线上环境出现无法正常显示等问题。为解决上述问题,提高自动化,减少上线 bug,六哥在这里提供一个通过枚举反射的数据字典的方案,仅供参考。
第一步
定义一个注解,用于定义数据字典类型名称和字典类型编码
public @interface DictDefine {
/**
* 字典类型名称
* @return
*/
String name();
/**
* 字典类型code(默认使用类名)
* @return
*/
String code() default "";
}
复制代码
第二步
定义一个接口用于规定字典 value 和字典 label 的获取方法
public interface IDict {
/**
* 字典值
* @return
*/
Integer getValue();
/**
* 字典标签
* @return
*/
String getLabel();
}
复制代码
第三步
定义枚举
@DictDefine(name = "用户类型")
public enum UserTypeEnum implements IDict {
member("会员", 0),
merchants("商户", 1),
operator("运营商", 2);
MallUserTypeEnum(String label, int value){
this.label = label;
this.value = value;
}
private final String label;
private final int value;
@Override
public Integer getValue() {
return this.value;
}
@Override
public String getLabel() {
return this.label;
}
}
复制代码
第四步
使用 spring 类扫描工具扫描指定包下的枚举类,转化为数据字典。这里是一次性扫描所有枚举放进 map 缓存,读取时只需通过字典 code 即可获取字典项,也可根据需要读取哪个就生成哪个,此处代码主要是提供扫描枚举生成数据字典的方法。
public static Map<String, List<DictItem>> scanEnumToDict() {
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents("cn.lg.soar.**.enums");
Map<String, List<DictItem>> map = new HashMap<>(candidateComponents.size());
for (BeanDefinition beanDefinition : candidateComponents) {
Class<?> x = Class.forName(beanDefinition.getBeanClassName());
// 判断是否是枚举且继承了字典接口
if (!Enum.class.isAssignableFrom(x) || !IDict.class.isAssignableFrom(x)) {
continue;
}
// 判断是否有字典注解
DictDefine annotation = x.getAnnotation(DictDefine.class);
if (annotation == null) {
continue;
}
// 获取字典code
String code = annotation.code();
code = "".equals(code) ? x.getSimpleName() : code;
// 生成字典项
IDict[] constants = (IDict[])x.getEnumConstants();
List<DictItem> items = new ArrayList<>(constants.length);
for (IDict d : constants) {
DictItem item = new DictItem();
item.setValue(d.getValue());
item.setLabel(d.getLabel());
items.add(item);
}
// 缓存
map.put(code, items);
}
return map;
}
复制代码
尾声
本文主要提供如何通过反射扫描枚举生成数据字典的示例,如果有更好的方案欢迎在评论区交流探讨,本文代码来源六哥开源前后端开源框架 lg-soar,如果您觉得对您有所帮助欢迎访问https://gitee.com/lgx1992/lg-soar给 lg-soar 一个 star
评论