前后端数据传输: 利用 Jackson 注解实现 Enum 与 int 的双向映射

前后端交互:如何优雅处理 Java 枚举与 JSON 数字的自动转换?

在 Java 后端开发中,我们经常面临一个"数据格式不匹配"的通用问题:

  • 数据库/前端 :倾向于使用 int(如 1, 0)或 String 类型的状态码,因为它们传输快、存储小。
  • 后端代码 :倾向于使用 Enum(枚举),因为枚举具备强类型约束,能避免"魔法数字"(Magic Number),提高代码可读性。

如果直接返回枚举,默认会输出枚举的英文名称(如 "ENABLE");如果前端传数字 1,后端默认又无法自动转成枚举对象。

本文将介绍如何利用 Jackson(Spring Boot 默认的 JSON 框架)的两个核心注解 @JsonValue 和 @JsonCreator,实现枚举对象 与JSON数值的无缝双向转换。

1. 场景复现:最简状态枚举

我们以最基础的"通用状态"为例。假设我们定义了一个包含 code 属性的枚举:

java 复制代码
package com.example.enums;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

public enum CommonStatus {
    
    DISABLE(0, "禁用"),
    ENABLE(1, "启用");

    private final int code;
    private final String desc;

    CommonStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    // ... 下面是核心代码 ...
}

2. 知识点详解

2.1 序列化难题:如何让 Enum 变成 int?

问题 :默认情况下,CommonStatus.ENABLE 序列化成 JSON 是 "ENABLE"。但前端往往需要数字 1。

解决方案 :使用 @JsonValue。

原理:该注解标记的方法,其返回值将作为整个对象序列化后的结果。

java 复制代码
    /**
     * 序列化 (Java -> JSON)
     * 标记此方法后,Jackson 会将枚举序列化为 code 的值 (0 或 1)
     * 而不是枚举的名字 ("DISABLE" 或 "ENABLE")
     */
    @JsonValue
    public int getCode() {
        return code;
    }

2.2 反序列化难题:如何让 int/String 变成 Enum?

问题 :前端传 JSON {"status": 1} 或 {"status": "1"}。Jackson 默认是按照枚举的"名字"去匹配的,找不到名字叫 "1" 的枚举项,就会报错。

解决方案 :使用 @JsonCreator。

原理 :该注解标记的静态方法(Static Method)将作为对象的"构造工厂"。Jackson 会把 JSON 中的值传给这个方法,由开发者自定义逻辑返回对应的枚举对象。

java 复制代码
    /**
     * 反序列化 (JSON -> Java)
     * 静态工厂方法:自定义解析逻辑
     * 
     * 技巧:参数使用 String 类型,可以同时兼容前端传 Number(1) 和 String("1")
     */
    @JsonCreator
    public static CommonStatus fromCode(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }

        try {
            // 1. 将输入值转为 int
            int targetCode = Integer.parseInt(value);

            // 2. 遍历枚举找到匹配的 code
            for (CommonStatus status : CommonStatus.values()) {
                if (status.code == targetCode) {
                    return status;
                }
            }
        } catch (NumberFormatException e) {
            // 非数字字符串处理
        }

        // 3. 找不到匹配项,抛出异常提示参数错误
        throw new IllegalArgumentException("Invalid status code: " + value);
    }

3. 为什么这么做?(总结)

通过这两个注解的组合,我们达成了以下效果:

  1. 对外(前端/数据库) :接口表现为简单的数字(Integer),符合通用的接口规范,传输效率高。
  2. 对内(Java逻辑) :代码中完全使用枚举对象,享受强类型检查、switch-case 支持和方法封装的优势。
  3. 鲁棒性 :在 fromCode 方法中,我们兼容了字符串和数字的输入,极大地提高了接口的容错能力。
相关推荐
猿究院_夏燊4 小时前
Spring Bean 生命周期
java·后端·spring
Wang's Blog5 小时前
Java 项目实战: 交友项目:登录链路回顾与今日任务地图
java·开发语言·状态模式·交友
信誓旦旦的程序猿5 小时前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
砚底藏山河5 小时前
python量化:行情数据回溯
java·开发语言·python·金融·maven
Jlzn88886 小时前
华东电芯分选通道数怎么配才不堵线
java·人工智能·架构·自动化·制造
香吧香6 小时前
GRPC连接机制---长连接分析
java·网络与传输协议
CCblandy6 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
我是人✓6 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 阿里云 OSS 入门案例:从创建 Bucket 到上传拿到可访问 URL
java·阿里云·交友
裕晟资质规划8 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全