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 ...
随机推荐
- K短路 学习笔记
K短路,顾名思义,是让你求从$s$到$t$的第$k$短的路. 暴力当然不可取,那么我们有什么算法可以解决这个问题? -------------------------- 首先,我们要维护一个堆. st ...
- 面试:Java基础知识(一)
1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽 ...
- @property@classmethod@staticmethod
一.静态属性@property将方法标记成数据属性:可以访问实例和类的属性 @classmethod标记成类的方法,不需要实例化,可以类直接调用的方法.可以访问类的属性方法,不能访问实例的 class ...
- Github获8300星!用Python开发的一个命令行的网易云音乐
最近在逛Github发现了一个非常有趣的库musicbox,是用纯Python打造的,收获了8300颗星.Python语言简单易学,好玩有趣,身边越来越多的小伙伴都开始学习Python.她的魅力非常大 ...
- 在图像中隐藏数据:用 Python 来实现图像隐写术
什么是“隐写术”? 隐写术是将机密信息隐藏在更大的信息中,使别人无法知道隐藏信息的存在以及隐藏信息内容的过程.隐写术的目的是保证双方之间的机密交流.与隐藏机密信息内容的密码学不同,隐写术隐瞒了传达消息 ...
- 事件 - DOM编程
何为 DOM 事件,HTML DOM 使JavaScript 有能力对 HTML 事件做出反应. 1. 事件流 一个 DOM 事件可以分为捕获过程.触发过程.冒泡过程. 下面一个<a>元素 ...
- 01-java实现动态数组
01-手撸动态数组 本篇是恋上数据结构第一季个人总结 借鉴https://juejin.im/post/6844904001478066183#heading-0 本人git https://gith ...
- C#LeetCode刷题之#628-三个数的最大乘积( Maximum Product of Three Numbers)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3726 访问. 给定一个整型数组,在数组中找出由三个数组成的最大乘 ...
- CSS动画基础知识
CSS动画就是通过CSS (Cascading Style Sheet,层叠样式表)代码搭建的网页动画.它允许设计师和开发人员通过编辑网站的CSS代码来添加页面动画,从而轻松取代传统动画图片或flas ...
- ubuntu18.04配置与美化
一:初步系统配置 1 不可或缺的更新 如果在上一步中勾选了安装 Ubuntu 时下载更新,那么大部分的系统更新已经下载完毕. 不过为了确保,先移步到 设置→详细信息 ,点击右下角的 检查更新 ,如果存 ...