MyBatis自定义TypeHandler实现字段加密解密

 更新时间:2025年03月16日 15:06:14   作者:小黑屋说YYDS  
本文主要介绍了MyBatis自定义TypeHandler实现字段加密解密,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

今天简单介绍利用MyBatis的TypeHandler接口实现字段的加解密。

字段的加密和解密,实现方式确实有好几种。比如,在业务层实现、在数据库层面实现等等,但是这些相对来说,耦合性稍微强那么一点点,而且涉及到改动的话,改动的地方比较多;所以最好的就是统一管理这些功能。

一、TypeHandler接口

Mybatis的TypeHandler类型转换器是负责Java类jdbc类型之间的转换。

主要涉及到下面这几个类:

  • TypeHandler 类型转换器的顶层接口。
  • BaseTypeHandler 抽象类继承自TypeHandler,Mybatis中所有的类型转换器实现均继承他。
  • TypeHandlerRegistry 类型转换器注册器,负责存储类型转换器。
  • TypeAliasRegistry 类型别名转换器,用来存储类型与别名的对应关系。

其主要作用就是:

  • 可以指定我们在Java实体类所包含的自定义类型存入数据库后的类型是什么。
  • 从数据库中取出该数据后自动转换为我们自定义的Java类型。

所以来实现简单的字段加密和解密比较方便。

二、实现

  • 1、定义一个实体类包装对象表示我们要加密的数据对象。
/**
 * 编写一个实体类,凡是此实体类的数据都表示需要加解密
 */
@Data
public class Encrypt {
    private String value;
}
  • 2、实现TypeHandler<T>接口,我们这实现BaseTypeHandler<T>
@MappedJdbcTypes(JdbcType.VARCHAR) // 表示该Handler处理的java类型
@MappedTypes(Encrypt.class) // 表示处理器处理的Jdbc类型
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {

    private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8);

    /**
     * 设置参数
     */
    @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 = SecureUtil.aes(KEYS);
        String encrypt = aes.encryptHex(parameter.getValue());
        ps.setString(i, encrypt);
    }

    /**
     * 获取值
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return decrypt(rs.getString(columnName));
    }

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

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

    public Encrypt decrypt(String value) {
        if (null == value) {
            return null;
        }
        return new Encrypt(SecureUtil.aes(KEYS).decryptStr(value));
    }
}
  • 3、配置Handler,配置的方式有集中;如果是MyBatisPlus,直接在字段注解上面添加即可;
    这里是MyBatis,所以可以写在配置文件中,也可以写在XML映射文件中,我们这里写在配置文件中。
# 指定自定义TypeHandler的包位置
mybatis.type-handlers-package=com.mybatis.typehandler

至此,关于自定义TypeHandler的开发就此完成,直接使用即可。

另外,基于自定义TypeHandler不仅可以实现自定义加解密,还可以实现特定数据类型的转换,这里以数据库类型为varchar映射Java对象类型的List集合类型为例说明。

还是自定义TypeHandler类,以逗号[,]分割为集合如下:

/**
 * 特定类型转换TypeHandler
 */
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)
public class ListTypeHandler extends BaseTypeHandler<List<String>> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
        if (null == parameter || parameter.isEmpty()) {
            ps.setString(i, null);
            return;
        }
        ps.setString(i, String.join(",", parameter));
    }

    @Override
    public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        final String value = rs.getString(columnName);
        if (StringUtils.hasText(value)) {
            return Arrays.asList(value.split(","));
        }
        return null;
    }

    @Override
    public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        final String value = rs.getString(columnIndex);
        if (StringUtils.hasText(value)) {
            return Arrays.asList(value.split(","));
        }
        return null;
    }

    @Override
    public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        final String value = cs.getString(columnIndex);
        if (StringUtils.hasText(value)) {
            return Arrays.asList(value.split(","));
        }
        return null;
    }
}
  • 4、使用
    定义数据库对象类,如下:
@Data
public class Customer {

    private Integer id;
    private Encrypt phone; // 表示要加密的字段
    private List<String> address; // 对应数据库字段address
    
}

建表语句:

CREATE TABLE `customer` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `phone` varchar(64) DEFAULT NULL COMMENT '手机号',
  `address` varchar(200) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客户表';

Mapper接口:

public interface CustomerMapper {

    int addCustomer(@Param("phone") Encrypt phone, @Param("address") String address);

    Customer findCustomer(@Param("phone") Encrypt phone);

}

Mapper接口XML:

 	<insert id="addCustomer">
        insert into customer(phone,address) values (#{phone},#{address})
    </insert>

    <select id="findCustomer" resultMap="BaseResultMapper">
        select * from customer where phone = #{phone}
    </select>

Controller接口:

@RestController
public class CustomerController {

    @Autowired
    private CustomerMapper customerMapper;

    @GetMapping("/addCustomer")
    public String addCustomer(@RequestParam("phone") String phone, @RequestParam("address") String address) {
        int result = customerMapper.addCustomer(new Encrypt(phone), address);
        return "添加结果: " + result;
    }

    @GetMapping("/findCustomer")
    public Customer findCustomer(@RequestParam("phone") String phone) {
        return customerMapper.findCustomer(new Encrypt(phone));
    }
}

数据库数据:

在这里插入图片描述

电话phone字段是加密之后的,address字段是 以逗号分隔的多个地址。

API调用结果如下:

在这里插入图片描述

可以看到电话号码,已经解密;地址成为字符串数组。

总结

MyBatis给我们提供了很多扩展类,MP和MB是一样的。所以关于数据结果类型的处理,可以使用TypeHandler接口。

到此这篇关于MyBatis自定义TypeHandler实现字段加密解密的文章就介绍到这了,更多相关MyBatis TypeHandler字段加密解密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 递归查询所有子节点id的方法实现

    java 递归查询所有子节点id的方法实现

    在多层次的数据结构中,经常需要查询一个节点下的所有子节点,本文主要介绍了java 递归查询所有子节点id的方法实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • SpringBoot配置连接两个或多个数据库的常用方法

    SpringBoot配置连接两个或多个数据库的常用方法

    在Spring Boot应用中连接多个数据库或数据源可以使用多种方式,本文讲给大家介绍两种常用的方法:使用Spring Boot官方支持的多数据源配置和使用第三方库实现多数据源,文章通过代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • Java加载资源文件时的路径问题的解决办法

    Java加载资源文件时的路径问题的解决办法

    今天偶然看到一篇关于tomcat加载servlet的文章,不由得想起了java加载资源文件的路径问题,资源文件可以使xml,properties,图片等,可以是任何文件
    2013-04-04
  • 详解Vue响应式的部分实现

    详解Vue响应式的部分实现

    响应式,简单来说当数据发生变化时,对数据有依赖的代码会重新执行。这篇文章主要为大家介绍了Vue中响应式的部分实现,感兴趣的可以了解一下
    2022-12-12
  • Java复杂表头的Excel导入功能实现

    Java复杂表头的Excel导入功能实现

    本篇文章主要介绍如何使用Java相关的技术,来实现复杂表头的excel导入功能,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-09-09
  • Java基础之ArrayList的扩容机制

    Java基础之ArrayList的扩容机制

    这篇文章主要介绍了Java基础之ArrayList的扩容机制,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有很好的帮助,需要的朋友可以参考下
    2021-05-05
  • Java基于socket服务实现UDP协议的方法

    Java基于socket服务实现UDP协议的方法

    这篇文章主要介绍了Java基于socket服务实现UDP协议的方法,通过两个简单实例分析了java通过socket实现UDP发送与接收的技巧,需要的朋友可以参考下
    2015-05-05
  • SpringBoot之自动装配原理及解读

    SpringBoot之自动装配原理及解读

    Spring Boot自动装配原理:通过@SpringBootApplication、@ComponentScan和@EnableAutoConfiguration注解,扫描主配置类所在包及其子包下的类,并加载符合条件的自动配置类,实现Spring IOC容器的自动配置
    2026-02-02
  • java servlet获得客户端相关信息的简单代码

    java servlet获得客户端相关信息的简单代码

    这篇文章主要介绍了java servlet获得客户端相关信息的简单代码,有需要的朋友可以参考一下
    2013-12-12
  • 详解Spring循环依赖的解决方案

    详解Spring循环依赖的解决方案

    这篇文章主要介绍了详解Spring循环依赖的解决方案,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05

最新评论