目录
- 概述
- 类型处理器类结构及作用
- Mybatis常用的默认类型处理器
- 类型处理器实现原理
- 利用自定义类型处理器实现数据加解密
概述
Mybatis作为持久层框架在存储和查询数据时,只需在Mapper.xml文件中配置好对应字段的JdbcType和JavaType,Mybatis通过内置的类型转换器就会自定转换成对应的类型。Mybatis内置默认的类型转换器是通过org.apache.ibatis.type.TypeHandlerRegistry类进行注册的。当然,我们如果需要对某些字段做特殊处理,比如加解密、状态转换、类型转换等,可以自定义类型转换器来实现。
类型处理器类结构及作用
- TypeHandler:定义类型处理器接口
- TypeReferance:定义了一个类型引用的抽象类,用于引用一个泛型类型
- BaseTypeHandler:类型处理器的公共类,所有类型处理器的公共模块,几乎所有类型处理器都是通过直接继承BaseTypeHandler来实现
Mybatis常用的默认类型处理器
MyBatis提供了一组默认的类型处理器(TypeHandler),用于在Java类型和JDBC 类型之间进行转换。默认类型处理器是自动注册的,无需额外配置。以下是 MyBatis 默认支持的类型处理器列表:
TypeHandler | Java类型 | Jdbc类型 |
---|---|---|
BooleanTypeHandler | Boolean | BIT、TINYINT、INTEGER |
ByteTypeHnadler | Byte | NUMERIC、TINYINT、SMALLINT |
ShortTypeHandler | Short | SMALLINT、TINYINT INTEGER |
IntegerTypeHandler | Integer | SMALLINT、INTEGER、BIGINT |
LongTypeHandler | Long | SMALLINT、INTEGER、BIGINT |
FloatTypeHanler | Float | DOUBLE、REAL、FLOAT |
DoubleTypeHandler | Double | REAL、DOUBLE、FLOAT |
BigDecimalTypeHandler | BigDecimal | NUMERIC、DECIMAL |
StringTypeHandler | String | CHAR、VARCHAR、LONGVARCHAR |
ClobTypeHandler | String | CLOB、LONGVARCHAR |
NStringTypeHandler | String | NVARCHAR、NCHAR |
NClobTypeHandler | String | NCLOB |
ByteArrayTypeHandler | byte[] | BLOB、LONGVARBINARY、VARBINARY |
BlobTypeHandler | byte[] | BLOB、LONGVARBINARY |
DateTypeHandler | Date | TIMESTAMP |
DateOnlyTypeHandler | Date | DATE |
TimeOnlyTypeHandler | Date | TIME |
SqlTimestampTypeHandler | Timestamp | TIMESTAMP |
SqlDateTypeHandler | Date | DATE |
类型处理器实现原理
Mybatis在预处理语句(PreparedStatement)中设置一个参数时,或者从结果集(ResultSet)中取出一个值时,都会用到TypeHandler。它的作用是将java类型(JavaType)转换成jdbc类型(JdbcType),或者将jdbc类型(JdbcType)转换成java类型(JavaType)。 自定义类型转换器方式是实现TypeHandler接口或继承BaseTypeHandler类,TypeHandler接口提供了四个方法是实现类必须实现的,如下:
当update/insert时,在DefaultParameterHandler#setParameters方法中设置Java类型与Jdbc类型的转换
利用自定义类型处理器实现数据加解密
- 自定义Base64TypeHandler实现org.apache.ibatis.type.TypeHandler接口或继承org.apache.ibatis.type.BaseTypeHandler,使用Base64模拟加解密(可根据实际项目选择加解密方案,比如AES、加密机等)
java
package com.learning.mybatis.typehandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Base64;
/**
* <p>
* 自定义类型处理器,实现org.apache.ibatis.type.TypeHandler接口
* </p>
*/
public class Base64TypeHandler implements TypeHandler<String> {
@Override
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
try {
// 设置参数的时候对参数进行加密
String encode = Base64.getEncoder().encodeToString(parameter.getBytes());
ps.setString(i, encode);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String getResult(ResultSet rs, String columnName) throws SQLException {
// 获取结果集对加密数据进行解密
String result = rs.getString(columnName);
if (result != null && !result.equals("")) {
try {
return new String(Base64.getDecoder().decode(result));
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
@Override
public String getResult(ResultSet rs, int columnIndex) throws SQLException {
// 获取结果集对加密数据进行解密
String result = rs.getString(columnIndex);
if (result != null && !result.equals("")) {
try {
return new String(Base64.getDecoder().decode(result));
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
@Override
public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
// 获取结果集对加密数据进行解密
String result = cs.getString(columnIndex);
if (result != null && !result.equals("")) {
try {
return new String(Base64.getDecoder().decode(result));
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
}
- 配置注册自定义处理器(mybatis-config.xml)
xml
<!-- 配置自定义处理器-->
<typeHandlers>
<typeHandler handler="com.learning.mybatis.typehandler.Base64TypeHandler"/>
</typeHandlers>
- 使用自定义处理器(mapper.xml文件)
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learning.mybatis.basicusage.mapper.UserMapper">
<resultMap id="resultMap" type="com.learning.mybatis.basicusage.entity.TEntity">
<id column="id" property="id"/>
<!-- 指定字段使用自定义类型处理器,对select生效-->
<result column="c" property="c" typeHandler="com.learning.mybatis.typehandler.Base64ypeHandler"/>
</resultMap>
<sql id="columnList">
id, c
</sql>
<!-- 如果是insert/update等进行生效,如下方法-->
<update id="update" parameterType="com.learning.mybatis.basicusage.entity.TEntity">
update T set c = #{entity.c, typeHandler=com.learning.mybatis.typehandler.Base64ypeHandler} where id = #{entity.id}
</update>
<select id="selectById1" resultMap="resultMap" useCache="false">
select <include refid="columnList"></include> from T where id = ${id}
</select>
</mapper>
- 测试类
java
package com.learning.mybatis.basicusage;
import com.learning.mybatis.basicusage.entity.TEntity;
import com.learning.mybatis.basicusage.mapper.UserMapper;
import com.learning.mybatis.plugin.page.PageInfo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisXmlTest {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
// 更新
TEntity tEntity = new TEntity();
tEntity.setId(1);
tEntity.setC("3232");
userMapper.update(tEntity);
// 查询
List<TEntity> tBeans = userMapper.selectById1(1, new PageInfo());
System.out.println("查询结果:" + tBeans);
session.commit();
session.close();
}
}
写在最后
Mybatis源码解析:mp.weixin.qq.com/s/asGekskJy...
通过自定义类型处理器实现数据加解密来理解Mybatis的类型处理器的实现机制。欢迎关注"程序员笨鸥"一起学习吧!