MyBatisPlus枚举类最佳实践(非常典型和高效的枚举类写法)

博客探讨了MyBatisPlus实现枚举类的最佳实践。介绍了枚举类作用及存在的问题,如数据库存储和JSON序列化问题。详细说明了MyBatisPlus的注解,如@EnumValue、@JsonValue等,还给出完整枚举类示例及讲解,最后总结其可简化枚举使用,让代码更简洁高效。

目录

1、MyBatisPlus枚举类最佳实践

2、枚举类的作用及问题

3、MyBatisPlus注解实现枚举最佳实践

4、简单来说

5、下面我们看一个使用上述注解的完整枚举类示例:

(1)枚举类:

(2)DTO类:

6、根据上面例子进行具体讲解

7、总结


1、MyBatisPlus枚举类最佳实践

在我们的项目中,经常会用到枚举类来定义一些常量状态。但是如果仅仅做简单的枚举,在数据库存储和前端交互时就会出现一些问题。今天就来探讨如何使用MyBatisPlus来实现枚举的最佳实践。

2、枚举类的作用及问题

我们知道,枚举类是一个特殊的类,用于定义常量。在项目中可以用枚举类来代替硬编码的常量,使代码更具可读性。但是简单的枚举类在实际使用中还存在一些问题:

枚举值在数据库中的存储问题。枚举通常用整型值存储,但没有语义

JSON序列化时无法表示枚举值的名称,只返回数字标识

反序列化时无法将数字值转换回对应的枚举对象

3、MyBatisPlus注解实现枚举最佳实践

MyBatisPlus提供了一些注解,可以非常方便地实现枚举类在数据库交互和JSON序列化中的最佳实践,主要包括:

@EnumValue,该注解可以将枚举字段的值转换为数据库存储的值。它会基于枚举的顺序值来映射到数据库中的数字。

@JsonValue,这个注解可以在枚举进行JSON序列化时指定使用枚举值进行转换。这样就可以在JSON中直接看到可读的枚举名称。

@JsonCreator,在反序列化JSON为枚举对象时,@JsonCreator可以把JSON值转换回对应的枚举对象。

of方法配合@JsonCreator注解,我们可以实现一个of方法,在反序列化时把JSON值转换成枚举。

这些注解来自两个依赖:

(1) @JsonValue 和 @JsonCreator 注解来自fasterxml.jackson.annotation包。这需要引入Jackson的依赖:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.4.2</version>
</dependency>

(2) @EnumValue 注解来自com.baomidou.mybatisplus.annotation包。这需要引入MyBatis-Plus的依赖:

<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId> 
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>

4、简单来说

在使用这种标准枚举模式编写业务逻辑时,可以直接通过枚举成员来表示状态,不需要担心底层的 value 或描述信息,使代码更简洁。

枚举类会 handles 序列化和反序列化的过程,确保:

1. 在返回JSON时,自动序列化为 value 或描述信息

2. 在接收前端数据时,自动根据 value 反序列化为枚举成员

3. 在保存到数据库时,自动转换为对应的 value 值

4. 在读取数据库数据时,自动根据 value 转换为枚举成员

所以我们只需要在业务代码中直接使用枚举成员,不需要做任何额外的处理,枚举类会负责与底层值的转换,使业务代码精简和高效。 


5、下面我们看一个使用上述注解的完整枚举类示例:

(1)枚举类:

import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.tianji.common.enums.BaseEnum;
import lombok.Getter;

@Getter //使用@Getter注解自动生成getter方法
public enum SectionType implements BaseEnum { //实现BaseEnum接口,标识这是一个枚举类
    VIDEO(1, "视频"),
    EXAM(2, "考试"),
    ;
    @JsonValue //把value值返回给前端(在JSON序列化时返回value的值)
    @EnumValue //把枚举的value转成数据库需要的
    int value;
    String desc;

    SectionType(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }


    @JsonCreator(mode = JsonCreator.Mode.DELEGATING) //前端提交form表单,of方法:将value转变成对应的枚举
    public static SectionType of(Integer value){
        if (value == null) {
            return null;
        }
        for (SectionType status : values()) {
            if (status.equalsValue(value)) {
                return status;
            }
        }
        return null;
    }
}

(2)DTO类:

当前端form表单提交数据给后端时,其中一个参数是这个枚举类中的枚举值。

此时后端通过DTO类来接收数据,其中定义一个成员属性,举个例子:

@EnumValid 注解来验证枚举值的合法性

@EnumValid 注解的主要参数:

        - enumeration:指定一个合法的枚举值数组,这里是{1, 2},枚举的 value 值
        - message:验证不通过时的错误提示信息

@Data
@ApiModel(description = "学习记录")
public class LearningRecordFormDTO {

    @ApiModelProperty("小节类型:1-视频,2-考试")
    @NotNull(message = "小节类型不能为空")
    @EnumValid(enumeration = {1, 2}, message = "小节类型错误,只能是:1-视频,2-考试")
    private SectionType sectionType;

}

6、根据上面例子进行具体讲解

这是一种典型的枚举类写法,具有以下几个特点:

1. 使用@Getter注解自动生成getter方法

2. 实现BaseEnum接口,标识这是一个枚举类

3. 每个枚举成员都有一个int类型的value字段,表示数据库存储的值

4. 使用@JsonValue注解,在JSON序列化时返回value的值

5. 使用@EnumValue注解,将value值转成数据库字段

6. 提供一个of方法,可以通过value值获取对应的枚举实例

7. of方法使用@JsonCreator注解,允许通过JSON反序列化获取枚举

8. of方法实现通过value值查找枚举实例的逻辑

9. 加入对null值的处理,保证健壮性总体来说,这种枚举类实现了将枚举值与数据库值映射的功能,同时可以方便的进行JSON序列化和反序列化。

10.配合标准枚举类写法,通过 @EnumValid 注解可以非常方便地实现自定义的枚举值验证,提高代码的健壮性。

通过在枚举类上使用以上注解,我们可以非常容易地在数据库存储和JSON序列化中实现枚举的自动转换,大大简化了枚举的使用难度。

7、总结

MyBatisPlus为枚举类的实现提供了非常好的注解支持。上面介绍的这些注解可以帮助我们优雅地解决枚举在数据库和网络传输中的处理问题。在项目中,我们可以根据这种最佳实践来实现枚举,使代码更简洁高效。 

<think>我们之前讨论的是将Java枚举映射到MySQL的INTEGER类型,现在用户明确要求实现数据库ENUM类型(MySQL的ENUM数据类型)与Java枚举的映射。 根据引用[1],MyBatis-Plus提供了@EnumValue注解来处理枚举值与数据库字段的映射。同时,引用[3]提到了自定义TypeHandler,但这里我们需要映射的是数据库的ENUM类型(字符串形式)而不是整数。 注意:数据库的ENUM类型在MySQL中是一种字符串类型,它允许我们在预定义的字符串列表中选择值。例如:ENUM('TYPE_A','TYPE_B')实现步骤: 1. 定义一个枚举类,使用@EnumValue注解标记要存储到数据库的字段(通常是枚举的字符串表示)。 2. 配置MyBatis-Plus使用其内置的枚举处理器(EnumTypeHandler)或者自定义处理器(如果默认行为不满足需求,但通常使用注解即可)。 然而,默认情况下,MyBatis-Plus的枚举处理有两种方式: - 方式一:将枚举的name()作为数据库值(默认行为,对应org.apache.ibatis.type.EnumTypeHandler) - 方式二:将枚举中标记了@EnumValue的字段作为数据库值(对应com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler) 因为我们需要映射到数据库的ENUM类型,所以应该使用方式二,这样数据库存储的是枚举中指定的字符串(与数据库ENUM定义的字符串一致)。 具体步骤: 步骤1:在枚举类中使用@EnumValue注解标记要存储的字段 ```java public enum ProjectTypeEnum { TYPE_A("TYPE_A"), TYPE_B("TYPE_B"); // 使用@EnumValue注解标记这个字段的值将存入数据库 @EnumValue private final String code; ProjectTypeEnum(String code) { this.code = code; } public String getCode() { return code; } } ``` 步骤2:在配置文件中启用MyBatis-Plus的枚举处理 在application.yml(或application.properties)中配置: ```yaml mybatis-plus: configuration: # 开启驼峰命名转换(根据需要) map-underscore-to-camel-case: true # 配置枚举处理,指定使用MybatisEnumTypeHandler(默认就是开启的,但为了明确可以配置) type-enums-package: com.example.core.enums # 扫描枚举的包路径,这样MyBatis-Plus会自动处理这些枚举 ``` 注意:从MyBatis-Plus 3.5.0开始,默认已经启用了对@EnumValue的支持,所以通常不需要额外配置。但为了确保,我们可以检查版本并配置。 步骤3:数据库表字段类型定义为ENUM,并包含枚举中定义的值 例如: ```sql CREATE TABLE project ( id BIGINT PRIMARY KEY, type ENUM('TYPE_A','TYPE_B') NOT NULL COMMENT '项目类型' ); ``` 步骤4:在实体类中直接使用枚举类型 ```java public class Project { private Long id; private ProjectTypeEnum type; // 自动映射 } ``` 这样,当保存实体时,MyBatis-Plus会自动将枚举中标记了@EnumValue的字段值(即code)存入数据库的ENUM字段。查询时,也会自动将数据库的字符串值转换为对应的枚举。 注意事项: 1. 确保枚举中的code值(即@EnumValue标记的字段值)与数据库ENUM定义的值完全一致(包括大小写)。 2. 如果不想配置type-enums-package,也可以通过在实体类字段上直接指定类型处理器(但通常不需要,因为全局配置已经启用): ```java @TableField(typeHandler = MybatisEnumTypeHandler.class) private ProjectTypeEnum type; ``` 3. 如果使用自定义的TypeHandler(如引用[3]所示),那么可以不使用@EnumValue,而是自己在TypeHandler中定义转换逻辑。但在MyBatis-Plus环境下,使用@EnumValue更加简便。 问题:如果数据库ENUM定义的值与枚举的code值不一致怎么办? 解决方案:可以自定义TypeHandler,在TypeHandler中进行转换。例如,数据库存储的是小写,而枚举中定义的是大写,那么可以在TypeHandler中进行大小写转换。 自定义TypeHandler示例(备用方案): ```java public class ProjectTypeEnumTypeHandler implements TypeHandler<ProjectTypeEnum> { @Override public void setParameter(PreparedStatement ps, int i, ProjectTypeEnum parameter, JdbcType jdbcType) throws SQLException { // 将枚举转换为数据库值(这里假设需要小写,但数据库ENUM定义的是小写,而枚举中是大写) if (parameter == null) { ps.setNull(i, Types.VARCHAR); } else { ps.setString(i, parameter.getCode().toLowerCase()); } } @Override public ProjectTypeEnum getResult(ResultSet rs, String columnName) throws SQLException { String code = rs.getString(columnName); return rs.wasNull() ? null : fromDbCode(code); } // 其他方法省略... private ProjectTypeEnum fromDbCode(String dbCode) { // 将数据库的小写值转为大写,然后匹配枚举 for (ProjectTypeEnum e : ProjectTypeEnum.values()) { if (e.getCode().equalsIgnoreCase(dbCode)) { return e; } } throw new IllegalArgumentException("未知的枚举值:" + dbCode); } } ``` 然后在实体类字段上指定: ```java @TableField(typeHandler = ProjectTypeEnumTypeHandler.class) private ProjectTypeEnum type; ``` 但是,如果使用自定义TypeHandler,就不需要@EnumValue注解了。 总结:对于数据库ENUM类型与Java枚举的映射,推荐优先使用MyBatis-Plus的@EnumValue注解方式,因为它简单且无需编写额外代码。只有在需要特殊转换逻辑时才使用自定义TypeHandler。 引用: [1] 中提到了使用@EnumValue注解标记枚举字段作为数据库值。 [3] 中提到了自定义TypeHandler,我们可以参考其写法,但用户的问题更推荐使用注解方式。 因此,回答应重点介绍@EnumValue注解方式,并给出自定义TypeHandler作为备选方案。 </think>### 实现数据库 ENUM 类型与 Java 枚举映射的方法 #### 🌟 推荐方案:使用 MyBatis-Plus 的 `@EnumValue` 注解 这是最简洁高效实现方式,无需编写额外处理器代码: ```java public enum ProjectTypeEnum { TYPE_A("TYPE_A"), TYPE_B("TYPE_B"); @EnumValue // 标记此字段映射到数据库 private final String code; ProjectTypeEnum(String code) { this.code = code; } public String getCode() { return code; } } ``` #### 配置步骤 1. **实体类声明** ```java public class Project { private Long id; private ProjectTypeEnum type; // 自动识别枚举映射 } ``` 2. **MySQL 建表语句** ```sql CREATE TABLE project ( id BIGINT PRIMARY KEY, type ENUM('TYPE_A', 'TYPE_B') NOT NULL COMMENT '项目类型' ); ``` 3. **配置文件启用枚举支持 (`application.yml`)** ```yaml mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler ``` #### ️ 关键注意事项 1. **值一致性** 确保枚举的 `code` 值(如 `"TYPE_A"`)与数据库 ENUM 定义完全匹配(包括大小写) 2. **版本兼容性** 需 MyBatis-Plus 3.5.0+ 版本支持完整枚举功能 3. **空值处理** 数据库 ENUM 字段需设置为 `NOT NULL` 或实体类使用包装类型: ```java private ProjectTypeEnum type; // 允许NULL ``` #### 🔧 备用方案:自定义 TypeHandler 当需要特殊转换逻辑时(如大小写转换),可创建自定义处理器: ```java public class EnumTypeHandler implements TypeHandler<ProjectTypeEnum> { @Override public void setParameter(PreparedStatement ps, int i, ProjectTypeEnum parameter, JdbcType jdbcType) { ps.setString(i, parameter.getCode().toLowerCase()); // 自定义转换 } @Override public ProjectTypeEnum getResult(ResultSet rs, String col) { String dbValue = rs.getString(col); return Arrays.stream(ProjectTypeEnum.values()) .filter(e -> e.getCode().equalsIgnoreCase(dbValue)) .findFirst().orElse(null); } } ``` 实体类配置: ```java public class Project { @TableField(typeHandler = EnumTypeHandler.class) private ProjectTypeEnum type; } ``` #### 🔄 映射机制对比 | **方案** | 优点 | 适用场景 | |----------------------|------------------------------|-------------------------| | `@EnumValue`注解 | 零编码,自动映射 | 枚举值与ENUM定义完全一致 | | 自定义TypeHandler | 可处理特殊转换逻辑 | 值存在大小写/格式差异时 | | MyBatis默认映射 | 无需配置 | 需直接存储枚举名称(name()) | > 💡 最佳实践提示: > 优先使用 `@EnumValue` 方案,仅当需要值转换时采用自定义 TypeHandler。确保数据库 ENUM 定义与 Java 枚举值保持同步修改[^1][^3]。 --- ### 🔍 相关问题 1. 如何处理 Java 枚举数据库 ENUM 值的大小写不一致问题? 2. MyBatis-Plus 的 `@EnumValue` 注解支持哪些数据库类型? 3. 如何实现数据库 ENUM 类型的默认值映射到 Java 枚举? 4. 当数据库新增 ENUM 值时,如何保证 Java 枚举的向后兼容性? [^1]: 在枚举类中使用 `@EnumValue` 标记映射字段 [^3]: 自定义枚举处理器实现值转换逻辑
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值