SpringBoot枚举处理
# SpringBoot枚举处理
# 枚举通用接口
/**
* 枚举通用接口(所有业务枚举需实现此接口)
*/
public interface BaseEnum {
/**
* 获取枚举编码
*/
String getCode();
/**
* 获取枚举名称
*/
String getName();
/**
* 获取枚举描述
*/
default String getDesc() {
return getName();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 枚举定义方式
/**
* 是否 枚举
*/
public enum YesNoEnum implements BaseEnum {
YES("1", "是"),
NO("0", "否");
private final String code;
private final String name;
YesNoEnum(String code, String name) {
this.code = code;
this.name = name;
}
@Override
public String getCode() {
return code;
}
@Override
public String getName() {
return name;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 枚举映射配置类
@Component
public class EnumMappingConfig {
// 核心映射:key=前端传的标识(小写+驼峰),value=枚举Class
public static final Map<String, Class<?>> ENUM_MAPPING = new HashMap<>();
// 静态初始化映射关系
static {
// 通用
ENUM_MAPPING.put("yesNo", YesNoEnum.class); // 通用是否
//ENUM_MAPPING.put("gender",GenderEnum.class);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 枚举加载工具类
/**
* 枚举加载工具类
*/
@Component
public class EnumLoaderUtil implements InitializingBean, ResourceLoaderAware {
// 枚举缓存:Key=枚举Class,Value=枚举列表
private static final Map<Class<? extends BaseEnum>, List<BaseEnum>> ENUM_CACHE = new ConcurrentHashMap<>();
// 要扫描的枚举包(可配置化,多个包用逗号分隔)
private static final String SCAN_PACKAGES = "com.joe.common.enums";
private ResourceLoader resourceLoader;
/**
* 初始化:扫描指定包下所有枚举类并缓存
*/
@Override
public void afterPropertiesSet() throws Exception {
scanAndLoadEnums();
}
/**
* 包扫描核心逻辑
*/
private void scanAndLoadEnums() throws Exception {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(resourceLoader);
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
// 拆分扫描包,逐个处理
for (String packageName : SCAN_PACKAGES.split(",")) {
// 包路径转资源路径(com.xxx.enums → classpath*:com/xxx/enums/**/*.class)
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(packageName)) +
"/**/*.class";
Resource[] resources = resolver.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
String className = metadataReader.getClassMetadata().getClassName();
Class<?> clazz = Class.forName(className);
// 筛选:是枚举类 + 实现BaseEnum接口
if (clazz.isEnum() && BaseEnum.class.isAssignableFrom(clazz)) {
Class<? extends BaseEnum> enumClass = (Class<? extends BaseEnum>) clazz;
// 获取枚举所有实例
BaseEnum[] enumConstants = enumClass.getEnumConstants();
ENUM_CACHE.put(enumClass, Arrays.asList(enumConstants));
}
}
}
}
}
/**
* 对外提供:根据枚举类型获取所有枚举项
* @param enumClass 枚举Class
* @return 枚举列表
*/
public static <T extends BaseEnum> List<T> getEnumsByType(Class<T> enumClass) {
List<BaseEnum> baseEnums = ENUM_CACHE.get(enumClass);
if (baseEnums == null) {
return Collections.emptyList();
}
return (List<T>) baseEnums;
}
/**
* 扩展:根据枚举类型+编码获取枚举实例
* @param enumClass 枚举Class
* @param code 枚举编码
* @return 枚举实例
*/
public static <T extends BaseEnum> T getEnumByCode(Class<T> enumClass, String code) {
List<T> lists = getEnumsByType(enumClass);
// 移除调试打印,避免控制台输出过多信息
// System.out.println(lists);
T t = lists.stream()
.filter(enumItem -> enumItem.getCode().equals(code))
.findFirst()
.orElse(null);
return t;
}
/**
* 通过凑得获取枚举名称
* @param enumClass
* @param code
*/
public static <T extends BaseEnum> String getLabelByCode(Class<T> enumClass, String code) {
List<T> lists = getEnumsByType(enumClass);
T result = lists.stream()
.filter(enumItem -> enumItem.getCode().equals(code))
.findFirst()
.orElse(null);
if (ObjectUtil.isNotEmpty(result)&&ObjectUtil.isNotEmpty(result.getName())) {
return result.getName();
}
return "";
}
/**
* 通过枚举 Label获取code
* @param enumClass 枚举类型
* @param label 枚举名称
* @return 枚举 code,如果找不到返回 空字符串
*/
public static <T extends BaseEnum> String getCodeByLabel(Class<T> enumClass, String label) {
if (StrUtil.isBlank(label)) {
return "";
}
List<T> enums = EnumLoaderUtil.getEnumsByType(enumClass);
for (T enumItem : enums) {
if (label.equals(StrUtil.trim(enumItem.getName()))) {
return enumItem.getCode();
}
}
return "";
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 枚举字典接口
@RestController
@RequestMapping("/api/dict")
public class CommonController {
/**
* 获取枚举选项列表
* @param type 前端传的枚举标识(如followResult、commonYesNo)
* @return 枚举选项列表
*/
@PermitAll
@GetMapping("/getByType")
public Object getEnumOptions(@RequestParam String type) {
// 1. 校验枚举标识是否存在
Class<?> enumClass = EnumMappingConfig.ENUM_MAPPING.get(type);
if (enumClass == null) {
return R.failed("无效的枚举标识:" + type);
}
// 2. 校验是否为BaseEnum子类
if (!BaseEnum.class.isAssignableFrom(enumClass)) {
return R.failed("枚举标识未实现BaseEnum接口:" + type);
}
// 3. 调用工具类获取枚举列表并转换为DTO
List<BaseEnum> items = EnumLoaderUtil.getEnumsByType((Class<BaseEnum>) enumClass);
if (items.isEmpty()) {
return R.failed(CollUtil.newArrayList());
}
List<EnumOptionVo> results=items.stream()
.map(EnumOptionVo::from)
.collect(Collectors.toList());
return R.ok(results);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 前端请求接口类
import request from '@/utils/request'
import Vue from 'vue'
const BASE_API = '/cdc/dict'
// 全局字典缓存(使用 Vue 的响应式系统)
const dictCache = new Vue({
data() {
return {
cache: {}
}
}
})
export function getDict(type) {
return request({
url: `/cdc/dict/getByType`,
method: 'get',
params: {type:type}
})
}
// 异步加载字典(用于需要 Promise 的场景)
export function getDictByType(type) {
return getDict(type).then(res => {
if (res.code == 0) {
// 更新缓存
dictCache.$set(dictCache.cache, type, res.data || [])
return res.data
} else {
dictCache.$set(dictCache.cache, type, [])
return []
}
})
}
// 同步获取字典(用于模板中直接使用)
export function getDictByTypeSync(type) {
// 如果缓存中有数据,直接返回
if (dictCache.cache[type]) {
return dictCache.cache[type]
}
// 如果没有缓存,初始化空数组并触发异步加载
if (!dictCache.cache.hasOwnProperty(type)) {
dictCache.$set(dictCache.cache, type, [])
// 异步加载数据
getDictByType(type).catch(() => {
dictCache.$set(dictCache.cache, type, [])
})
}
return dictCache.cache[type]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 前端ui代码
<el-form-item label="是否发生不良反应" prop="isAdverseReaction">
<el-radio-group v-model="localForm.isAdverseReaction" :disabled="isDetail">
<el-radio
v-for="dict in getDictByTypeSync('yesNo')"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Last Updated: 2026/01/29, 19:40:49