MyBatis-Plus 提供了枚举处理器,让我们可以优雅地在数据库字段和 Java 枚举之间进行转换,而不需要手动处理映射关系。
一、为什么需要枚举处理器?
数据库中通常用 0/1 或 'A'/'B' 这样的值表示状态,而 Java 中我们希望使用枚举类型。没有枚举处理器时,需要手动转换,容易出错且代码冗余。
二、实现方式
在枚举字段上加
@EnumValue,标记哪个字段的值存入数据库:
示例:


【备注】:
类型处理器多是由mybatis提供;
但是mybatis-plus在此基础上,添加了两个常用的类型处理器
2-1、实现步骤
1、通过注解@EnumValue,告诉mp,枚举中的哪一个字段作为数据库中的存值

2、通过配置项,让枚举处理器生效

3、对于枚举的返回值,由springMVC中的Jackson json处理,通过注解@JsonValue,标记返回枚举中的哪一个值。

2-2、小结:

三、反序列化时(接收前端参数),配合 @JsonCreator
前端传来 JSON 数据 → Java 把它转换成对象,这个过程会遇到坑!
若是枚举示例如下:

按照当前逻辑,当传值是desc字符串时:
{
"username":"商丛书6",
"email":"shang@qq.com",
"age":22,
"status":"冻结"
}

数据库存值没有问题。
但是当传值是value时:
{
"username":"商丛书7",
"email":"shang@qq.com",
"age":22,
"status":1
}
存值有误:

原因:
因为 Jackson 默认支持按枚举的 ordinal(下标顺序)来反序列化,而不是你 @EnumValue 定义的 code 值:
java
public enum UserStatus {
NORMAL(1, "正常"), // ordinal=0,code=1
FROZEN(-1, "冻结"); // ordinal=1,code=0
}
整个链路:
Postman 传 "冻结"
↓ Jackson 反序列化(@JsonValue 的 desc 字段匹配)
UserStatus.NORMAL 枚举对象
↓ MyBatis-Plus 写库(@EnumValue 的 value 字段)
数据库存 -1
java
Postman 传 1
↓ Jackson 按 ordinal 匹配(第1个枚举)
UserStatus.FROZEN 枚举对象
↓ MyBatis-Plus 写库
数据库存 -1
3-1、解决方法: @JsonCreator
在枚举里加 @JsonCreator 方法,根据你想支持的传值方式来写。
@JsonCreator 是加在枚举类里的一个静态方法上,这个方法你自己来写:
java
@Getter
public enum UserStatus {
NORMAL(1, "正常"),
FROZEN(-1, "冻结");
@EnumValue
private int value;
@JsonValue
private String desc;
UserStatus(int value, String desc) {
this.value = value;
this.desc = desc;
}
@JsonCreator
public static UserStatus of(int value){
for (UserStatus e : values()){
if(value == e.value){
return e;
}
}
throw new IllegalArgumentException("无效的状态值: " + value);
}
}
这样前端传 "status": 1 时,Jackson 就会调用这个 of(1) 方法,按 value 字段去匹配枚举,而不是按 ordinal 顺序,避免了之前说的那个坑。
【注意】:方法名不一定叫of!!!
名字随便起,@JsonCreator 才是关键,Jackson 认的是这个注解,不是方法名。
叫什么都行:
java
@JsonCreator
public static UserStatus fromCode(int code) { ... }
@JsonCreator
public static UserStatus getByCode(int code) { ... }
@JsonCreator
public static UserStatus create(int code) { ... }
of 只是一个约定俗成的命名习惯,参考了 Java 标准库的风格(比如 Optional.of()、LocalDate.of() 等),看起来简洁,但并不是强制要求。
一个枚举里只能有一个 @JsonCreator 方法,因为 Jackson 反序列化时只能有一个入口,多了它不知道该用哪个,会报错。
如果你想同时支持数字和字符串,就在这一个方法里做兼容处理:
java
@JsonCreator
public static UserStatus of(Object val) {
String str = val.toString().trim();
for (UserStatus e : values()) {
// 既能匹配 code(数字),也能匹配 desc(中文)
if (String.valueOf(e.code).equals(str) || e.desc.equals(str)) {
return e;
}
}
throw new IllegalArgumentException("无效的状态值: " + val);
}
这样前端传 0 或者 "正常" 都能正确匹配。