之前的《MyBatis 中 SqlMapConfig 配置文件详解》记了一下 MyBatis 中的核心配置文件各个标签的作用和使用场景,这篇文章细说一下配置文件中 typeHandlers 标签的详细使用。
在 MyBatis 的 sql 映射配置文件中,为 sql 配置的输入参数最终要从 java 类型转换成数据库能识别的类型,而从 sql 的查询结果集中获取的数据,也要从数据库的数据类型转换为对应的 Java 类型。
在 MyBatis 中,使用类型处理器(TypeHandler)将数据库获取的值以合适的方式转换为 Java 类型,或者将 Java 类型的参数转换为数据库对应的类型。
在 MyBatis 中有许多自带的类型处理器,但有时候也会满足不了开发的需求,这时候就需要配置自己的类型处理器了,而 typeHandlers 标签就是用来声明自己的类型处理器的。
使用 typeHandlers 标签配置一个自己的类型处理器,一般需要三个步骤:编写类型处理器类,在 MyBatis 全局配置文件中配置该类型处理器,在 sql 映射配置文件中使用。
例如要编写一个将 JDBC 的 timestamp 类型与 Date 类型相互转换的类型处理器配置示例。首先编写类型处理器,一般要实现 org.apache.ibatis.type.TypeHandler 接口,接口的泛型指定要转换的 Java 参数类型,若不指定则默认为 Object 类,实现 TypeHandler 接口主要改写四个方法,如下:
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
public String getResult(ResultSet rs,String columnName)
public String getResult(ResultSet rs,int columnIndex)
public String getResult(CallableStatement cs,int columnIndex)
setParameter 方法是在 sql 配置传入参数时(新增、删除、修改、查询)执行的操作,可以在将参数传入数据库之前在该方法中对数据类型做处理。
另外三个 getResult 方法则在数据库返回结果时,将结果信息转换为相应的 Java 类型。区别在于前两个 getResult 方法供普通 select 方法使用,一个根据字段名,一个根据字段下标来获取数据,最后一个 getResult 方法供存储过程使用,根据字段下标获取数据。
以下代码是编写一个将 JDBC 的 timestamp 类型与 Date 类型相互转换的类型处理器配置示例:
package cn.com.mybatis.test;
import java.sql.CallableStatement;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.JdbcType;
public class DateTypeHandler implements TypeHandler<Date> {
//转换日期类型的辅助类
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException{
//指定传入的Java参数对应JDBC中的数据库类型
System.out.println("其他逻辑");
ps.setDate(i, parameter);
System.out.println("其他逻辑");
}
public Date getResult(ResultSet rs,String columnName) throws SQLException{
System.out.println("其他逻辑");
return rs.getDate(columnName);
}
public Date getResult(ResultSet rs,int columnIndex) throws SQLException{
System.out.println("其他逻辑");
return rs.getDate(columnIndex);
}
public Date getResult(CallableStatement cs,int columnIndex) throws SQLException{
System.out.println("其他逻辑");
return cs.getDate(columnIndex);
}
}
之后在 MyBatis 的全局配置文件 SqlMapConfig 中使用 typeHandlers 标签来注册类型处理器,示例代码如下:
"cn.com.mybatis.test.DateTypeHandler" javaType="java.util.Date" jdbcType="TIMESTAMP"/>
然后在 sql 映射文件 xxxMapper.xml 中的 sql 语句中添加自定义的类型处理器的处理配置即可,代码示例如下:
insert into user(username,password,regdate) value(#{username},#{password},
#{regdate,javaType=date,jdbcType=TIMESTAMP,
typeHandler=cn.com.mybatis.test.DateTypeHandler})
如果设置了参数 regdate,就会将 Java 的 Date 类型转换为数据库需要的 timestamp 类型。另外,对于查询结果,如果定义了 resultMap 来设置结果集对象的映射,同样可以在标签内指定 javaType,jdbcType 和 typeHandler 的名称。
在编写自定义的类型处理器时,可以不实现 TypeHandler 接口,转而继承另一个类 org.apache.ibatis.type.BaseTypeHandler, 它是 MyBatis 的一个标准基础类型处理器类。
BaseTypeHandler 本身已经实现了 TypeHandler 接口,并继承了 TypeReferance 抽象类,在它内部简单的实现了 TypeHandler 接口中定义的四个方法的部分功能。
继承 BaseTypeHandler 类之后,可以通过改写 setNonNullParameter、getNullableResult 方法(三个)来实现类型处理器。示例代码如下:
public abstract void setNonNullParameter(PreparedStatement ps,int i,T parameter,JdbcType jdbcType)
public abstract T getNullableResult(ResultSet rs,String columnName)
public abstract T getNullableResult(ResultSet rs,int columnIndex)
public abstract T getNullableResult(CallableStatement cs,int columnIndex)
因为 BaseTypeHandler 继承 TypeReferance 抽象类,所以它本身也是一个抽象类,类中的 4 个方法也为抽象方法。
MyBatis 中,其内部的类型处理器大部分都是继承上面的 4 个方法来实现的,当其内部的类型处理器无法满足开发需求时,就需要自己定义类型处理类,步骤为先编写类型处理器类,其次将该处理器类配置到全局配置文件中,最后在 sql 映射配置文件中使用即可。
公众号回复数字“8”领取CIS加固全套手册。
微 信:fageweiketang,朋友圈不定期干货分享,欢迎讨论。
公众号:发哥微课堂,专注于代码审计、WEB渗透、网络安全。