周振林 周振林
首页
  • 前端文章

    • HTML
    • CSS
    • Tailwind CSS (opens new window)
    • JavaScript
    • Vue3
    • 其他
  • Spring
  • SpringMVC
  • Mybatis
  • Docker
  • 设计模式
  • 安装教程
  • 其他教程
  • 基础
  • 虚拟化
  • OpenStack
  • 心情杂货
关于
收藏

周振林

IT界的小学生
首页
  • 前端文章

    • HTML
    • CSS
    • Tailwind CSS (opens new window)
    • JavaScript
    • Vue3
    • 其他
  • Spring
  • SpringMVC
  • Mybatis
  • Docker
  • 设计模式
  • 安装教程
  • 其他教程
  • 基础
  • 虚拟化
  • OpenStack
  • 心情杂货
关于
收藏
  • Spring

    • 接口设计规范
    • Spring IoC
    • Spring AOP
    • SpringBoot基础
    • SpringBoot 常用注解
    • SpringBoot Conditional注解
    • SpringBoot 组件注入方式
    • SpringBoot 组件Bean生命周期
    • SpringBoot自动配置原理
    • SpringBoot自定义Starter
    • SpringBoot其他功能
    • SpringBoot JdbcTemplate
    • SpringBoot事务
    • SpringBoot文档
    • SpringBoot Starter和BOM区别
    • SpringBoot集成Modbus实现设备
    • 查询优化N+1
    • Response设置响应编码
    • SpringBoot枚举处理
      • SpringBoot枚举处理
        • 枚举通用接口
        • 枚举定义方式
        • 枚举映射配置类
        • 枚举加载工具类
        • 枚举字典接口
        • 前端请求接口类
        • 前端ui代码
    • Thymeleaf教程
    • Maven教程
    • Tree工具类,轻松搞定树结构
    • 项目代码组织方式
  • SpringMVC

  • Mybatis

  • Docker

  • 设计模式

  • 安装教程

  • 其他教程

  • 后端
  • Spring
周振林
2026-01-29
目录

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

# 枚举定义方式

/**
 * 是否 枚举
 */
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

# 枚举映射配置类

@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

# 枚举加载工具类


/**
 * 枚举加载工具类
 */
@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

# 枚举字典接口

@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

# 前端请求接口类

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

# 前端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
Last Updated: 2026/01/29, 19:40:49
Response设置响应编码
Thymeleaf教程

← Response设置响应编码 Thymeleaf教程→

最近更新
01
策略模式
01-30
02
查询优化N+1
12-02
03
项目代码组织方式
12-02
更多文章>
Copyright © 2019-2026 鲁ICP备19032096号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×