¥
立即购买

Java枚举值生成器

12 浏览
1 试用
0 购买
Dec 6, 2025更新

本提示词专为Java开发场景设计,能够根据具体业务需求生成规范的枚举值定义。通过分析应用场景、枚举用途和业务约束,提供符合Java编码标准的枚举结构,包括合理的命名规范、完整的枚举值列表以及必要的文档注释,帮助开发者快速构建高质量的枚举类型,提升代码的可读性和可维护性。适用于权限管理、状态机、配置选项等多种Java开发场景。

枚举概述

  • 业务用途:该枚举用于多租户SaaS后台的统一角色模型,控制菜单可见、数据域隔离与 REST API 访问,并参与审批流、审计日志与跨服务鉴权。
  • 设计思路:
    • 采用稳定且全局唯一的 code,作为序列化与持久化标识,避免使用 ordinal。
    • 常量命名使用 UPPER_SNAKE_CASE;code 以 ROLE_ 前缀与 Spring Security 约定对齐。
    • 提供 fromCode 与 hasPermission 方法,便于反序列化与权限快速判断。
    • 提供 displayName(默认显示名)与 messageKey(国际化 key),兼顾默认显示与 i18n。
    • 引入优先级 priority(数值越小权限越高),支持灰度与决策控制。
    • 默认权限标签 defaultPermissionTags 以标签集合表达能力边界,便于扩展和灰度开关。

枚举定义

package com.example.security;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.springframework.security.core.GrantedAuthority;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统统一角色模型。
 *
 * 设计约束:
 * 1) code 全局唯一且长期稳定;仅以 code 进行序列化/持久化;严禁使用 ordinal。
 * 2) 常量命名使用 UPPER_SNAKE_CASE;code 以 ROLE_ 前缀兼容 Spring Security。
 * 3) priority 数值越小代表级别越高(如系统管理员 < 租户管理员)。
 * 4) defaultPermissionTags 为角色的默认权限标签集合,可用于菜单/数据域/API/审批/审计等快速判定与灰度开关。
 *
 * 国际化建议:
 * - displayName 为默认回退展示名;
 * - messageKey 可交由 Spring MessageSource 或前端 i18n 解析为本地化文案。
 */
public enum Role implements GrantedAuthority {

    /**
     * 系统管理员(平台级),具备平台范围的全局管理能力。
     */
    SYSTEM_ADMIN(
            "ROLE_SYSTEM_ADMIN",
            "System Administrator",
            "role.system_admin",
            10,
            Set.of("MENU_ALL", "DATA_ALL", "API_ALL", "APPROVAL_ALL", "AUDIT_ALL", "XSRV_ALL")
    ),

    /**
     * 租户管理员(租户级),管理本租户的用户、项目与配置。
     */
    TENANT_ADMIN(
            "ROLE_TENANT_ADMIN",
            "Tenant Administrator",
            "role.tenant_admin",
            20,
            Set.of("MENU_TENANT_ADMIN", "DATA_TENANT_ALL", "API_TENANT_ALL", "APPROVAL_TENANT", "AUDIT_TENANT")
    ),

    /**
     * 项目管理员(项目级),管理项目成员、资源与发布。
     */
    PROJECT_ADMIN(
            "ROLE_PROJECT_ADMIN",
            "Project Administrator",
            "role.project_admin",
            30,
            Set.of("MENU_PROJECT_ADMIN", "DATA_PROJECT_ALL", "API_PROJECT_ALL", "APPROVAL_PROJECT", "AUDIT_PROJECT")
    ),

    /**
     * 成员(可写),参与日常研发/运营,具备项目写权限。
     */
    MEMBER(
            "ROLE_MEMBER",
            "Member",
            "role.member",
            50,
            Set.of("MENU_MEMBER", "DATA_PROJECT", "API_WRITE", "AUDIT_SELF")
    ),

    /**
     * 只读访客(最小权限),仅可查看。
     */
    READONLY_GUEST(
            "ROLE_READONLY_GUEST",
            "Readonly Guest",
            "role.readonly_guest",
            90,
            Set.of("MENU_READONLY", "DATA_READONLY", "API_READONLY")
    );

    private final String code;
    private final String displayName;
    private final String messageKey;
    private final int priority;
    private final Set<String> defaultPermissionTags;

    Role(String code,
         String displayName,
         String messageKey,
         int priority,
         Set<String> defaultPermissionTags) {
        this.code = Objects.requireNonNull(code, "code");
        this.displayName = Objects.requireNonNull(displayName, "displayName");
        this.messageKey = Objects.requireNonNull(messageKey, "messageKey");
        this.priority = priority;
        this.defaultPermissionTags = Collections.unmodifiableSet(new LinkedHashSet<>(defaultPermissionTags));
    }

    // ------- Jackson 兼容:以 code 序列化/反序列化 -------

    /**
     * 返回稳定的全局唯一 code,用于 JSON 序列化/持久化。
     */
    @JsonValue
    public String getCode() {
        return code;
    }

    /**
     * 通过 code 进行 JSON 反序列化。
     */
    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public static Role fromJson(String code) {
        return fromCode(code);
    }

    // ------- Spring Security 兼容:作为 GrantedAuthority -------

    /**
     * Spring Security 所需的权限标识,直接返回 code。
     */
    @Override
    public String getAuthority() {
        return code;
    }

    // ------- 业务属性 -------

    /**
     * 默认回退显示名(若未做 i18n 替换时使用)。
     */
    public String getDisplayName() {
        return displayName;
    }

    /**
     * 国际化消息键(示例:role.system_admin)。
     */
    public String getMessageKey() {
        return messageKey;
    }

    /**
     * 角色优先级,数值越小权限级别越高。
     */
    public int getPriority() {
        return priority;
    }

    /**
     * 该角色的默认权限标签集合(不可变)。
     */
    public Set<String> getDefaultPermissionTags() {
        return defaultPermissionTags;
    }

    /**
     * 简单权限判断:当前角色是否包含给定权限标签(大小写敏感,按完全匹配)。
     * 如需通配/前缀匹配,请在业务层扩展。
     */
    public boolean hasPermission(String permissionTag) {
        if (permissionTag == null || permissionTag.isEmpty()) {
            return false;
        }
        return defaultPermissionTags.contains(permissionTag);
    }

    /**
     * 比较当前角色是否高于另一个角色(优先级数字越小越高)。
     */
    public boolean higherThan(Role other) {
        return this.priority < other.priority;
    }

    // ------- code 查找与唯一性保障 -------

    private static final Map<String, Role> CODE_LOOKUP;

    static {
        Map<String, Role> map = Arrays.stream(values())
                .collect(Collectors.toMap(
                        Role::getCode,
                        r -> r,
                        (a, b) -> {
                            // 理论上不会发生,若发生说明 code 冲突
                            throw new IllegalStateException("Duplicated role code: " + a.getCode());
                        },
                        LinkedHashMap::new
                ));
        CODE_LOOKUP = Collections.unmodifiableMap(map);
    }

    /**
     * 根据稳定 code 获取角色;若 code 无效则抛出异常。
     *
     * @throws IllegalArgumentException 如果 code 未匹配到任何角色
     */
    public static Role fromCode(String code) {
        Role role = (code == null) ? null : CODE_LOOKUP.get(code);
        if (role == null) {
            throw new IllegalArgumentException("Unknown role code: " + code);
        }
        return role;
    }

    /**
     * 尝试根据 code 查找角色;未匹配时返回 Optional.empty(),便于向后兼容处理。
     */
    public static Optional<Role> tryFromCode(String code) {
        return Optional.ofNullable(code).map(CODE_LOOKUP::get);
    }
}

使用示例

// 1) 反序列化与序列化(Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(Role.MEMBER); // 输出: "ROLE_MEMBER"
Role role = mapper.readValue("\"ROLE_PROJECT_ADMIN\"", Role.class); // Role.PROJECT_ADMIN

// 2) 安全框架(Spring Security):作为 GrantedAuthority 使用
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;

Authentication auth = new UsernamePasswordAuthenticationToken(
        "alice",
        null,
        Set.of(Role.TENANT_ADMIN) // 直接传入枚举,GrantedAuthority = code
);
// hasRole('TENANT_ADMIN') 与 hasAuthority('ROLE_TENANT_ADMIN') 均可配合使用

// 3) 业务判断:菜单 / 数据域 / API 开关
if (role.hasPermission("MENU_PROJECT_ADMIN")) {
    // 展示项目管理员菜单
}
if (Role.SYSTEM_ADMIN.higherThan(Role.MEMBER)) {
    // 系统管理员级别高于成员
}

// 4) 枚举查找:向后兼容地处理未知值
Role parsed = Role.tryFromCode("ROLE_UNKNOWN")
                  .orElse(Role.READONLY_GUEST); // 优雅降级

// 5) 国际化显示
// Spring MessageSource: messageKey -> 本地化名称;若找不到则使用 displayName 回退
String i18nName = messageSource.getMessage(role.getMessageKey(), null, role.getDisplayName(), locale);

// 6) Switch 使用
switch (role) {
    case SYSTEM_ADMIN:
        // 平台级操作
        break;
    case TENANT_ADMIN:
        // 租户级操作
        break;
    default:
        // 常规或只读
        break;
}

注意事项

  • 序列化与持久化
    • 禁止使用 ordinal;请使用 code 进行 JSON 序列化与数据库持久化。
    • JPA 持久化建议使用 AttributeConverter 将 Role 与 code 映射。例如:
      • AttributeConverter<Role, String>: convertToDatabaseColumn = role.getCode(); convertToEntityAttribute = Role.fromCode(code)。
  • 命名与唯一性
    • 常量名使用 UPPER_SNAKE_CASE;code 全局唯一且长期稳定,禁止修改已发布 code。
    • 如需新增角色,仅新增新常量与新 code,不要复用旧 code。
  • 国际化
    • 优先通过 messageKey 获取本地化名称,displayName 仅作为回退。
  • 权限标签
    • defaultPermissionTags 为“默认能力边界”,可结合业务扩展通配/层级策略(例如前缀匹配),用于菜单、数据域、API、审批与审计的快速开关与灰度发布。
  • 向后兼容
    • 上游服务可使用 tryFromCode 处理未知 code 并降级,避免枚举新增导致反序列化失败。
    • 如果希望 Jackson 在未知值时使用默认值,可在全局启用 ObjectMapper 的 READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE,并引入一个默认常量(如 UNKNOWN);当前实现未包含该常量,以保持角色集合纯净。
  • 版本与依赖
    • 代码使用 Set.of(...) 需 JDK 9+(建议 11+)。如需 JDK 8,请改用 Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(...)))。
    • 若不希望在枚举中直接依赖 Spring Security,可去掉 implements GrantedAuthority,并在业务处将 role.getCode() 包装为 SimpleGrantedAuthority。

枚举概述

  • 业务用途:用于电商订单全链路的状态管理,驱动前端提示、仓配协同与事件消息发送,并兼顾异常重试、对账统计与幂等处理。
  • 设计思路:
    • 以稳定的字符串状态码进行唯一标识(ORDER_前缀),避免依赖 ordinal,确保序列化与日志只输出 code,便于跨系统对账与消息解耦。
    • 提供 isTerminal、canRefund、nextStates 等方法,支持状态判定、可退款校验与合规迁移控制。
    • 允许自状态迁移(自环)以支持异常重试与幂等(同一事件重复处理不导致非法迁移)。
    • 预留 UNKNOWN 以便当存在未识别的新增状态码时能够向后兼容(反序列化到 UNKNOWN 而不抛错);新增过渡状态只需扩展静态迁移表与消息映射即可。
    • 提供 reportKey 与 messageTopic 映射,确保与报表和消息主题的一致性。

枚举定义

package com.example.order;

import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

// 如使用 Jackson 做 JSON 序列化/反序列化,可启用以下注解。
// 非 Jackson 环境可忽略或替换为自定义序列化策略。
// import com.fasterxml.jackson.annotation.JsonCreator;
// import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
// import com.fasterxml.jackson.annotation.JsonValue;

/**
 * 订单状态(全链路)
 * - 使用字符串 code(ORDER_ 前缀)作为稳定标识以便序列化、日志与跨系统对账。
 * - 禁止依赖 ordinal;toString 与 JSON 序列化仅输出 code。
 * - nextStates 包含自环(自身)以支持异常重试/幂等。
 * - UNKNOWN 用于向后兼容未来新增状态码。
 */
public enum OrderStatus {

    /**
     * 未知状态(向后兼容占位)
     * 解析到未识别的 code 时使用本状态,正常流程不应设置为 UNKNOWN。
     */
    // @JsonEnumDefaultValue
    UNKNOWN(
        "ORDER_UNKNOWN",
        "未知状态",
        "unknown",
        "order.status.unknown",
        false,
        false
    ),

    /**
     * 已创建:下单成功,等待支付
     */
    CREATED(
        "ORDER_CREATED",
        "已创建",
        "created",
        "order.status.created",
        false,
        false
    ),

    /**
     * 待支付:已发起支付等待结果
     */
    PENDING_PAYMENT(
        "ORDER_PENDING_PAYMENT",
        "待支付",
        "pending_payment",
        "order.status.pending_payment",
        false,
        false
    ),

    /**
     * 已支付:待仓配拣货
     */
    PAID(
        "ORDER_PAID",
        "已支付",
        "paid",
        "order.status.paid",
        false,
        true // 已支付允许发起退款
    ),

    /**
     * 拣货中:仓内处理
     */
    PICKING(
        "ORDER_PICKING",
        "拣货中",
        "picking",
        "order.status.picking",
        false,
        true // 支持退款(拣货未出库)
    ),

    /**
     * 已出库/已发货
     */
    SHIPPED(
        "ORDER_SHIPPED",
        "已发货",
        "shipped",
        "order.status.shipped",
        false,
        true // 支持拦截退款/拒收退款策略(由业务网关控制)
    ),

    /**
     * 已签收/已送达(交易完成)
     */
    DELIVERED(
        "ORDER_DELIVERED",
        "已签收",
        "delivered",
        "order.status.delivered",
        true,  // 终态
        false  // 默认不支持退款(售后另行处理,不纳入此主流程)
    ),

    /**
     * 已取消(未履约完成即终止)
     */
    CANCELED(
        "ORDER_CANCELED",
        "已取消",
        "canceled",
        "order.status.canceled",
        true,  // 终态
        false
    ),

    /**
     * 已退款(全额或最终退款)
     */
    REFUNDED(
        "ORDER_REFUNDED",
        "已退款",
        "refunded",
        "order.status.refunded",
        true,  // 终态
        false
    );

    // code 为唯一外部标识,序列化与日志仅输出此字段
    private final String code;
    // 面向用户/前端的文案
    private final String label;
    // 报表聚合使用的稳定 key(与数仓/指标对齐)
    private final String reportKey;
    // 消息主题(topic 或路由键),用于状态事件推送
    private final String messageTopic;
    // 是否为终态
    private final boolean terminal;
    // 是否可退款(在本状态下是否允许发起退款流程)
    private final boolean refundable;

    OrderStatus(String code,
                String label,
                String reportKey,
                String messageTopic,
                boolean terminal,
                boolean refundable) {
        this.code = code;
        this.label = label;
        this.reportKey = reportKey;
        this.messageTopic = messageTopic;
        this.terminal = terminal;
        this.refundable = refundable;
    }

    // Jackson 序列化时仅输出 code;非 Jackson 环境可使用自定义序列化器
    // @JsonValue
    public String getCode() {
        return code;
    }

    public String getLabel() {
        return label;
    }

    public String getReportKey() {
        return reportKey;
    }

    public String getMessageTopic() {
        return messageTopic;
    }

    public boolean isTerminal() {
        return terminal;
    }

    public boolean canRefund() {
        return refundable;
    }

    /**
     * 允许的迁移集合(包含自环,用于异常重试/幂等)。
     * 例如:PENDING_PAYMENT -> {PENDING_PAYMENT, PAID, CANCELED}
     */
    public Set<OrderStatus> nextStates() {
        Set<OrderStatus> set = TRANSITIONS.get(this);
        return set != null ? set : Collections.singleton(this);
    }

    /**
     * 是否允许从当前状态迁移到目标状态。
     * 迁移合法包括自环(幂等处理)。
     */
    public boolean canTransitionTo(OrderStatus target) {
        if (target == null) return false;
        return nextStates().contains(target);
    }

    /**
     * 基于 code 的解析(向后兼容:未知 code 映射为 UNKNOWN)。
     */
    // @JsonCreator
    public static OrderStatus fromCode(String code) {
        if (code == null || code.isEmpty()) return UNKNOWN;
        OrderStatus s = BY_CODE.get(code);
        return s != null ? s : UNKNOWN;
    }

    /**
     * 静态工具:检查 from -> to 是否允许。
     */
    public static boolean canTransition(OrderStatus from, OrderStatus to) {
        return from != null && from.canTransitionTo(to);
    }

    /**
     * toString 仅输出 code,便于统一日志/审计。
     */
    @Override
    public String toString() {
        return code;
    }

    // ---- 内部映射:code -> enum,用于高效解析 ----
    private static final Map<String, OrderStatus> BY_CODE;
    static {
        EnumMap<OrderStatus, String> tmp = new EnumMap<>(OrderStatus.class);
        for (OrderStatus s : OrderStatus.values()) {
            tmp.put(s, s.code);
        }
        Map<String, OrderStatus> map = new java.util.HashMap<>();
        for (Map.Entry<OrderStatus, String> e : tmp.entrySet()) {
            String c = e.getValue();
            if (map.put(c, e.getKey()) != null) {
                throw new IllegalStateException("Duplicate order status code: " + c);
            }
        }
        BY_CODE = Collections.unmodifiableMap(map);
    }

    // ---- 迁移关系:包含自环(幂等) ----
    private static final EnumMap<OrderStatus, Set<OrderStatus>> TRANSITIONS = new EnumMap<>(OrderStatus.class);
    static {
        // 辅助:生成不可变集合
        java.util.function.Function<OrderStatus[], Set<OrderStatus>> setOf =
                (arr) -> Collections.unmodifiableSet(EnumSet.of(arr[0], arr));

        // 说明:每个集合都包含自环(第一个参数即 from)
        put(CREATED,
            CREATED, PENDING_PAYMENT, CANCELED);

        put(PENDING_PAYMENT,
            PENDING_PAYMENT, PAID, CANCELED);

        put(PAID,
            PAID, PICKING, CANCELED, REFUNDED);

        put(PICKING,
            PICKING, SHIPPED, CANCELED, REFUNDED);

        put(SHIPPED,
            SHIPPED, DELIVERED, REFUNDED);

        put(DELIVERED,
            DELIVERED /* 终态,自环仅为幂等等价重复上报 */);

        put(CANCELED,
            CANCELED /* 终态 */);

        put(REFUNDED,
            REFUNDED /* 终态 */);

        put(UNKNOWN,
            UNKNOWN /* 不建议使用,作为占位 */);
    }

    private static void put(OrderStatus from, OrderStatus... allows) {
        // 构造包含自环的集合(确保 allows 已包含 from;若未包含则自动加入)
        EnumSet<OrderStatus> set = EnumSet.noneOf(OrderStatus.class);
        if (allows == null || allows.length == 0) {
            set.add(from);
        } else {
            Collections.addAll(set, allows);
            set.add(from);
        }
        TRANSITIONS.put(from, Collections.unmodifiableSet(set));
    }
}

使用示例

import com.example.order.OrderStatus;
import java.util.Set;

public class OrderStatusDemo {

    // 事件到达时的状态迁移校验(包含幂等自环)
    public static boolean tryTransition(String orderId, OrderStatus current, OrderStatus target) {
        if (!OrderStatus.canTransition(current, target)) {
            // 非法迁移,记录并拒绝
            System.out.printf("Reject transition %s -> %s for order %s%n", current, target, orderId);
            return false;
        }
        // 持久化 target 状态(若 target == current 则为幂等重试)
        System.out.printf("Apply transition %s -> %s for order %s%n", current, target, orderId);
        // persist(orderId, target.getCode());
        // 发送状态事件(使用 messageTopic 与 code)
        // messageBus.publish(target.getMessageTopic(), Map.of("orderId", orderId, "status", target.getCode()));
        return true;
    }

    // 前端提示 / 文案展示
    public static String prompt(OrderStatus status) {
        switch (status) {
            case CREATED:
                return "订单已创建,请尽快支付";
            case PENDING_PAYMENT:
                return "支付处理中,请稍候";
            case PAID:
                return "支付成功,等待拣货";
            case PICKING:
                return "仓库拣货中,请耐心等待";
            case SHIPPED:
                return "包裹已发出,注意查收";
            case DELIVERED:
                return "包裹已签收,感谢您的购买";
            case CANCELED:
                return "订单已取消";
            case REFUNDED:
                return "已完成退款";
            case UNKNOWN:
            default:
                return "状态更新中";
        }
    }

    // 对账与报表统计:聚合 reportKey
    public static void report(OrderStatus status) {
        String key = status.getReportKey(); // 如 "shipped"
        // metrics.counter("order_status", "key", key).increment();
        System.out.printf("Report increment for key=%s%n", key);
    }

    public static void main(String[] args) {
        OrderStatus cur = OrderStatus.fromCode("ORDER_PAID");
        Set<OrderStatus> next = cur.nextStates();
        System.out.println("Next allows from PAID: " + next); // 输出 code 集合(toString 即 code)

        // 示例迁移:PAID -> PICKING
        tryTransition("O202501010001", cur, OrderStatus.PICKING);

        // 幂等重试:PICKING -> PICKING
        tryTransition("O202501010001", OrderStatus.PICKING, OrderStatus.PICKING);

        // 非法迁移:PENDING_PAYMENT -> DELIVERED
        tryTransition("O202501010002", OrderStatus.PENDING_PAYMENT, OrderStatus.DELIVERED);

        // 报表统计
        report(OrderStatus.SHIPPED);

        // 前端提示
        System.out.println(prompt(OrderStatus.SHIPPED));

        // 序列化(示意):status.getCode() 或 Jackson @JsonValue
        System.out.println("Serialize: " + OrderStatus.SHIPPED.getCode()); // "ORDER_SHIPPED"
    }
}

注意事项

  • 稳定性与兼容性
    • 仅以 code 作为外部标识进行序列化与日志输出;禁止依赖 ordinal 或 name。
    • 如使用 Jackson,建议启用 @JsonValue 与 @JsonCreator,并保留 UNKNOWN(或使用 @JsonEnumDefaultValue)以兼容未来新增状态码。
    • 新增状态或过渡时:
      • 新增一个唯一 code(以 ORDER_ 前缀);
      • 补充 label、reportKey、messageTopic;
      • 在静态 TRANSITIONS 中维护合法迁移(务必包含自环)。
  • 幂等与重试
    • nextStates 默认包含自环,支持重复消息/重复回调的安全处理。
    • canTransition/canTransitionTo 用于网关/服务间的保护,避免越级或逆向迁移。
  • 退款标记
    • canRefund 仅作为状态维度的可退款指示,具体业务规则(如部分退款、拦截退款、售后等)应在领域服务内进一步校验(支付渠道、物流节点等)。
  • 报表与消息
    • reportKey 与 messageTopic 与数据仓库指标、消息中台主题保持一致性;如需变更请以兼容方式做别名映射。
  • 代码规范
    • 确保 BY_CODE 无重复(枚举已在静态块校验)。
    • 避免在 switch 中遗漏 UNKNOWN 分支,防止未来新增状态导致的默认行为不当。
    • 单元测试覆盖:fromCode 解析、迁移矩阵合法性(不可从终态迁出,除自环)、退款标记与前端提示一致性。

枚举概述

  • 业务用途:在微服务平台中为功能开关与系统配置提供统一、类型安全的配置键集合,替代散落在代码中的硬编码字符串,便于集中治理、审计和热更新。
  • 设计思路:
    • 统一前缀与命名:所有配置键使用 app. 前缀并采用 kebab-case(短横线)风格,天然兼容 Spring Boot Binder 与主流配置中心。
    • 范围隔离:为每个键标注作用域(GLOBAL、TENANT、SERVICE),并提供作用域校验与派生键生成,满足多租户与多服务隔离。
    • 安全默认:每个键都包含安全可回滚的默认值,避免因配置缺失或回滚失败导致故障。
    • 互操作性:提供 fromKey、getDefaultValue、scope 校验方法;键可直接用于 Spring 的 Environment/Binder 进行类型绑定和热更新。

枚举定义

package com.example.config;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 统一的应用配置键定义。所有键:
 * 1) 必须以 "app." 前缀开头;
 * 2) 使用 kebab-case(如: feature-toggle.enabled);
 * 3) 按作用域进行隔离:GLOBAL(全局)、TENANT(租户级)、SERVICE(服务级)。
 *
 * 作用域派生键(用于多租户/多服务隔离)约定:
 * - TENANT 作用域:app.tenants.{tenantId}.<suffix>
 * - SERVICE 作用域:app.services.{serviceName}.<suffix>
 * 其中 <suffix> 为 canonical key 去掉 "app." 前缀后的部分。
 *
 * 示例:
 * - Canonical: app.payment.enabled
 * - TENANT:    app.tenants/acme/payment.enabled 或 app.tenants.acme.payment.enabled(推荐用点分隔)
 *   约定采用点分隔:app.tenants.acme.payment.enabled
 * - SERVICE:   app.services.order-service.payment.enabled
 *
 * 注意:派生键仅用于区分作用域;如无匹配,则回退到 canonical key(GLOBAL)。
 */
public enum AppConfigKey {

    /**
     * 是否启用风控开关(租户级)。
     * 默认 false,确保在未明确开启时不影响正常放行策略。
     *
     * 示例:
     * - Canonical: app.feature.risk-control.enabled
     * - Tenant:    app.tenants.acme.feature.risk-control.enabled
     */
    FEATURE_RISK_CONTROL_ENABLED(
            "app.feature.risk-control.enabled",
            "false",
            "租户级风控功能开关;关闭时仅执行基础校验。",
            ConfigScope.TENANT
    ),

    /**
     * 风控策略(租户级)。
     * 取值示例:conservative / balanced / aggressive(默认 conservative 更安全)。
     */
    FEATURE_RISK_CONTROL_STRATEGY(
            "app.feature.risk-control.strategy",
            "conservative",
            "租户级风控策略模式。",
            ConfigScope.TENANT
    ),

    /**
     * 默认缓存过期时间(秒)(服务级)。
     * 默认 600 秒,安全且可回滚,避免缓存穿透。
     */
    CACHE_DEFAULT_TTL_SECONDS(
            "app.cache.default-ttl-seconds",
            "600",
            "服务级默认缓存 TTL(秒)。",
            ConfigScope.SERVICE
    ),

    /**
     * 是否启用布隆过滤器(服务级)。
     * 默认 false,避免对内存/CPU产生未评估的额外开销。
     */
    CACHE_BLOOM_FILTER_ENABLED(
            "app.cache.bloom-filter.enabled",
            "false",
            "启用布隆过滤器以降低缓存穿透。",
            ConfigScope.SERVICE
    ),

    /**
     * 支付开通(租户级)。
     * 默认 false,确保未开通租户不暴露支付能力。
     */
    PAYMENT_ENABLED(
            "app.payment.enabled",
            "false",
            "租户级支付能力是否启用。",
            ConfigScope.TENANT
    ),

    /**
     * 支付服务提供方(租户级)。
     * 默认 none,避免误接入;具体值由集成时约定(如: stripe/alipay/wechat/…)。
     */
    PAYMENT_PROVIDER(
            "app.payment.provider",
            "none",
            "租户级支付提供方标识。",
            ConfigScope.TENANT
    ),

    /**
     * 日志级别(服务级)。
     * 默认 INFO。建议仅在排障期间提升日志级别。
     */
    LOGGING_LEVEL(
            "app.logging.level",
            "INFO",
            "服务级日志级别(TRACE/DEBUG/INFO/WARN/ERROR)。",
            ConfigScope.SERVICE
    ),

    /**
     * 是否输出 JSON 日志(服务级)。
     * 默认 false,避免在未准备聚合/分析时影响可读性。
     */
    LOGGING_JSON_ENABLED(
            "app.logging.json.enabled",
            "false",
            "服务级 JSON 日志输出开关。",
            ConfigScope.SERVICE
    ),

    /**
     * 服务级限流(每秒请求数)。
     * 默认 100,提供基础保护能力。
     */
    SERVICE_RATE_LIMIT_PPS(
            "app.service.rate-limit-pps",
            "100",
            "服务级每秒请求限流阈值。",
            ConfigScope.SERVICE
    ),

    /**
     * 熔断开关(服务级)。
     * 默认 true,更安全,避免级联故障。
     */
    SERVICE_CIRCUIT_BREAKER_ENABLED(
            "app.service.circuit-breaker.enabled",
            "true",
            "服务级熔断器开关。",
            ConfigScope.SERVICE
    ),

    /**
     * 灰度发布比例(服务级)。
     * 默认 0;单位为百分比 0-100。
     */
    FEATURE_GRAY_RELEASE_PERCENTAGE(
            "app.feature.gray-release.percentage",
            "0",
            "服务级灰度流量占比(0-100)。",
            ConfigScope.SERVICE
    ),

    /**
     * 维护模式(全局)。
     * 默认 false;开启后可降级非关键路径(由各服务自行解释该开关)。
     */
    FEATURE_MAINTENANCE_MODE_ENABLED(
            "app.feature.maintenance-mode.enabled",
            "false",
            "全局维护模式开关。",
            ConfigScope.GLOBAL
    );

    public static final String APP_PREFIX = "app.";
    private static final String TENANTS_SEGMENT = "tenants";
    private static final String SERVICES_SEGMENT = "services";
    private static final Pattern SEGMENT_PATTERN = Pattern.compile("[a-z0-9]+(-[a-z0-9]+)*");

    private static final Map<String, AppConfigKey> BY_KEY;

    private final String key;           // canonical key
    private final String defaultValue;  // safe, rollback-friendly
    private final String description;   // brief doc
    private final ConfigScope scope;

    AppConfigKey(String key, String defaultValue, String description, ConfigScope scope) {
        this.key = Objects.requireNonNull(key, "key");
        this.defaultValue = Objects.requireNonNull(defaultValue, "defaultValue");
        this.description = Objects.requireNonNull(description, "description");
        this.scope = Objects.requireNonNull(scope, "scope");
    }

    static {
        Map<String, AppConfigKey> map = new HashMap<>();
        for (AppConfigKey k : values()) {
            validateNaming(k.key);
            if (map.put(k.key, k) != null) {
                throw new IllegalStateException("Duplicated config key: " + k.key);
            }
        }
        BY_KEY = Collections.unmodifiableMap(map);
    }

    /**
     * 返回 canonical key(全局键,形如 app.xxx.yyy)。
     */
    public String key() {
        return key;
    }

    /**
     * 返回默认值(字符串形式)。调用方可据需要转换为具体类型。
     */
    public String getDefaultValue() {
        return defaultValue;
    }

    /**
     * 返回键的作用域。
     */
    public ConfigScope getScope() {
        return scope;
    }

    /**
     * 返回简单说明,便于界面/审计展示。
     */
    public String getDescription() {
        return description;
    }

    /**
     * 根据 canonical key 查找枚举常量。
     * @throws IllegalArgumentException 不存在时抛出
     */
    public static AppConfigKey fromKey(String key) {
        AppConfigKey k = BY_KEY.get(key);
        if (k == null) {
            throw new IllegalArgumentException("Unknown config key: " + key);
        }
        return k;
    }

    /**
     * 生成租户级派生键(TENANT)。
     * 约定格式:app.tenants.{tenantId}.<suffix>
     * @throws IllegalStateException 如果该键的作用域不是 TENANT
     */
    public String keyForTenant(String tenantId) {
        if (scope != ConfigScope.TENANT) {
            throw new IllegalStateException("Key " + key + " is not TENANT-scoped.");
        }
        requireNonBlank(tenantId, "tenantId");
        return APP_PREFIX + TENANTS_SEGMENT + "." + tenantId + "." + suffix();
    }

    /**
     * 生成服务级派生键(SERVICE)。
     * 约定格式:app.services.{serviceName}.<suffix>
     * @throws IllegalStateException 如果该键的作用域不是 SERVICE
     */
    public String keyForService(String serviceName) {
        if (scope != ConfigScope.SERVICE) {
            throw new IllegalStateException("Key " + key + " is not SERVICE-scoped.");
        }
        requireNonBlank(serviceName, "serviceName");
        return APP_PREFIX + SERVICES_SEGMENT + "." + serviceName + "." + suffix();
    }

    /**
     * 作用域校验:用于在写入/覆盖时确保使用了正确的作用域。
     * @throws IllegalArgumentException 不匹配时抛出
     */
    public void validateScope(ConfigScope expected) {
        if (this.scope != expected) {
            throw new IllegalArgumentException(
                    "Scope mismatch for key " + key + ": expected " + expected + ", actual " + scope);
        }
    }

    private String suffix() {
        return key.substring(APP_PREFIX.length()); // strip "app."
    }

    private static void validateNaming(String k) {
        if (!k.startsWith(APP_PREFIX)) {
            throw new IllegalStateException("Key must start with 'app.': " + k);
        }
        String[] parts = k.substring(APP_PREFIX.length()).split("\\.");
        if (parts.length == 0) {
            throw new IllegalStateException("Key missing segments: " + k);
        }
        for (String p : parts) {
            if (!SEGMENT_PATTERN.matcher(p).matches()) {
                throw new IllegalStateException("Key segment not kebab-case: " + k + " -> " + p);
            }
        }
        if (!k.equals(k.toLowerCase())) {
            throw new IllegalStateException("Key must be lowercase: " + k);
        }
    }

    private static void requireNonBlank(String s, String name) {
        if (s == null || s.trim().isEmpty()) {
            throw new IllegalArgumentException(name + " must not be blank");
        }
    }
}

/**
 * 配置作用域。
 * - GLOBAL:全局默认配置;
 * - TENANT:租户级配置(可覆盖 GLOBAL);
 * - SERVICE:服务级配置(可覆盖 GLOBAL)。
 *
 * 注意:TENANT 与 SERVICE 互相独立,最终生效策略由业务约定(例如:优先使用更具体的作用域)。
 */
enum ConfigScope {
    GLOBAL,
    TENANT,
    SERVICE
}

使用示例

  • 基础读取(Environment + Spring Boot Binder),带作用域回退与默认值
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;

public class ConfigReader {

    private final Environment env;

    public ConfigReader(Environment env) {
        this.env = env;
    }

    /**
     * 读取配置:根据作用域拼接派生键,找不到则回退到 canonical key,最后使用默认值。
     * 仅演示常见类型转换(String/Boolean/Integer/Long/Double);更复杂类型可自行扩展。
     */
    public <T> T read(AppConfigKey key, Class<T> type, String tenantId, String serviceName) {
        Binder binder = Binder.get(env);

        // 1) 按作用域尝试读取(优先更具体的作用域)
        String[] candidates = buildCandidates(key, tenantId, serviceName);

        for (String candidate : candidates) {
            if (candidate == null) continue;
            T v = binder.bind(candidate, Bindable.of(type)).orElse(null);
            if (v != null) return v;
        }

        // 2) 未命中则使用默认值
        return convertDefault(key.getDefaultValue(), type);
    }

    private static String[] buildCandidates(AppConfigKey k, String tenantId, String serviceName) {
        switch (k.getScope()) {
            case TENANT:
                return new String[] {
                        k.keyForTenant(tenantId), // tenant override
                        k.key()                   // fallback: global canonical
                };
            case SERVICE:
                return new String[] {
                        k.keyForService(serviceName), // service override
                        k.key()                       // fallback: global canonical
                };
            case GLOBAL:
            default:
                return new String[] { k.key() };
        }
    }

    @SuppressWarnings("unchecked")
    private static <T> T convertDefault(String raw, Class<T> type) {
        if (type == String.class) return (T) raw;
        if (type == Boolean.class || type == boolean.class) return (T) Boolean.valueOf(raw);
        if (type == Integer.class || type == int.class) return (T) Integer.valueOf(raw);
        if (type == Long.class || type == long.class) return (T) Long.valueOf(raw);
        if (type == Double.class || type == double.class) return (T) Double.valueOf(raw);
        // 如需 Duration、Enum 等,可在此补充解析逻辑
        throw new IllegalArgumentException("Unsupported type for default conversion: " + type);
    }
}
  • 典型用法示例
// 1) 风控开关(租户级)
boolean rcEnabled = new ConfigReader(env).read(
        AppConfigKey.FEATURE_RISK_CONTROL_ENABLED, Boolean.class, "acme", null);

// 2) 风控策略(租户级)
String rcStrategy = new ConfigReader(env).read(
        AppConfigKey.FEATURE_RISK_CONTROL_STRATEGY, String.class, "acme", null);

// 3) 缓存 TTL(服务级)
int ttl = new ConfigReader(env).read(
        AppConfigKey.CACHE_DEFAULT_TTL_SECONDS, Integer.class, null, "order-service");

// 4) 支付开通(租户级),scope 校验(写入/覆盖前)
AppConfigKey.PAYMENT_ENABLED.validateScope(ConfigScope.TENANT);
String tenantKey = AppConfigKey.PAYMENT_ENABLED.keyForTenant("acme"); // app.tenants.acme.payment.enabled

// 5) 日志级别(服务级)
String logLevel = new ConfigReader(env).read(
        AppConfigKey.LOGGING_LEVEL, String.class, null, "billing-service");

// 6) fromKey(由配置中心或审计日志回溯枚举)
AppConfigKey key = AppConfigKey.fromKey("app.feature.maintenance-mode.enabled");

注意事项

  • 命名规范
    • 全部以 app. 开头,分段用点号分隔,段内使用 kebab-case(小写字母/数字与短横线)。
    • 不得包含环境、密钥、令牌等敏感信息;默认值亦不得泄露敏感内容。
  • 作用域与优先级
    • TENANT 与 SERVICE 是相互独立的维度;示例中各自回退到 GLOBAL(canonical)。
    • 若需更复杂的优先级(如 TENANT > SERVICE > GLOBAL),请在读取逻辑中统一约定并实现。
  • 向后兼容
    • 新增键不应改变既有键的语义;调整默认值需审慎评估并配合灰度。
    • 如需废弃键,先添加 @Deprecated 并保留一段观测期,提供迁移路径。
  • Spring Boot Binder
    • 上述键天然兼容 Spring 的 Environment/Binder;复杂类型(Duration、Enum)可通过自定义转换器或在示例的 convertDefault 中扩展。
  • 审计与治理
    • 建议在读取逻辑中记录命中的具体键(tenant/service/global),用于变更可观测与合规审计。
  • 热更新
    • 配合配置中心与 Spring Cloud Context(如 @RefreshScope 或事件监听)可实现热更新;建议对关键开关设置变更保护(如最小/最大值、白名单)。

示例详情

解决的问题

把“枚举怎么设计”这件事从耗时的经验活,变成标准化、可复制的高效流程。一键生成符合团队规范的枚举定义与使用示例,覆盖权限角色、订单状态、系统配置等常见业务场景;减少漏项与命名混乱,提升可读性与可维护性;缩短评审与联调时间,让试用用户在真实项目中快速见效,促成团队从试用到付费的转化。

适用用户

Java后端开发工程师

快速生成订单、支付、权限等枚举;统一命名与注释,一次成型,减少返工与代码评审时间。

架构师与技术负责人

制定团队枚举规范与模板,审视业务状态覆盖度,确保跨模块一致性,降低维护与版本冲突成本。

测试工程师与QA

根据输出的枚举清单梳理用例边界与数据准备,及时发现缺失状态,减少漏测与回归风险。

特征总结

依据业务描述轻松生成规范枚举清单,附命名建议与注释,交付可直接落地的代码。
自动分析用途与边界,补全遗漏状态,避免上线后因枚举不全导致流程中断。
一键输出统一命名与注释模板,协作更一致,代码更易读,维护更省心。
针对权限、订单状态、配置选项等常见场景,提供即用示例,降低接入和沟通成本。
支持面向未来的扩展建议与兼容策略,减少版本演进时的破坏性改动与返工。
按规范生成注释与注意事项,帮助新人快速理解业务含义,缩短交接和学习时间。
可按场景参数定制枚举结构与示例调用,减少重复劳动,让代码评审更高效。
提供简洁的验证清单与最佳实践提醒,上线前自查,降低缺陷与回滚风险。

如何使用购买的提示词模板

1. 直接在外部 Chat 应用中使用

将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。

2. 发布为 API 接口调用

把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。

3. 在 MCP Client 中配置使用

在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。

AI 提示词价格
¥20.00元
先用后买,用好了再付款,超安全!

您购买后可以获得什么

获得完整提示词模板
- 共 558 tokens
- 3 个可调节参数
{ 业务场景 } { 枚举用途 } { 特殊约束 }
获得社区贡献内容的使用权
- 精选社区优质案例,助您快速上手提示词
使用提示词兑换券,低至 ¥ 9.9
了解兑换券 →
限时半价

不要错过!

半价获取高级提示词-优惠即将到期

17
:
23
小时
:
59
分钟
:
59