MyBatis 原生仅提供2 种基础枚举处理器,无法满足业务中存储枚举编码 / 自定义值的核心需求:
EnumOrdinalTypeHandler:基于枚举 ordinal()(定义顺序:0、1、2...)映射,枚举顺序变更会导致数据错乱;
EnumTypeHandler:基于枚举 name()(常量名称:PRIMARY、SECONDARY)映射,存储冗余、可读性差。
MyBatis-Plus 最优解决方案
提供 MybatisEnumTypeHandler(基于枚举自定义属性自动映射),核心规则:
标记过的枚举 → 自动使用该处理器,映射自定义属性值;
未标记的枚举 → 沿用 MyBatis 全局默认枚举处理器(默认 EnumTypeHandler);
全局配置仅对未标记枚举生效,不影响已标记枚举。
2 选 1,零配置自动映射
MyBatis-Plus 提供 注解 和 接口 两种标记方式,指定数据库存储的枚举值。
@EnumValue 注解(推荐,极简)
作用:直接标记枚举字段为 数据库存储值,支持 Integer/String/Byte 任意类型; 核心注解:com.baomidou.mybatisplus.annotation.EnumValue。
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum GradeEnum {
PRIMARY(1, "小学"),
SECONDARY(2, "中学"), // 修正原拼写错误:SECONDORY
HIGH(3, "高中");
// 标记:数据库仅存储该字段的值
@EnumValue
private final Integer code;
// 业务描述(仅业务使用,不入库)
private final String desc;
}实现 IEnum 接口(通用适配)
作用:实现 MP 标准接口,重写方法指定数据库存储值,适配框架集成场景; 核心接口:com.baomidou.mybatisplus.annotation.IEnum。
import com.baomidou.mybatisplus.annotation.IEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
// 泛型:指定数据库存储值的类型
public enum AgeEnum implements IEnum<Integer> {
ONE(1, "一岁"),
TWO(2, "二岁"),
THREE(3, "三岁");
private final Integer value;
private final String desc;
// 重写方法:返回数据库存储的值
@Override
public Integer getValue() {
return this.value;
}
}直接声明枚举类型,无需手动配置 typeHandler,MP 自动完成映射:
import lombok.Data;
@Data
public class User {
private String name; // 姓名
private AgeEnum age; // 年龄(接口标记枚举)
private GradeEnum grade; // 年级(注解标记枚举)
}全局默认处理器配置
对于 未加注解 / 未实现接口 的枚举,可自定义全局默认处理器,不影响已标记枚举。
mybatis-plus:
configuration:
# 全局默认枚举处理器(默认:EnumTypeHandler)
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandlerimport com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
import org.apache.ibatis.type.EnumOrdinalTypeHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer() {
return properties -> {
var coreConfig = new com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties.CoreConfiguration();
// 设置全局默认枚举处理器
coreConfig.setDefaultEnumTypeHandler(EnumOrdinalTypeHandler.class);
properties.setConfiguration(coreConfig);
// 关闭 MP 启动 banner(可选)
properties.getGlobalConfig().setBanner(false);
};
}
}自动映射机制
MyBatis-Plus 会自动扫描项目中标记的枚举,自动注册 MybatisEnumTypeHandler,你无需:
在 resultMap 中手动指定 typeHandler;
在实体字段上加 @TableField(typeHandler = xxx.class);
手动注册类型处理器。
真正实现 零配置、自动映射。
数据库存储枚举编码,接口需返回编码而非枚举名称,适配主流序列化框架。
双注解共用(统一数据库 + 接口值)
一个字段同时标记 数据库存储 和 接口返回,极简无冗余:
@EnumValue // 数据库存 code
@JsonValue // Jackson 序列化返回 code
private final Integer code;无需全局配置,仅用 @JsonValue 即可实现 序列化 + 反序列化(前端传 code → 后端自动转枚举)。
备选:全局 toString 配置
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
}
}配合枚举重写 toString():
@Override
public String toString() {
return String.valueOf(this.code);
}引入依赖
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.46+</version>
</dependency>全局配置
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
@Configuration
public class Fastjson2Config {
@Bean
public HttpMessageConverter<?> fastJsonConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
converter.getFastJsonConfig().setWriterFeatures(JSONWriter.Feature.WriteEnumUsingToString);
return converter;
}
}import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {}import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class EnumTest {
@Autowired
private UserMapper userMapper;
// 插入:枚举自动转为 code 存入数据库
@Test
void insert() {
User user = new User();
user.setName("张三");
user.setAge(AgeEnum.TWO); // 入库:2
user.setGrade(GradeEnum.PRIMARY); // 入库:1
userMapper.insert(user);
}
// 查询:数据库 code 自动转为枚举对象
@Test
void select() {
User user = userMapper.selectById(1);
System.out.println(user.getAge()); // AgeEnum.TWO
System.out.println(user.getGrade()); // GradeEnum.PRIMARY
}
}