通用枚举转换的实现 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 
// 例如:
// 
public class DefaultEnumTypeHandler extends BaseTypeHandler {

    private Class type;

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

    public DefaultEnumTypeHandler(Class 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 {

    private Class type;

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

    public DefaultStringEnumTypeHandler(Class 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;

通用枚举转换的实现 BaseTypeHandler、@MappedTypes背后的执行逻辑-ibatis_第1张图片 

 

实体类使用具体枚举类

仅关注红色内容即可

通用枚举转换的实现 BaseTypeHandler、@MappedTypes背后的执行逻辑-ibatis_第2张图片

 Mapper配置

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




    
        
        
        
        
        
    
    
    
        id, role_name, enabled , create_by, create_time
    

    
    
        insert into sys_role
        
            
                role_name,
            
            
                enabled,
            
            
                create_by,
            
            
                create_time,
            
        
        
            
                #{roleName,jdbcType=VARCHAR},
            
            
                #{enabled,jdbcType=INTEGER},
            
            
                #{createBy,jdbcType=BIGINT},
            
            
                #{createTime,jdbcType=TIMESTAMP},
            
        
    

MyBatis-config 配置




    
        
        
        
        
    

    
        
        
        
        
        
    

效果演示

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);
    }

通用枚举转换的实现 BaseTypeHandler、@MappedTypes背后的执行逻辑-ibatis_第3张图片

 测试查询

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

通用枚举转换的实现 BaseTypeHandler、@MappedTypes背后的执行逻辑-ibatis_第4张图片

 

你可能感兴趣的:(数据库,sql,mybatis)