当前位置: 首页 > article >正文

MyBatis之TypeHandler的自定义实现

文章目录

  • 一、TypeHandler概述
  • 二、TypeHandler的工作原理
    • 1.设置参数(Parameter Setting)
    • 2.获取结果(Result Getting)
    • 3.类型映射和转换规则
    • 4.自定义TypeHandler的扩展性
  • 三、自定义的具体实现
    • 业务场景
    • 分析需求
    • 具体实现

一、TypeHandler概述

在 MyBatis 中,类型处理器(TypeHandler)扮演着 JavaType 与 JdbcType 之间转换的桥梁角色。它们用于在执行 SQL 语句时,将 Java 对象的值设置到 PreparedStatement 中,或者从 ResultSet 或 CallableStatement 中取出值。

二、TypeHandler的工作原理

TypeHandler在MyBatis中是一个核心概念,其工作原理主要涉及Java类型和JDBC类型之间的转换。下面将详细介绍TypeHandler的工作原理。

1.设置参数(Parameter Setting)

当Mybatis要执行一个sql语句时,(例如INSERT UPDATE等),它需要将Java对象的属性值设置到SQL语句对应的占位符上,这个过程就是通过TypeHandler来完成的。

具体步骤

  1. MyBatis会根据映射配置找到对应的TypeHandler实例。这个映射配置可以在MyBatis的配置文件或者XML文件中定义。
  2. TypeHandler实例会接收到Java对象中的属性值,并将其转换成JDBC能够识别的类型。这个转换过程是根据Java类型和JDBC类型之间的映射关系来完成的。
  3. 转换后的值会被设置到PreparedStatement对象对应的占位符上,以便数据库能够正常解析和执行SQL语句

2.获取结果(Result Getting)

当数据库进行查询操作并返回结果集合时,MyBatis需要将结果集中的数据提取出来,转换成Java对象中的对应属性类型,这个过程同样是由TypeHandler来完成的。

具体步骤

  1. MyBatis会根据映射配置找到对应的TypeHandler实例
  2. TypeHandler实例会从ResultSet对象中提取数据,这个提取过程是根据数据库字段和Java属性之间的映射关系来实现的。
  3. 提取出来的数据会被转换成Java对象中的对应属性类型,这个转换过程是由Java类型和JDBC类型之间的映射关系来完成的。
  4. 转换后的值会被设置到Java对象中对应的属性上,以便程序能够正确处理和使用这些数据。

3.类型映射和转换规则

TypeHandler的核心功能是实现Java类型和JDBC类型之间的映射和转换。这个映射和转换规则是根据Java类型和JDBC类型的特性和语义来定义的。

对于基本数据类型(如int、long、float等),MyBatis提供了内置的TypeHandler实现,这些实现能够直接将Java基本数据类型转换为对应的JDBC基本数据类型,反之亦然。
对于复杂数据类型(如自定义对象、集合等),MyBatis允许开发者自定义TypeHandler来实现复杂的类型转换逻辑。

4.自定义TypeHandler的扩展性

MyBatis的TypeHandler机制具有很高的扩展性。我们可以通过实现TypeHandler接口或继承BaseTypeHandler类来创建自定义的TypeHandler实现。自定义的TypeHandler可以实现任意复杂的类型转换逻辑,以满足特定业务需求。

此外,MyBatis还提供了丰富的API和扩展点来支持开发者自定义TypeHandler的注册和使用方式。我们可以通过配置文件、注解或编程方式将自定义的TypeHandler注册到MyBatis中,并在Mapper的XML映射文件中引用它们来处理特定的数据类型转换需求。

三、自定义的具体实现

业务场景

现在我们要对用户存入的手机号进行处理。存入手机号时需要进行加密操作,从数据库中取出手机号时,进行解密。

分析需求

TypeHandler是将指定类型转换成数据库支持的类型

  1. TypeHandler拿到手机号,进行加密
  2. TypeHandler加密后转换成指定JDBC类型存入数据库
  3. TypeHandler从数据库中取出JDBC类型
  4. TypeHandler拿到JDBC类型进行解密
  5. 返回手机号

具体实现

我们先定义一个Encrypt类。
这是我们自定义的类,后续会配合注解使用。

@Data
public class Encrypt {

    private String value;
    public Encrypt(){}
    public Encrypt(String value){
        this.value = value;
    }
}
@MappedTypes(Encrypt.class)     //被处理的类型
@MappedJdbcTypes(JdbcType.VARCHAR)      //转换成的JDBC类型
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {

    //手机号的加密我们采用aes加密方式
    //密钥
    private final byte[] KEY = "123456789abcdefg".getBytes(StandardCharsets.UTF_8);

    /**
     * 设置参数
     * @param ps SQL 预编译的对象
     * @param i  需要赋值的索引位置
     * @param parameter  原本位置i需要赋的值
     * @param jdbcType   jdbc类型
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
            if(parameter == null || parameter.getValue() == null){
                ps.setString(i,null);
                return;
            }
            AES aes = new AES(KEY);
            String str = aes.encryptHex(parameter.getValue());
            ps.setString(i, str);
    }

    /**
     * 获取值
     * @param rs    结果集
     * @param columnName       索引名
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return decrypt(rs.getString(columnName));
    }

    /**
     * 获取值
     * @param rs     结果集
     * @param columnIndex       索引
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return decrypt(rs.getString(columnIndex));
    }

    /**
     * 获取值
     * @param cs    结果集
     * @param columnIndex   索引
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return decrypt(cs.getString(columnIndex));
    }

	//解密方法
    private Encrypt decrypt(String str){
        if (StringUtils.hasText(str)){
            return null;
        }
        return new Encrypt(SecureUtil.aes(KEY).decryptStr(str));
    }
}

注意
在properties文件中配置路径

mybatis.type-handlers-package=com.example.lottery.dao.handler

http://www.kler.cn/news/340794.html

相关文章:

  • Golang | Leetcode Golang题解之第462题最小操作次数使数组元素相等II
  • GNU/Linux - tarball文件介绍介绍
  • C#中Json序列化的进阶用法
  • Spring中注入bean时的scope属性详解、往singleton中注入prototype属性的bean以及Spring使用注解实现AOP切面编程
  • qwt实现码流柱状图多色柱体显示
  • SAP将假脱机(Spool requests)内容转换为PDF文档[RSTXPDFT4]
  • GAMES202作业3
  • 27-云计算下一个十年技术Serverless
  • 阿里140滑块-滑块验证码逆向分析思路学习
  • class 031 位运算的骚操作
  • Spring Boot 整合 Minio
  • JavaScript基础---typeof和instanceof的区别
  • git 相关问题解决一一记录
  • 斯坦福 CS229 I 机器学习 I 构建大型语言模型 (LLMs)
  • 如何在两台服务器之间迁移 MySQL 数据库
  • MySQL 实验 6:定义数据的完整性
  • 【JVM】高级篇
  • 【AAOS】Android Automotive 9模拟器源码下载及编译
  • C++ 内部类
  • Python测试库介绍及示例