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 分钟前
构建有效 Agent 的核心原则
java·人工智能·git·学习·自动化
神魔皆以血嗜8 分钟前
Java 实现简单状态机(订单状态流转)
java·后端
随性而行36017 分钟前
企业微信 API 如何实现业务消息自动通知?接口应用场景解析
java·人工智能·后端·微信·机器人·企业微信
姜九笙56123 分钟前
python学习---归来仍是新人
java·python·学习
HEJOO936 分钟前
Java 并发运行中的安全问题详解
java·开发语言
2601_9621066440 分钟前
【无标题】
java·idea
汉吉龙测控技术43 分钟前
激光对中仪作用介绍(AS 激光对中仪)
java
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 完善用户信息章节复盘:套路清单与自检清单
java·dubbo·交友
用户3126874877201 小时前
Java 11-21 新特性盘点:var、record、sealed、虚拟线程
java
TangGeeA1 小时前
命令安全设置
java·服务器·安全