类型处理器(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. NOI Online#1 小记

    虽然只是一个普通的模拟赛,但是毕竟是我第一次参加官方组织的比赛,所以还是写一篇小记纪念一下吧(毕竟经验少,太菜了. 上午一直颓着,随便看了两眼文化课,补了补昨天的化学作业,就当是对明天月考的复习吧(月 ...

  2. Python格式化字符串(f,F,format,%)

    # 格式化字符串: 在字符串前加上 f 或者 F 使用 {变量名} 的形式来使用变量名的值 year = 2020 event = 'Referendum' value = f'Results of ...

  3. python8.1多线程

    import threadingimport time def run1 (name,sex): print(name,sex,"执行线程1") time.sleep(3)def ...

  4. 使用git将本地仓库上传到远程仓库(转)

    第一步:创建一个工程目录 执行: git init 第二步:把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点".",意为添加文件夹下的所有 ...

  5. XCTF-WEB-新手练习区(1-4)笔记

    靶场地址:https://adworld.xctf.org.cn/ 1:view_source X老师让小宁同学查看一个网页的源代码,但小宁同学发现鼠标右键好像不管用了. 原理:使用浏览器F12或者B ...

  6. Win10系统Jmeter+maven+Jenkins接口自动化环境搭建(一)

    Jmeter+maven+Jenkins实现接口自动化,需要使用idea或eclipse配置maven项目,这里我使用的是idea.具体步骤如下: 1.安装jmeter+jdk jmeter安装之前需 ...

  7. C#LeetCode刷题之#844-比较含退格的字符串​​​​​​​(Backspace String Compare)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4030 访问. 给定 S 和 T 两个字符串,当它们分别被输入到空 ...

  8. GitHub 热点速览 Vol.32:VScode 韭菜基金插件,极大提高“工作”效率

    作者:HelloGitHub-小鱼干 摘要:有什么比干着本职工作--编码,而又兼顾"外快"--炒股更有开心的事情呢?leek-fund 就是这么一个极大提升你工作幸福度和效率的插件 ...

  9. Linux与Windows的区别(后面了解后继续更新)

    1.转自知乎上的@Haoyuan Xing得答案: Linux是一个以开发者为中心的操作系统,Windows是以消费者为中心的操作系统.这是最根本的区别,也是Linux相对于Windows的优势/劣势 ...

  10. Nmap在实战中的高级用法(详解)

    @ 目录 Nmap在实战中的高级用法(详解) Nmap简单的扫描方式: 一.Nmap高级选项 1.查看本地路由与接口 2.指定网口与IP地址 3.定制探测包 二.Nmap扫描防火墙 1.SYN扫描 2 ...