通用枚举转换的实现 BaseTypeHandler、@MappedTypes背后的执行逻辑-ibatis

SQL

create table sys_role
(
    id          bigint auto_increment comment '角色ID'
        primary key,
    role_name   varchar(50) null comment '角色名',
    enabled     int         null comment '有效标志',
    create_by   bigint      null comment '创建人',
    create_time datetime    null comment '创建时间'
)
    comment '角色表' charset = utf8;

枚举规范接口

JDBC数字转JavaType的字符串接口

/**
 *  枚举应该包含 属性 Integer value 、String label;
 */
public interface BaseIntDBEnum {
    Integer getValue();

    String getLabel();

    String toString();
}

JDBC字符串转JavaType的字符串接口

/**
 *  枚举应该包含 属性 Integer value 、String label;
 */
public interface BaseStringDBEnum {
    String getValue();

    String getLabel();

    String toString();
}

枚举具体类

public enum SysRoleUserTypeEnum implements BaseStringDBEnum {
    ONE("admin", "管理员"),
    TWO("user", "普通用户");

    String value;

    String label;

    SysRoleUserTypeEnum(String value, String label) {
        this.value = value;
        this.label = label;
    }

    @Override
    public String getValue() {
        return value;
    }

    @Override
    public String getLabel() {
        return label;
    }
    // 必须添加
    @Override
    public String toString() {
        return label;
    }
}
public enum SysRoleIDDBEnum implements BaseIntDBEnum {

    FIRST(1, "第一名"),
    SECOND(2, "第二名"),
    THREE(3, "第三名");


    Integer value;

    String label;

    public Integer getValue() {
        return value;
    }

    public String getLabel() {
        return label;
    }

    SysRoleIDDBEnum(Integer value, String label) {
        this.value = value;
        this.label = label;
    }

    /**
     * 因为 TypeHandler 的三个 get 方法返回值是 BaseIntDBEnum
     * 如果不重新 toString 方法。则展示值 为 Enum 的 name(DISABLE、ENABLE)
     *
     * @return 禁用\启用
     */
    @Override
    public String toString() {
        return label;
    }
}
public enum SysRoleIntDBEnum implements BaseIntDBEnum {
    /**
     * 0-立即发布、1-定时发布
     */

    DISABLE(0, "禁用"),
    ENABLE(1, "启用");

    Integer value;

    String label;

    public Integer getValue() {
        return value;
    }

    public String getLabel() {
        return label;
    }

    SysRoleIntDBEnum(Integer value, String label) {
        this.value = value;
        this.label = label;
    }

    /**
     * 因为 TypeHandler 的三个 get 方法返回值是 BaseIntDBEnum
     * 如果不重新 toString 方法。则展示值 为 Enum 的 name(DISABLE、ENABLE)
     *
     * @return 禁用\启用
     */
    @Override
    public String toString() {
        return label;
    }
}

添加对应的TypeHandler

JDBC数字 与 JavaType的字符串处理的TypeHandler

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// 规范应该写 @MappedJdbcTypes
//@MappedJdbcTypes(value = JdbcType.TINYINT, includeNullJdbcType = true)
@MappedTypes(value = {SysRoleIntDBEnum.class ,SysRoleIDDBEnum.class})
// 实现DisplayedEnum 都需要写进去
// MyBatis 会扫描 @MappedTypes 的所有value 并生成 一对一的 DefaultEnumTypeHandler 
// 例如:<typeHandler handler="EnableTypeHandler" javaType="SysRoleIntDBEnum"/>
// <typeHandler handler="EnableTypeHandler" javaType="SysRoleIDDBEnum"/>
public class DefaultEnumTypeHandler extends BaseTypeHandler<BaseIntDBEnum> {

    private Class<BaseIntDBEnum> type;

    public DefaultEnumTypeHandler() {
        System.out.println("init DefaultEnumTypeHandler no args");
        this.type = BaseIntDBEnum.class;
    }

    public DefaultEnumTypeHandler(Class<BaseIntDBEnum> type) {
        System.out.println("init DefaultEnumTypeHandler with args");
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, BaseIntDBEnum parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, parameter.getValue());
    }

    @Override
    public BaseIntDBEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convert(rs.getInt(columnName));
    }

    @Override
    public BaseIntDBEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convert(rs.getInt(columnIndex));
    }

    @Override
    public BaseIntDBEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convert(cs.getInt(columnIndex));
    }

    private BaseIntDBEnum convert(int status) {
        BaseIntDBEnum[] objs = type.getEnumConstants();
        for (BaseIntDBEnum em : objs) {
            if (em.getValue() == status) {
                return em;
            }
        }
        return null;
    }
}

 JDBC字符串 与 JavaType的字符串处理的TypeHandler

@MappedTypes({SysRoleUserTypeEnum.class})
public class DefaultStringEnumTypeHandler extends BaseTypeHandler<BaseStringDBEnum> {

    private Class<BaseStringDBEnum> type;

    public DefaultStringEnumTypeHandler() {
        System.out.println("init DefaultStringEnumTypeHandler no args");
        this.type = BaseStringDBEnum.class;
    }

    public DefaultStringEnumTypeHandler(Class<BaseStringDBEnum> type) {
        System.out.println("init DefaultStringEnumTypeHandler with args");
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, BaseStringDBEnum parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.getValue());
    }

    @Override
    public BaseStringDBEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convert(rs.getString(columnName));
    }

    @Override
    public BaseStringDBEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convert(rs.getString(columnIndex));
    }

    @Override
    public BaseStringDBEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convert(cs.getString(columnIndex));
    }

    private BaseStringDBEnum convert(String value) {
        BaseStringDBEnum[] enumConstants = type.getEnumConstants();
        for (BaseStringDBEnum dbEnum : enumConstants) {
            if (dbEnum.getValue() == value) {
                return dbEnum;
            }
        }
        return null;
    }
}

@MappedTypes 的作用

在扫描所有的typehandler:1.查看类上是否标注有注解;2.若标有注解则循环注册typehandler;3.循环注册即通过有参构造创建对象,参数是 @MappedTypes 的 value

2.如果没有标注@MappedTypes则使用 typehandler的无参数的构造方法创建typehandler;

 

 

实体类使用具体枚举类

仅关注红色内容即可

 Mapper配置

此处未具体配置要使用的typehangdler

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tk.mybatis.simple.mapper.SysRoleMapper">
    <resultMap id="BaseResultMap" type="tk.mybatis.simple.model.SysRole">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
        <result column="enabled" jdbcType="INTEGER" property="enabled" />
        <result column="create_by" jdbcType="BIGINT" property="createBy"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    </resultMap>
    
    <sql id="Base_Column_List">
        id, role_name, enabled , create_by, create_time
    </sql>

    <select id="selectByPrimaryKey" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from sys_role
        where id = #{id,jdbcType=BIGINT}
    </select>
    <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="tk.mybatis.simple.model.SysRole"
            useGeneratedKeys="true">
        insert into sys_role
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="roleName != null">
                role_name,
            </if>
            <if test="enabled != null">
                enabled,
            </if>
            <if test="createBy != null">
                create_by,
            </if>
            <if test="createTime != null">
                create_time,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="roleName != null">
                #{roleName,jdbcType=VARCHAR},
            </if>
            <if test="enabled != null">
                #{enabled,jdbcType=INTEGER},
            </if>
            <if test="createBy != null">
                #{createBy,jdbcType=BIGINT},
            </if>
            <if test="createTime != null">
                #{createTime,jdbcType=TIMESTAMP},
            </if>
        </trim>
    </insert>
</mapper>

MyBatis-config 配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- logImpl 属性配置指定使用 LOG4J 输出日志 -->
        <setting name="logImpl" value="LOG4J"/>
        <!--指定 Enum 使用的默认 TypeHandler (新增于 3.4.5)-->
        <!-- <setting name="defaultEnumTypeHandler"  value="**TypeHandler"/>-->
    </settings>

    <typeHandlers>
        <!-- 这里配置的话在 xml 遇到对应了类型会自动使用 TypeHandler --》
        <!-- 此处未指明要处理的JavaType是什么,使用为两个TypeHandler 处理的是 一类(多种数据)无法指定到一种数据类型-->
        <typeHandler handler="tk.mybatis.simple.type.DefaultEnumTypeHandler" />
        <typeHandler handler="tk.mybatis.simple.type.DefaultStringEnumTypeHandler" />
        <!--使用该注解可以指定(package 应放在 typeHandler的后面)-->
        <!-- <package name="tk.mybatis.simple.type"/> -->
    </typeHandlers>

</configuration>

效果演示

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;

import java.io.IOException;
import java.io.Reader;

// 基础测试类
public class BaseMapperTest {
    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init() {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }

    public SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }


}

测试添加 

    @Test
    public void testInsertSelective(){
        SqlSession sqlSession = getSqlSession();
        SysRoleMapper sysRoleMapper = sqlSession.getMapper(SysRoleMapper.class);
        SysRole record = new SysRole();
        record.setEnabled(SysRoleIntDBEnum.ENABLE);
        int i = sysRoleMapper.insertSelective(record);
        System.out.println(i);
    }

 测试查询

    @Test
    public void testSelectByPrimaryKey() {
        SqlSession sqlSession = getSqlSession();
        SysRoleMapper sysRoleMapper = sqlSession.getMapper(SysRoleMapper.class);
        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(1L);
        System.out.println(sysRole);
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值