mybatis 枚举自动转换

本文介绍了如何在SpringBoot项目中实现MyBatis的枚举自动转换,以解决字段存储枚举值的问题。通过自定义AutoEnumTypeHandler类继承BaseTypeHandler,并使用@EnumTransfer注解,实现在保存和查询时自动转换枚举。详细讲解了转换的原理,包括写入时获取枚举入库值和查询时反射枚举方法。同时,强调了在数据库对枚举入库没有特定要求时,可不使用转换直接保存枚举的name。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

目前公司的一个SpringBoot项目,有一张表的一个字段需要存储枚举,之前保存的一直是枚举的code值,导致实体类的该属性是int类型,而不是枚举类型。技术领导希望我能解决这个问题,思路很简单,从网上找一下 “mybatis枚举自动转换”,应该不难。

结果:

但是看过大部分文章后,发现在 通用的自动转换 时,有点麻烦,大部分都建议枚举实现一个接口或在转换类中表明转换哪些枚举。经常仔细查看代码,根据我们项目的实际情况。编写出 枚举通用转换类,仅供参考。

废话不多说,直接上代码:

AutoEnumTypeHandler.class

package com.founderbn.common.mybatis.typeHandler;

import com.founderbn.common.mybatis.constants.EnumTransfer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class AutoEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
    private Class<E> type;

    public AutoEnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        } else {
            EnumTransfer transfer = (EnumTransfer)type.getAnnotation(EnumTransfer.class);
            if (transfer == null) {
                throw new RuntimeException(type.getSimpleName() + " 没有使用@EnumTransfer ,不明确转换方式");
            } else {
                this.type = type;
            }
        }
    }

    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        EnumTransfer transfer = (EnumTransfer)this.type.getAnnotation(EnumTransfer.class);
        String value = transfer.value();
        value = value.substring(0, 1).toUpperCase() + value.substring(1);

        try {
            Method method = this.type.getMethod("get" + value);
            ps.setObject(i, method.invoke(parameter));
        } catch (Exception var8) {
            throw new RuntimeException("AutoEnumTypeHandler 转换枚举时,异常,请检查 EnumTransfer的value ", var8);
        }
    }

    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        int code = rs.getInt(columnName);
        return rs.wasNull() ? null : this.codeOf(code);
    }

    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        int code = rs.getInt(columnIndex);
        return rs.wasNull() ? null : this.codeOf(code);
    }

    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int code = cs.getInt(columnIndex);
        return cs.wasNull() ? null : this.codeOf(code);
    }

    private E codeOf(int code) {
        try {
            return this.codeOf(this.type, code);
        } catch (Exception var3) {
            throw new IllegalArgumentException("Cannot convert " + code + " to " + this.type.getSimpleName() + " by code value.", var3);
        }
    }

    public <E extends Enum<?>> E codeOf(Class<E> enumClass, int code) {
        EnumTransfer transfer = (EnumTransfer)this.type.getAnnotation(EnumTransfer.class);
        String value = transfer.value();
        value = value.substring(0, 1).toUpperCase() + value.substring(1);
        E[] enumConstants = (Enum[])enumClass.getEnumConstants();
        Enum[] arr$ = enumConstants;
        int len$ = enumConstants.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            Enum e = arr$[i$];

            try {
                Method method = e.getClass().getMethod("get" + value);

                try {
                    if (method.invoke(e).equals(code)) {
                        return e;
                    }
                } catch (IllegalAccessException var12) {
                    var12.printStackTrace();
                } catch (InvocationTargetException var13) {
                    var13.printStackTrace();
                }
            } catch (NoSuchMethodException var14) {
                throw new RuntimeException(this.type.getSimpleName() + " 方法没有get" + value + "() 方法");
            }
        }

        return null;
    }
}

@EnumTransfer 注解

@Retention(RetentionPolicy.RUNTIME)
public @interface EnumTransfer {
    String value() default "id";
}


原理:

1.AutoEnumTypeHandler.class 继承mybatis的 BaseTypeHandler类,重写方法。

2.在"写入"setNonNullParameter 方法内,通过注解的方式,获取到枚举想要入库的值

3.在 "查询"getNullableResult方法内,通过数据库值,反射枚举方法得到枚举值

整理思路还是很简单的,如果项目在定义枚举时,有一定的规范,可以更加简单些,不过我写的这个反射获取方法更加灵活,可以不同的枚举,选择入库id,code,name...自由选择。

ps:如果数据库对枚举入库没有要求,也可以不使用枚举转换方法,默认入库保存枚举的name,灵活变通。


springboot在使用该枚举工具栏时,需显示说明:


枚举:

@EnumTransfer
public enum Status {
    STAUTS_ENABLE(1, "启用", "enable"),
    STAUTS_DISABLE(2, "停用", "disable");

    private int id;
    private String name;
    private String enname;

    public int getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public String getEnname() {
        return this.enname;
    }

    private Status(int id, String name, String enname) {
        this.id = id;
        this.name = name;
        this.enname = enname;
    }

    public static Status getById(int id) {
        switch(id) {
        case 1:
            return STAUTS_ENABLE;
        case 2:
            return STAUTS_DISABLE;
        default:
            return null;
        }
    }
}

显示说明引用:

@Bean(name = "sqlSessionFactory")
	public SqlSessionFactory sqlSessionFactoryBean() throws Exception{
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource);
		//配置信息在application.yml
		bean.setTypeAliasesPackage(environment.getProperty("mybatis.typeAliasesPackage"));

		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

		// 添加XML目录
		bean.setMapperLocations(resolver.getResources(environment.getProperty("mybatis.mapperLocations")));

		SqlSessionFactory sqlSessionFactory = bean.getObject();
		// 取得类型转换注册器
		TypeHandlerRegistry typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
		// 注册默认枚举转换器
		typeHandlerRegistry.register(Status.class,AutoEnumTypeHandler.class);

		return sqlSessionFactory;

	}


参考资料: mybatis枚举自动转换,主要是在他的基础上,改动的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值