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

相关推荐
天上掉下来个程小白2 分钟前
Redis-14.在Java中操作Redis-Spring Data Redis使用方式-操作列表类型的数据
java·redis·spring·springboot·苍穹外卖
ゞ 正在缓冲99%…10 分钟前
leetcode22.括号生成
java·算法·leetcode·回溯
写代码的小王吧13 分钟前
【Java可执行命令】(十)JAR文件签名工具 jarsigner:通过数字签名及验证保证代码信任与安全,深入解析 Java的 jarsigner命令~
java·开发语言·网络·安全·web安全·网络安全·jar
伊成27 分钟前
Springboot整合Mybatis+Maven+Thymeleaf学生成绩管理系统
java·maven·mybatis·springboot·学生成绩管理系统
一人の梅雨41 分钟前
化工网平台API接口开发实战:从接入到数据解析‌
java·开发语言·数据库
扫地的小何尚1 小时前
NVIDIA工业设施数字孪生中的机器人模拟
android·java·c++·链表·语言模型·机器人·gpu
Niuguangshuo1 小时前
Python设计模式:克隆模式
java·开发语言·python
suimeng61 小时前
基本元素定位(findElement方法)
java·selenium
方渐鸿1 小时前
【2025】快速部署安装docker以及项目搭建所需要的基础环境(mysql、redis、nginx、nacos)
java·运维·docker·持续部署·dockercompse
程序员鱼皮1 小时前
2025最新 Java 面经:美团后端面试真实复盘,附答案模板,速速收藏!
java·后端·面试