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

相关推荐
毕设源码-朱学姐1 天前
【开题答辩全过程】以 基于Java的医务室病历管理小程序为例,包含答辩的问题和答案
java·开发语言·小程序
沐浴露z1 天前
详解 零拷贝(Zero Copy):mmap、sendfile、DMA gather、splice
java·网络·操作系统
kyle~1 天前
C++---关键字constexpr
java·开发语言·c++
dllxhcjla1 天前
css第二天
java·前端·css
春生野草1 天前
SpringBoot配置文件
java·数据库·spring boot
车江毅1 天前
亿级O2O(智能设备)系统架构笔记【原创】
java·分布式·技术战略规划
code_std1 天前
SpringBoot 登录验证码
java·spring boot·后端
摇滚侠1 天前
Spring Boot3零基础教程,响应式编程,前景提要,笔记108
java·spring boot·笔记
java干货1 天前
BIO是“一人盯一桌”,NIO是“一人管全场”,AIO是“机器人送餐”
java·机器人·nio
Mos_x1 天前
@RestController注解
java·后端