前后端数据传输: 利用 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 方法中,我们兼容了字符串和数字的输入,极大地提高了接口的容错能力。
相关推荐
神奇的程序员3 小时前
从已损坏的备份中拯救数据
运维·后端·前端工程化
Goldn.4 小时前
Java核心技术栈全景解析:从Web开发到AI融合
java· spring boot· 微服务· ai· jvm· maven· hibernate
oden4 小时前
AI服务商切换太麻烦?一个AI Gateway搞定监控、缓存和故障转移(成本降40%)
后端·openai·api
李慕婉学姐5 小时前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
m0_740043735 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
编织幻境的妖5 小时前
SQL查询连续登录用户方法详解
java·数据库·sql
未若君雅裁5 小时前
JVM面试篇总结
java·jvm·面试
kk哥88996 小时前
C++ 对象 核心介绍
java·jvm·c++
招风的黑耳6 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
xunyan62346 小时前
面向对象(下)-接口的理解
java·开发语言