Spring Boot 2.7.18(最终 2.x 系列版本)3 - 枚举规范定义:定义基础枚举接口;定义枚举工具类;示例枚举

Spring Boot 2.7.18(最终 2.x 系列版本)3 - 枚举规范定义:定义基础枚举接口;定义枚举工具类;示例枚举

Spring Boot 2.7.18(最终 2.x 系列版本)3 - 枚举规范定义


定义基础枚举接口

java 复制代码
package cn.hao.kai.enums;

import java.io.Serializable;

/**
 * <h2>基础枚举接口</h2>
 *
 * <p><strong>说明:</strong></p>
 * <ul>
 *     <li>用于统一枚举结构:值 + 描述,参考 {@link ExampleEnum} 实现</li>
 *     <li>配合 {@link EnumUtil} 使用</li>
 * </ul>
 *
 * @param <V> 枚举编码类型
 * @author Hao Kai
 */
@SuppressWarnings("unused")
public interface IBaseEnum<V> extends Serializable {

    /**
     * 获取枚举编码(唯一标识)
     *
     * @return 枚举编码
     */
    V getEnumCode();

    /**
     * 获取枚举描述
     *
     * @return 枚举描述信息
     */
    String getEnumDescription();
}

定义枚举工具类

java 复制代码
package cn.hao.kai.enums;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;

/**
 * <h2>枚举工具类</h2>
 * 仅适用于实现 {@link IBaseEnum} 接口的枚举类,用于统一处理实现 {@link IBaseEnum} 接口的枚举类,如:值获取、条件查询、转 Map/List、下拉框结构等。
 *
 * <p><strong>主要功能:</strong></p>
 * <ul>
 *     <li>根据 value、name、description 获取枚举实例</li>
 *     <li>自定义条件获取</li>
 *     <li>枚举值存在性校验</li>
 *     <li>转为 Map/List/下拉列表</li>
 *     <li>缓存提升性能</li>
 * </ul>
 *
 * <p><strong>调用示例:</strong>参考 {@link ExampleEnum} 实现</p>
 * <pre>{@code
 * getEnumByEnumCode(ExampleEnum.class, 0);// SUCCESS
 * getEnumByEnumName(ExampleEnum.class, "FAIL"); // FAIL
 * getEnumByEnumDescription(ExampleEnum.class, "成功"); // SUCCESS
 * existsEnumCode(ExampleEnum.class, 1); // true
 * existsEnumName(ExampleEnum.class, "SUCCESS"); // true
 * existsEnumDescription(ExampleEnum.class, "失败"); // true
 * getByCondition(ExampleEnum.class, e -> e.getEnumCode() == 1); // FAIL
 * toList(ExampleEnum.class, "code", "desc"); // [{code=0, desc=成功}, {code=1, desc=失败}]
 * toDropdownList(ExampleEnum.class, "value", "label"); // [{value=0, label=成功}, {value=1, label=失败}]
 * }</pre>
 * 
 * @author Hao Kai
 */
@SuppressWarnings("unused")
public final class EnumUtil {

    /**
     * 枚举值缓存
     */
    private static final Map<Class<?>, Map<Object, Enum<?>>> ENUM_CODE_CACHE = new ConcurrentHashMap<>();
    /**
     * 枚举描述缓存
     */
    private static final Map<Class<?>, Map<String, Enum<?>>> ENUM_DESC_CACHE = new ConcurrentHashMap<>();

    private EnumUtil() {
        throw new UnsupportedOperationException("EnumUtil is a utility class and cannot be instantiated.");
    }

    /**
     * 根据枚举编码获取枚举实例
     *
     * @param enumClass 枚举类
     * @param enumCode  枚举编码
     * @param <E>       枚举类型
     * @param <V>       枚举编码类型
     * @return 匹配的枚举项或 null
     *
     * <pre>{@code
     * EnumUtil.getEnumByEnumCode(Status.class, 0); // => SUCCESS
     * }</pre>
     */
    @SuppressWarnings("unchecked")
    public static <E extends Enum<E> & IBaseEnum<V>, V> E getEnumByEnumCode(Class<E> enumClass, V enumCode) {
        if (enumClass == null || enumCode == null) return null;
        return (E) ENUM_CODE_CACHE
                .computeIfAbsent(enumClass, EnumUtil::initValueCache)
                .get(enumCode);
    }

    /**
     * 根据枚举名获取实例
     *
     * @param enumClass 枚举类
     * @param enumName  枚举名称
     * @param <E>       枚举类型
     * @return 匹配的枚举项或 null
     *
     * <pre>{@code
     * EnumUtil.getEnumByEnumName(Status.class, "SUCCESS"); // => SUCCESS
     * }</pre>
     */
    public static <E extends Enum<E>> E getEnumByEnumName(Class<E> enumClass, String enumName) {
        if (enumClass == null || enumName == null) return null;
        try {
            return Enum.valueOf(enumClass, enumName);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    /**
     * 根据枚举描述获取实例
     *
     * @param enumClass       枚举类
     * @param enumDescription 描述
     * @param <E>             枚举类型
     * @return 匹配的枚举项或 null
     *
     * <pre>{@code
     * EnumUtil.getEnumByEnumDescription(Status.class, "失败"); // => FAIL
     * }</pre>
     */
    @SuppressWarnings("unchecked")
    public static <E extends Enum<E> & IBaseEnum<?>> E getEnumByEnumDescription(Class<E> enumClass, String enumDescription) {
        if (enumClass == null || enumDescription == null) return null;
        return (E) ENUM_DESC_CACHE
                .computeIfAbsent(enumClass, EnumUtil::initDescriptionCache)
                .get(enumDescription);
    }

    /**
     * 根据条件获取枚举实例
     *
     * @param enumClass 枚举类
     * @param predicate 条件谓词
     * @param <E>       枚举类型
     * @return 匹配的枚举项或 null
     *
     * <pre>{@code
     * EnumUtil.getByCondition(Status.class, e -> e.getEnumCode() == 1); // => FAIL
     * }</pre>
     */
    public static <E extends Enum<E> & IBaseEnum<?>> E getByCondition(Class<E> enumClass, Predicate<E> predicate) {
        for (E e : enumClass.getEnumConstants()) {
            if (predicate.test(e)) return e;
        }
        return null;
    }

    /**
     * 判断值是否存在
     *
     * @param enumClass 枚举类
     * @param enumCode  枚举编码
     * @param <E>       枚举类型
     * @param <V>       枚举编码类型
     * @return true 表示存在
     *
     * <pre>{@code
     * EnumUtil.existsEnumCode(Status.class, 1); // => true
     * }</pre>
     */
    public static <E extends Enum<E> & IBaseEnum<V>, V> boolean existsEnumCode(Class<E> enumClass, V enumCode) {
        return getEnumByEnumCode(enumClass, enumCode) != null;
    }

    /**
     * 判断名称是否存在
     *
     * @param enumClass 枚举类
     * @param enumName  枚举名称
     * @param <E>       枚举类型
     * @return true 表示存在
     */
    public static <E extends Enum<E>> boolean existsEnumName(Class<E> enumClass, String enumName) {
        return getEnumByEnumName(enumClass, enumName) != null;
    }

    /**
     * 判断描述是否存在
     *
     * @param enumClass       枚举类
     * @param enumDescription 枚举描述
     * @param <E>             枚举类型
     * @return true 表示存在
     */
    public static <E extends Enum<E> & IBaseEnum<?>> boolean existsEnumDescription(Class<E> enumClass, String enumDescription) {
        return getEnumByEnumDescription(enumClass, enumDescription) != null;
    }

    /**
     * 枚举转为 Map 列表
     *
     * @param enumClass      枚举类
     * @param codeKey        map 中的 code 字段名
     * @param descriptionKey map 中的 description 字段名
     * @param <E>            枚举类型
     * @return list of map
     *
     * <pre>{@code
     * EnumUtil.toList(Status.class, "code", "desc"); // [{code=0, desc=成功}, {code=1, desc=失败}]
     * }</pre>
     */
    public static <E extends Enum<E> & IBaseEnum<?>> List<Map<String, Object>> toList(
            Class<E> enumClass,
            String codeKey,
            String descriptionKey
    ) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (E e : enumClass.getEnumConstants()) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(codeKey, e.getEnumCode());
            map.put(descriptionKey, e.getEnumDescription());
            list.add(map);
        }
        return list;
    }

    /**
     * 枚举转为下拉列表结构
     *
     * @param enumClass 枚举类
     * @param valueKey  下拉框 value 字段名
     * @param labelKey  下拉框 label 字段名
     * @param <E>       枚举类型
     * @return 下拉框数据
     *
     * <pre>{@code
     * EnumUtil.toDropdownList(Status.class, "value", "label"); // [{value=0, label=成功}, {value=1, label=失败}]
     * }</pre>
     */
    public static <E extends Enum<E> & IBaseEnum<?>> List<Map<String, Object>> toDropdownList(
            Class<E> enumClass,
            String valueKey,
            String labelKey
    ) {
        return toList(enumClass, valueKey, labelKey);
    }

    // ===== 缓存初始化 =====
    @SuppressWarnings("unchecked")
    private static Map<Object, Enum<?>> initValueCache(Class<?> enumClass) {
        Map<Object, Enum<?>> map = new HashMap<>();
        for (Enum<?> e : ((Class<? extends Enum<?>>) enumClass).getEnumConstants()) {
            IBaseEnum<?> base = (IBaseEnum<?>) e;
            map.put(base.getEnumCode(), e);
        }
        return map;
    }

    @SuppressWarnings("unchecked")
    private static Map<String, Enum<?>> initDescriptionCache(Class<?> enumClass) {
        Map<String, Enum<?>> map = new HashMap<>();
        for (Enum<?> e : ((Class<? extends Enum<?>>) enumClass).getEnumConstants()) {
            IBaseEnum<?> base = (IBaseEnum<?>) e;
            map.put(base.getEnumDescription(), e);
        }
        return map;
    }

    /**
     * <h3>演示主方法</h3>
     * 用于测试全部方法是否工作正常
     */
    public static void main(String[] args) {
        System.out.println("== getEnumByEnumCode: " + getEnumByEnumCode(ExampleEnum.class, 0));// SUCCESS
        System.out.println("== getEnumByEnumName: " + getEnumByEnumName(ExampleEnum.class, "FAIL")); // FAIL
        System.out.println("== getEnumByEnumDescription: " + getEnumByEnumDescription(ExampleEnum.class, "成功")); // SUCCESS
        System.out.println("== existsEnumCode: " + existsEnumCode(ExampleEnum.class, 1)); // true
        System.out.println("== existsEnumName: " + existsEnumName(ExampleEnum.class, "SUCCESS")); // true
        System.out.println("== existsEnumDescription: " + existsEnumDescription(ExampleEnum.class, "失败")); // true
        System.out.println("== getByCondition: " + getByCondition(ExampleEnum.class, e -> e.getEnumCode() == 1)); // FAIL
        System.out.println("== toList: " + toList(ExampleEnum.class, "code", "desc")); // [{code=0, desc=成功}, {code=1, desc=失败}]
        System.out.println("== toDropdownList: " + toDropdownList(ExampleEnum.class, "value", "label")); // [{value=0, label=成功}, {value=1, label=失败}]
    }

}

示例枚举

java 复制代码
package cn.hao.kai.enums;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 示例枚举 ExampleEnum
 * <p>
 * 使用说明:
 * <ul>
 *   <li>前端需要同时获取枚举的 code 和 desc 字段。</li>
 *   <li>使用 {@link com.fasterxml.jackson.annotation.JsonFormat#shape()} = {@link com.fasterxml.jackson.annotation.JsonFormat.Shape#OBJECT}
 *       使枚举以对象形式序列化,例如:
 *       <pre>
 *       {
 *         "code": 0,
 *         "desc": "成功"
 *       }
 *       </pre>
 *   </li>
 *   <li>由于实现了接口 {@code IBaseEnum},Jackson 会默认将 {@code getEnumCode()}、
 *       {@code getEnumDescription()} 一并序列化为属性。</li>
 *   <li>为避免重复字段,使用 {@link com.fasterxml.jackson.annotation.JsonIgnore}
 *       忽略这些方法的序列化。</li>
 * </ul>
 * </p>
 *
 * @author Hao Kai
 */
@Getter
@AllArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum ExampleEnum implements IBaseEnum<Integer> {
    SUCCESS(0, "成功"),
    FAIL(1, "失败");

    private final Integer code;
    private final String desc;

    @JsonIgnore
    @Override
    public Integer getEnumCode() {
        return code;
    }

    @JsonIgnore
    @Override
    public String getEnumDescription() {
        return desc;
    }
}
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
默_笙3 天前
🍙 给每个请求过安检:FastAPI 是怎么把校验写进类型注解的
python
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
qq_426003963 天前
启动playwright录制codegen生成自动化测试脚本
python·自动化
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
长沙三为智能科技3 天前
家政小程序开发从0到上线:五阶段交付流程与验收清单
python
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端