前后端交互:如何优雅处理 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. 为什么这么做?(总结)
通过这两个注解的组合,我们达成了以下效果:
- 对外(前端/数据库) :接口表现为简单的数字(Integer),符合通用的接口规范,传输效率高。
- 对内(Java逻辑) :代码中完全使用枚举对象,享受强类型检查、switch-case 支持和方法封装的优势。
- 鲁棒性 :在
fromCode方法中,我们兼容了字符串和数字的输入,极大地提高了接口的容错能力。