类型处理器(TypeHandler)

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

通过类型处理器(TypeHandler),可以实现javaBean以某种方式存入数据库中,抑或是从数据库取出的数据如何映射为javaBean。

通过继承BaseTypeHandler类,我们可以定制这个类型处理器,已实现枚举类或是一个javaBean的存取和写入。

内置的枚举处理器

mybatis内置了两个枚举类型处理器,EnumTypeHandler和EnumOrdinalTypeHandler,这两个类型都不好用,一般也是我们自己实现枚举的类型处理器。

EnumTypeHandler存入数据库的是枚举的name,EnumOrdinalTypeHandler存入数据库的是枚举的位置。例如下方的枚举,当我们有一个枚举值是EStatus.init时,这时我们使用mybatis的EnumTypeHandler存入数据库的是"init"字符串;而EnumOrdinalTypeHandler存入的是3,因为init是第四个值,第一个值disable的index是0。

public enum EStatus {

    disable("0"), enable("1"), deleted("2"),
init("10"), start("11"), wait("12"), end("13");
}

EnumTypeHandler源码

public class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
private final Class<E> type; //采用父类的构造方法,会获取到注解MappedTypes中的value,作为type
public EnumTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
} else {
this.type = type;
}
} //写入数据库时调用
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
if (jdbcType == null) {
ps.setString(i, parameter.name());
} else {
ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE);
} } //以下三个方法是在存入时候调用,一个是根据列名获取值,一个是根据列索引位置获取值,最后一个是存储过程。
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
String s = rs.getString(columnName);
return s == null ? null : Enum.valueOf(this.type, s);
} public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String s = rs.getString(columnIndex);
return s == null ? null : Enum.valueOf(this.type, s);
} public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String s = cs.getString(columnIndex);
return s == null ? null : Enum.valueOf(this.type, s);
}
}

自定义枚举类处理

1、实现BaseTypeHandler接口,重写方法


public class GenderHandler extends BaseTypeHandler<Gender> { @Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Gender gender, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, gender.getCode());
} @Override
public Gender getNullableResult(ResultSet resultSet, String s) throws SQLException {
return Gender.getGender(resultSet.getString(s));
} @Override
public Gender getNullableResult(ResultSet resultSet, int i) throws SQLException {
return Gender.getGender(resultSet.getString(i));
} @Override
public Gender getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return Gender.getGender(callableStatement.getString(i));
} }

2、在application.yml中加入配置,扫描handler组件

mybatis:
# 配置mybatis的resultType别名,默认是别名为小写
type-aliases-package: com.lexiaoyao.mybatisdemo.domain
# 配置扫描的xml文件位置
mapper-locations: classpath:mybatis/mapper/*.xml
# mybatis详细配置文件
config-location: classpath:mybatis/mybatis-config.xml
# 扫描handler组件
type-handlers-package: com.lexiaoyao.mybatisdemo.handler

通用枚举处理器

note 这里将mysql数据库里字段定义为char(1)

1、定义枚举类的接口,统一格式


public interface BaseEnum<E extends Enum<?>, T> { T getCode();//code为存入数据库的值 String getInfo();//info为实际意义 }

2、定义枚举类


public enum Gender implements BaseEnum<Gender, String> {
Male("1", "男"),
Female("0", "女"),
Unknown("3", "保密"); private String code;
private String info; Gender(String code, String info) {
this.code = code;
this.info = info;
} public static Gender getGender(String code) {
return Arrays.stream(Gender.values()).filter(i -> i.getCode().equals(code)).findAny().orElse(null); } public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getInfo() {
return info;
} public void setInfo(String info) {
this.info = info;
}
}

3、编写统一的枚举映射handler


public class NormalEnumHandler<E extends BaseEnum> extends BaseTypeHandler<E> { private Class<E> enumType;
private E[] enums; public NormalEnumHandler(Class<E> type) {
if (type == null)
throw new IllegalArgumentException("Type argument cannot be null");
this.enumType = type;
this.enums = type.getEnumConstants();//获取所有枚举数组
if (this.enums == null)
throw new IllegalArgumentException(type.getSimpleName()
+ " does not represent an enum type.");
} public NormalEnumHandler() {
} @Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, E e, JdbcType jdbcType) throws SQLException {
if (jdbcType == null) {
preparedStatement.setString(i, (String) e.getCode());
} else {
preparedStatement.setObject(i, e.getCode(), jdbcType.TYPE_CODE);
} } @Override
public E getNullableResult(ResultSet resultSet, String s) throws SQLException {
return resultSet.wasNull() ? null : locateEnumStatus(resultSet.getString(s));
} @Override
public E getNullableResult(ResultSet resultSet, int i) throws SQLException {
return resultSet.wasNull() ? null : locateEnumStatus(resultSet.getString(i));
} @Override
public E getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return callableStatement.wasNull() ? null : locateEnumStatus(callableStatement.getString(i));
} private E locateEnumStatus(String value) {
return Arrays.stream(enums)
.filter(i -> i.getCode().equals(value))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("未知的枚举类型:" + value + ",请核对" + enumType.getSimpleName()));
} }

4、相应的扫描包下只需写一个Handler,并继承NormalEnumHandler


@MappedTypes(value = {Gender.class})
public class NormalHandler<E extends BaseEnum> extends NormalEnumHandler<E> {
public NormalHandler(Class<E> type) {
super(type);
}
}

要新加入枚举时候,只需要在MappedTypes的数据里添加一个即可。

5、配置扫描包

mybatis:
# 配置mybatis的resultType别名,默认是别名为小写
type-aliases-package: com.lexiaoyao.mybatisdemo.domain
# 配置扫描的xml文件位置
mapper-locations: classpath:mybatis/mapper/*.xml
# mybatis详细配置文件
config-location: classpath:mybatis/mybatis-config.xml
# 扫描handler组件
type-handlers-package: com.lexiaoyao.mybatisdemo.handler

Git

https://github.com/lexiaoyao1995/mybatisDemo

Mybatis 枚举类处理的更多相关文章

  1. 使用内部枚举类作为外部类的参数的Mybatis的参数该如何判断

    新写了一个接口,期望根据不同的参数来给数据库中不同的字段进行传值.这里使用了内部静态枚举类的方式进行传值,在写mybatis动态sql时,如果是普通对象,一般使用,那么使用枚举类,如何判断枚举类的值呢 ...

  2. mybatis枚举映射成tinyint

    第一步:定义顶级枚举接口 public interface BaseEnum<E extends Enum<?>, T> { public T getCode(); publi ...

  3. mybatis枚举自动转换(通用转换处理器实现)

    https://blog.csdn.net/fighterandknight/article/details/51520595 https://blog.csdn.net/fighterandknig ...

  4. mybatis 枚举类型使用

    一.首先定义接口,提供获取数据库存取的值得方法,如下: public interface BaseEnum { int getCode(); } 二.定义mybatis的typeHandler扩展类, ...

  5. mybatis枚举类型处理器

    1. 定义枚举值的接口 public abstract interface ValuedEnum { int getValue(); } 所有要被mybatis处理的枚举类继承该接口 2. 定义枚举类 ...

  6. Mybatis枚举转换

    自定义mybatis枚举转换,原理是如果用户没有定义自己的枚举转换工具,mybatis在解析枚举类时会自动获取mybatis的BaseTypeHandler,来转换枚举类,我们只需要重写这个枚举转换器 ...

  7. Linq专题之提高编码效率—— 第三篇 你需要知道的枚举类

     众所周知,如果一个类可以被枚举,那么这个类必须要实现IEnumerable接口,而恰恰我们所有的linq都是一个继承自IEnumerable接口的匿名类, 那么问题就来了,IEnumerable使了 ...

  8. 0029 Java学习笔记-面向对象-枚举类

    可以创建几个对象? n多个:大部分的类,都可以随意创建对象,只要内存不爆掉 1个:比如单例类 有限的几个:采用单例类的设计思路,可以只允许创建少数的几个特定的对象:还有就是枚举类. 创建少数几个对象, ...

  9. FastJson转换自定义枚举类

    在项目中有些状态需要采用枚举类型,在数据库中保存的是name(英文),而前台需要显示的是text(中文). 所以这就需要自己去实现序列. 例如对象: import java.util.Date; im ...

随机推荐

  1. tp3.2 新增邮件类

    1.新建方法   调用发送邮件,我的目录在/admin下 2.新增邮件方法 类的发送配置功能 文件地址: 网站根目录\项目目录\Admin\Common\ 文件 名   :function.php   ...

  2. 《计算机存储与外设》 1Cache存储器与虚拟存储器

    初读这本书,是2020年3,4月吧,以前学的大多数处理器,balabala的,虽然也有介绍储存器的,但总是不是很详细,主要还是关注cpu等计算部件或者总线等事物,就如同这本书中所写,人们往往可以很清楚 ...

  3. CI4框架应用一 - 环境搭建

    CI框架 (codeigniter)算是一个古老的框架了,由于在工作中一直在使用这个框架,还是比较有感情的.我对CI的感觉就是,简单易用,学习曲线平滑,对于新手友好. 目前CI框架已经更新到CI4了, ...

  4. 《RabbitMQ》如何保证消息不被重复消费

    一 重复消息 为什么会出现消息重复?消息重复的原因有两个:1.生产时消息重复,2.消费时消息重复. 1.1 生产时消息重复 由于生产者发送消息给MQ,在MQ确认的时候出现了网络波动,生产者没有收到确认 ...

  5. 又一个小而美的Java Web框架: Solon!

    Solon 是Java世界里一个新的极易上手的Web框架.参考过 Javalin . Spring 等很多现有框架的设计. 取名自海贼王里的角色,说是希能像他一样能打 小.真的是小.最小的运行单位只有 ...

  6. 远程服务器的管理工具SSH

    1.SSH是什么? SSH:Secure Shell 安全外壳协议 建立在应用层基础上的安全协议 可靠,专为远程登录会话和其他网络服务提供安全性的协议 有效防止远程管理过程中的信息泄露问题 SSH客户 ...

  7. Java基础—字符串

    事实上,Java是没有内置的字符串类型的,而是在标准Java类库中提供了一个预定义类String.每个用双引号括起来的字符串都是String类的一个实例: String str = "&qu ...

  8. 痞子衡嵌入式:一种i.MXRT下从App中进入ROM串行下载模式的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下在App中利用ROM API进ISP/SDP模式的方法. 我们知道i.MXRT系列分为两大阵营:CM33内核的i.MXRT ...

  9. C#LeetCode刷题之#16-最接近的三数之和(3Sum Closest)

    目录 问题 示例 分析 问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3620 访问. 给定一个包括 n 个整数的 ...

  10. day6 函数

    1.关键字参数     给实参对应的形参   调用函数时 设置关键字参数,形参=实参,把实参固定给那个形参 2.元组的可变(不定长参数)的使用      可变参数可以接收任意数量的普通的形参,并且组包 ...