Mybatis之如何利用自定义类型处理器实现数据的加解密

目录

  • 概述
  • 类型处理器类结构及作用
  • 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的类型处理器的实现机制。欢迎关注"程序员笨鸥"一起学习吧!

相关推荐
_一条咸鱼_4 小时前
揭秘 Android TextInputLayout:从源码深度剖析其使用原理
android·java·面试
_一条咸鱼_4 小时前
揭秘!Android VideoView 使用原理大起底
android·java·面试
_一条咸鱼_4 小时前
深度揭秘!Android TextView 使用原理全解析
android·java·面试
_一条咸鱼_4 小时前
深度剖析:Android Canvas 使用原理全揭秘
android·java·面试
_一条咸鱼_4 小时前
深度剖析!Android TextureView 使用原理全揭秘
android·java·面试
_一条咸鱼_4 小时前
揭秘!Android CheckBox 使用原理全解析
android·java·面试
_一条咸鱼_4 小时前
深度揭秘:Android Toolbar 使用原理的源码级剖析
android·java·面试
_一条咸鱼_4 小时前
揭秘 Java ArrayList:从源码深度剖析其使用原理
android·java·面试