Mybatis 枚举类处理
类型处理器(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 枚举类处理的更多相关文章
- 使用内部枚举类作为外部类的参数的Mybatis的参数该如何判断
新写了一个接口,期望根据不同的参数来给数据库中不同的字段进行传值.这里使用了内部静态枚举类的方式进行传值,在写mybatis动态sql时,如果是普通对象,一般使用,那么使用枚举类,如何判断枚举类的值呢 ...
- mybatis枚举映射成tinyint
第一步:定义顶级枚举接口 public interface BaseEnum<E extends Enum<?>, T> { public T getCode(); publi ...
- mybatis枚举自动转换(通用转换处理器实现)
https://blog.csdn.net/fighterandknight/article/details/51520595 https://blog.csdn.net/fighterandknig ...
- mybatis 枚举类型使用
一.首先定义接口,提供获取数据库存取的值得方法,如下: public interface BaseEnum { int getCode(); } 二.定义mybatis的typeHandler扩展类, ...
- mybatis枚举类型处理器
1. 定义枚举值的接口 public abstract interface ValuedEnum { int getValue(); } 所有要被mybatis处理的枚举类继承该接口 2. 定义枚举类 ...
- Mybatis枚举转换
自定义mybatis枚举转换,原理是如果用户没有定义自己的枚举转换工具,mybatis在解析枚举类时会自动获取mybatis的BaseTypeHandler,来转换枚举类,我们只需要重写这个枚举转换器 ...
- Linq专题之提高编码效率—— 第三篇 你需要知道的枚举类
众所周知,如果一个类可以被枚举,那么这个类必须要实现IEnumerable接口,而恰恰我们所有的linq都是一个继承自IEnumerable接口的匿名类, 那么问题就来了,IEnumerable使了 ...
- 0029 Java学习笔记-面向对象-枚举类
可以创建几个对象? n多个:大部分的类,都可以随意创建对象,只要内存不爆掉 1个:比如单例类 有限的几个:采用单例类的设计思路,可以只允许创建少数的几个特定的对象:还有就是枚举类. 创建少数几个对象, ...
- FastJson转换自定义枚举类
在项目中有些状态需要采用枚举类型,在数据库中保存的是name(英文),而前台需要显示的是text(中文). 所以这就需要自己去实现序列. 例如对象: import java.util.Date; im ...
随机推荐
- 【BZOJ2821】作诗 题解(分块+前缀和)
前言:世间还有这么卡常的题…… ------------------ 题目链接 题目大意:给定长度为$n$的序列${a_i}$.有$m$次询问,问$[l,r]$内出现正偶数次的数字有多少个. 这题跟蒲 ...
- python2.3嵌套if结构:
#案例:存款100万的请款下,买宝马:老爸资助大于50万买宝马740:大于30万买宝马520:小于20万宝马320.存款大于50万小于100万买丰田:大于20万小于50万买二手车:小于20万自行车! ...
- 【学习笔记】VS Code的launch.json 的 Python和Chrome常用配置(MacOS)
遇到的问题: 1.无法直接用VS Code调用Chrome来打开HTML文件 2.VS Code调用Chrome成功后,Python解释器无法启动调试了 解决方法: 以下是我的 launch.json ...
- 07 CentOS简单命令与XShell简单使用
关机 poweroff 重启 init 6 查看ip地址 ifconfig 查看当前目录下的文件与目录 ls ll 判断命令是内部还是外部的类型 type ifconfig 通过file /sbin/ ...
- JavaFX桌面应用开发系列文章
~ JavaFX桌面应用开发系列文章汇总篇 ~ JavaFX桌面应用开发-HelloWorld JavaFX布局神器-SceneBuilder JavaFX让UI更美观-CSS样式 JavaFX桌面应 ...
- 2020-04-09:TCP的四次挥手中为什么要有TIME_WAIT状态?
TIME_WAIT状态存在有两个原因.<1>可靠终止TCP连接.如果最后一个ACK报文因为网络原因被丢弃,此时server因为没有收到ACK而超时重传FIN报文,处于TIME_WAIT状态 ...
- C#算法设计查找篇之02-二分查找
二分查找(Binary Search) 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/699 访问. 二分查找也称折半查 ...
- 为什么你的 64-bit 程序可能占用巨大的虚拟空间
出于很多目的,我从最新的 Go 系统内核开发源码复制了一份代码,在一个正常的运行环境中构建(和重新构建)它,在构建版本基础上周期性地重新构建 Go 程序.近期我在用 ps 查看我的一个程序的内存使用情 ...
- 通过实际案例摸清楚Spring事务传播的行为
@ 目录 事务传播 案例准备 案例解析 1.无事务 2. Propagation.REQUIRED 3. Propagation.SUPPORTS 4. Propagation.MANDATORY 5 ...
- Python默认参数的陷阱
一:内置函数 globals() locals() 1.返回的是字典,字典里面的键值对:全局作用域的全部内容 print(globals()) 2.返回的是字典,字典里面的键值对:当前作用域的全部内容 ...