✨ 基于 JsonSerialize 实现接口返回数据的智能枚举转换(优雅告别前端硬编码!)

引言 🌟

在日常开发中,我们会返回数据给前端,但数据格式往往不符合前端的预期。这时我们可以使用 JsonSerialize 对返回的数据进行定制化处理 ------

比如将时间戳转换为日期格式、将 BigDecimal 转换为字符串格式等,这些都是比较常见的需求。

然而,在实际开发中,我们存入数据库的数据往往都是与枚举值相对应的编码 (如 "aliyun"、"dh3t" ),而前端展示时却需要对应的中文名称(如**"阿里云"** )。如果每次都在 Service 层手动 set 一个**desc**字段,不仅繁琐,还容易遗漏。

✅ 更优雅的做法是: 利用 Jackson 的 JsonSerializer ,在序列化阶段自动为枚举字段注入对应的描述信息 ,实现类似 provider: "aliyun" + providerDesc: "阿里云" 的自动输出。

  • 🎯 本文将带你实现:

  • 枚举值自动映射数据库 ✅(借助 MyBatis-Plus)

  • 接口返回时自动附加中文描述 ✅(通过自定义序列化器)

  • 前后端彻底解耦,新增枚举无需改前端代码 ✅

需要实现的效果如下图:

本文将带你一步步实现这一优雅方案!

🧩 1. 场景还原:我们面临的问题

假设我们有一个短信服务商枚举:

java 复制代码
public enum SmsProvider {
    aliyun("aliyun", "阿里云"),
    dh3t("dh3t", "大汉三通");

    private String value;
    private String desc;

    SmsProvider(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    // getter 省略...
}

数据库中存储的是 value 字段(如 "aliyun"),但我们希望接口返回时,除了原始字段外,还能自动携带一个 xxxDesc 字段用于展示,比如:

java 复制代码
{
  "provider": "aliyun",
  "providerDesc": "阿里云"
}

🎯 目标达成:前端直接使用 providerDesc 展示,无需任何判断逻辑!

⚙️ 2. 核心技术栈准备:MyBatis-Plus 枚举支持

2.1 什么是 IEnum<T>?

📌 IEnum<T> 是 MyBatis-Plus 提供的枚举接口,用于实现数据库字段与 Java 枚举之间的自动映射。

复制代码
com.baomidou.mybatisplus.core.enums.IEnum

当你使用 IEnum 时:

  • 查询数据库 → 自动映射为对应枚举对象
  • 插入/更新 → 自动提取 .getValue() 写入数据库

💡 它让"数据库值 ↔ 枚举对象"转换变得透明无感!


2.2 自定义通用枚举接口:IOxEnum

为了统一管理带描述的枚举类型,我们创建一个扩展接口:

java 复制代码
public interface IOxEnum extends IEnum<String> {
    /**
     * 获取枚举的中文描述
     */
    String getDesc();
}

✅ 所有需要"值+描述"功能的枚举都应实现此接口。


2.3 实现枚举类:SmsProvider

java 复制代码
public enum SmsProvider implements IOxEnum {

    aliyun("aliyun", "阿里云"),
    dh3t("dh3t", "大汉三通");

    private String value;
    private String desc;

    SmsProvider(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @Override
    public String getValue() {
        return this.value;
    }

    @Override
    public String getDesc() {
        return this.desc;
    }
}

✅ 注意:必须实现 getValue() 和 getDesc() 方法。

2.4 配置 MyBatis-Plus 扫描枚举包

在 application.yml 中添加配置,确保 MP 能识别你的枚举:

java 复制代码
mybatis-plus:
  type-enums-package: com.yourcompany.enums  # 替换为你的枚举包路径

✅ 这样 MyBatis-Plus 才能在 CRUD 时自动完成枚举转换!


🎛️ 3. 实现自定义 JSON 序列化器:自动注入 Desc 字段

现在进入最关键的一步:通过 JsonSerializer 在序列化时动态添加 xxxDesc 字段。

创建 OxJsonSerialize 序列化器

java 复制代码
@Slf4j
public class OxJsonSerialize<T> extends JsonSerializer<T> {

    @Override
    public void serialize(T value, JsonGenerator gen, SerializerProvider serializers)
            throws IOException {

        String fieldName = gen.getOutputContext().getCurrentName();
        log.info("正在序列化字段: {}, 值: {}", fieldName, value);

        if (value instanceof IEnum) {
            try {
                Class<?> clazz = value.getClass();
                Field descField = clazz.getDeclaredField("desc");
                descField.setAccessible(true);
                String desc = (String) descField.get(value);

                // 先输出原始字段(如 "provider": "aliyun")
                gen.writeObject(value);

                // 再输出描述字段(如 "providerDesc": "阿里云")
                gen.writeFieldName(fieldName + "Desc");
                gen.writeString(desc);

            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException("枚举字段 'desc' 访问失败,请检查是否正确定义", e);
            }
        } else {
            gen.writeObject(value); // 非枚举原样输出
        }
    }
}

🔍 原理说明:

  • 利用 JsonGenerator 控制输出流程
  • 获取当前字段名,动态拼接 Desc 后缀
  • 反射读取 desc 字段内容并写入 JSON

🏷️ 4. 在实体类中使用自定义序列化器

在你的实体类字段上添加 @JsonSerialize 注解:

java 复制代码
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@Data
public class SmsTemplate {

    private String name;

    @JsonSerialize(using = OxJsonSerialize.class)
    private SmsProvider provider; // 自动输出 provider + providerDesc
}

✅ 调用接口返回结果如下:

java 复制代码
{
  "name": "验证码模板",
  "provider": "aliyun",
  "providerDesc": "阿里云"
}

成功实现自动扩展描述字段!

✅ 5. 方案优势总结

优势 说明
免前端维护映射 新增枚举后,前端无需修改代码
前后端解耦 所有逻辑集中在后端,职责清晰
复用性强 只要实现 IOxEnum 接口,所有枚举均可使用
无缝集成 MP 利用 IEnum 实现数据库自动映射
扩展灵活 可进一步支持 color、icon 等元信息输出

📌 6. 注意事项 & 建议

  1. 字段命名规范 :建议所有描述字段统一以 Desc 结尾,便于前端识别。
  2. 泛型增强 :可将 OxJsonSerialize 改造成支持更多类型(如 Integer 枚举)。
  3. 日志调试:上线初期建议保留日志,便于排查字段匹配问题。

🎉 结语

通过 MyBatis-Plus + IEnum + JsonSerialize 的组合拳,我们实现了:

一次定义枚举,多端自动生效 ✅

再也不用写一堆 if-else 或维护冗长的 Map<String, String> 映射表了!

相关推荐
噢,我明白了1 小时前
java中唯一键和幂等键的应用
java·后端
程序猿乐锅1 小时前
【黑马点评 | 第八篇】Redisson分布式锁
java·数据库·spring boot·redis·分布式·spring·缓存
福兮说1 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea1 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
考虑考虑1 小时前
synchronized字符串常量
java·后端·java ee
长谷深风1112 小时前
Tool与Skill:AI能力设计的分水岭
java·人工智能·ai·大模型·aiagent
科技观察哨2 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
m0_587383002 小时前
广州24小时自助健身房解决方案实战指南与系统部署要点
java·spring·小程序·架构·需求分析
Escalating_xu2 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言
niucloud-admin2 小时前
JAVA V6 多商户商城 开发文档——web前端
前端