MyBatis-Plus11:枚举处理器

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 或者 "正常" 都能正确匹配。

相关推荐
ruleslol1 天前
MyBatis-Plus12:JSON处理器
mybatis-plus
ruleslol1 天前
MyBatis-Plus13:自定义 TypeHandler
mybatis-plus
ruleslol3 天前
MyBatis-Plus07:rewriteBatchedStatements 参数详解与批处理
mybatis-plus
ruleslol3 天前
MyBatis-Plus08:代码生成
mybatis-plus
ruleslol3 天前
MyBatis-Plus09:静态工具Db
mybatis-plus
树码小子3 天前
Mybatis(17)Mybatis-Plus条件构造器(2)& 自定义 SQL
数据库·sql·mybatis-plus
ruleslol3 天前
MyBatis-Plus10:逻辑删除
mybatis-plus
树码小子4 天前
Mybatis(16)Mybatis-Plus条件构造器(1)
数据库·mybatis-plus
树码小子5 天前
Mybatis(14)Mybatis-Plus入门 & 简单使用
java·mybatis-plus