当大家使用 mybatis 作为持久层框架时, 在存储和查询数据时, 只需要在 mapper.xml 文件中配置好对应字段的 JdbcType 和 JavaType,mybatis 就可以帮我们转化对应的类型. 这背后是有 mybatis 内置的类型转换器做转换(可见源码 TypeHandlerRegistry). 但是有时候, 我们会对某些字段做特殊处理, 比如加密和解密, 状态转换, 类型转换等. 这个时候我们需要自定义类型转换器.
一, 原理
使用场景: mybatis 在预处理语句 (PreparedStatement) 中设置一个参数时, 或者从结果集 (ResultSet) 中取出一个值时, 都会用到 TypeHandler. 它的作用就是将 java 类型 (javaType) 转化为 jdbc 类型 (jdbcType), 或者将 jdbc 类型(jdbcType) 转化为 java 类型(javaType).
二, 自定义类型处理器
实现 TypeHandler 接口或者继承 BaseTypehandler
TypeHandler 是一个接口, 它定义了如下四个方法, 实现类必须去实现, 方法如下:
- void setParameter(PreparedStatement var1, int var2, T var3,JdbcType var4) throws SQLException;
- T getResult(ResultSet var1, String var2) throws SQLException;
- T getResult(ResultSet var1, int var2) throws SQLException;
- T getResult(CallableStatement var1, int var2) throws SQLException;
- }
setParameter: 通过 preparedStatement 对象设置参数, 将 T 类型的数据存入数据库.
getResult: 通过列名或者下标来获取结果数据, 也可以通过 CallableStatement 获取数据.
三, 案例(自定义敏感字段加解密处理器)
MyTypeHandler 实现 TypeHandler 接口
- package com.mdd.mybatis.typehandle;
- import com.mdd.mybatis.util.DESUtil;
- import org.apache.commons.lang3.StringUtils;
- 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;
- public class MyTypeHandle implements TypeHandler<String> {
- private static String KEY = "123456";
- @Override
- public void setParameter(PreparedStatement preparedStatement, int i, String s, JdbcType jdbcType) throws SQLException {
- try {
- String encrypt = DESUtil.encrypt(s, KEY);
- preparedStatement.setString(i, encrypt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @Override
- public String getResult(ResultSet resultSet, String s) throws SQLException {
- String result = resultSet.getString(s);
- if (StringUtils.isNotEmpty(result)) {
- try {
- return DESUtil.decrypt(result, KEY);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- @Override
- public String getResult(ResultSet resultSet, int i) throws SQLException {
- String result = resultSet.getString(i);
- if (StringUtils.isNotEmpty(result)) {
- try {
- return DESUtil.decrypt(result, KEY);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- @Override
- public String getResult(CallableStatement callableStatement, int i) throws SQLException {
- String result = callableStatement.getString(i);
- if (StringUtils.isNotEmpty(result)) {
- try {
- return DESUtil.decrypt(result, KEY);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return result;
- }
- }
配置注册自定义处理器(mybatis.cfg.xml)
- <!-- 自定义类型处理器 -->
- <typeHandlers>
- <typeHandler handler="com.mdd.mybatis.typehandle.MyTypeHandle"></typeHandler>
- </typeHandlers>
使用自定义处理器(mapper 文件)
- <?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.mdd.mybatis.dao.UserDao">
- <resultMap id="BaseResultMap" type="com.mdd.mybatis.dao.vo.User">
- <id column="user_id" property="userId" jdbcType="VARCHAR"/>
- <result column="name" property="name" typeHandler="com.mdd.mybatis.typehandle.MyTypeHandle"/>
- <result column="password" property="password" jdbcType="VARCHAR"/>
- <result column="age" property="age" jdbcType="INTEGER"/>
- </resultMap>
- <sql id="Base_Column_List">
- user_id,name,password, age
- </sql>
- <insert id="saveUser">
- INSERT INTO t_user(user_id,name, password, age) VALUES (
- #{userId,jdbcType=VARCHAR},#{name,jdbcType=VARCHAR},
- #{password,jdbcType=VARCHAR},#{age,jdbcType=INTEGER}
- )
- </insert>
- <insert id="saveUserWithType">
- INSERT INTO t_user(user_id,name, password, age) VALUES (
- #{userId,jdbcType=VARCHAR},#{name,typeHandler=com.mdd.mybatis.typehandle.MyTypeHandle},
- #{password,jdbcType=VARCHAR},#{age,jdbcType=INTEGER}
- )
- </insert>
- <select id="queryUser" resultMap="BaseResultMap">
- select * from t_user where user_id = #{userId,jdbcType=VARCHAR}
- </select>
- </mapper>
通过上面的配置, 自定义的 TypeHandler 就会生效, 敏感字段的加解密在 dao 层就可以解决, 对上层业务无感, 使用相当方便, 也更加灵活.
参考 http://www.mybatis.org/mybatis-3/configuration.html#typeHandler
来源: https://www.cnblogs.com/xwlhyy1072552712/p/9615877.html