基于mybatis-plus进行加解密 Spring Boot Starter

独立的加解密 Spring Boot Starter

TypeHandler 使用说明文档(含依赖配置)

📦 一、Maven 依赖配置

在使用 TypeHandler 之前,需要先添加以下依赖:

xml 复制代码
<dependency>
    <groupId>cloud.cqcloud.platform</groupId>
    <artifactId>ylc-rpamis-spring-boot-starter</artifactId>
    <version>1.0.3</version>
</dependency>

说明: 该依赖包含了 TypeHandler 所需的 Sm4Utils 加密工具类及相关依赖。

如果需要密钥更改请自己下载源码替换,适配jdk17以下自己更换BouncyCastle 加密库版本和springboot版本即可或者移除,不影响的。版本是作为标准依赖用的,不影响使用。

📌 二、功能概述

TypeHandler 是一个基于 MyBatis 的自定义类型处理器 ,用于实现字段级别的自动加密存储自动解密查询 。它采用 SM4 国密算法对敏感数据进行加密处理,同时提供了便捷的对象加解密工具方法。


三、MyBatis 自动加解密配置

3.1 实体类配置(注解方式)

在需要加解密的实体字段上添加 @TableField 注解,指定 typeHandler

java 复制代码
@TableName(value = "user")
public class User {
    
    @TableField(typeHandler = TypeHandler.class)
    private String username;
    
    @TableField(typeHandler = TypeHandler.class)
    private String phone;
    
    @TableField(typeHandler = TypeHandler.class)
    private String email;
    
    // 普通字段,不加解密
    private Integer age;
}

实体操作

bash 复制代码
SysUserVo vo = new SysUserVo();
// 解密信息
Optional.ofNullable(user)
		.ifPresent(TypeHandler::decrypt);
// 拷贝属性
BeanUtils.copyProperties(user, vo);

或者
UserInfo userInfo = new UserInfo();
		// 解密
		TypeHandler.decrypt(sysUser);
		// 设置用户信息
		userInfo.setSysUser(sysUser);
分页查询
public IPage<SysUserVo> getUsersWithRolePage(Page<?> page, SysUserDto dto) {
		TypeHandler.encryptField(dto, SysUserDto::getUsername, SysUserDto::setUsername);
		TypeHandler.encryptField(dto, SysUserDto::getPhone, SysUserDto::setPhone);
		return baseMapper.getUsersWithRolePage(page, dto, DataScope.of());
	}
/**
	 * 根据用户名获取用户列表
	 * @param username
	 * @return
	 */
	@Override
	public List<SysUser> getUserListByUserName(String username) {
		// 1. 查询用户列表
		List<SysUser> userList = baseMapper.selectList(
				Wrappers.<SysUser>lambdaQuery()
						.like(SysUser::getUsername, TypeHandler.encryptText(username))
		);
		// 2. 批量解密(如果查询结果不为空)
		Optional.ofNullable(userList)
				.filter(list -> !list.isEmpty())
				.ifPresent(list -> list.forEach(TypeHandler::decrypt));
		// 3. 返回解密后的列表
		return userList;
	}

说明:

  • 插入/更新时:自动将明文加密为 Base64 密文存入数据库
  • 查询时:自动将数据库密文解密为明文返回

3.2 XML 映射文件配置

<result><id> 标签中指定 typeHandler

xml 复制代码
<resultMap id="BaseResultMap" type="com.cqcloud.platform.entity.User">
    <id column="id" property="id" />
    <result column="user_name" property="username" 
            typeHandler="com.cqcloud.platform.utils.TypeHandler"/>
    <result column="phone" property="phone" 
            typeHandler="com.cqcloud.platform.utils.TypeHandler"/>
    <result column="email" property="email" 
            typeHandler="com.cqcloud.platform.utils.TypeHandler"/>
</resultMap>

<!-- 插入时也需要指定 typeHandler -->
<insert id="insert">
    INSERT INTO user (user_name, phone, email)
    VALUES (
        #{username, typeHandler=com.cqcloud.platform.utils.TypeHandler},
        #{phone, typeHandler=com.cqcloud.platform.utils.TypeHandler},
        #{email, typeHandler=com.cqcloud.platform.utils.TypeHandler}
    )
</insert>

3.3 查询示例

java 复制代码
@Mapper
public interface UserMapper {
    
    // 查询时会自动解密
    User selectById(@Param("id") Long id);
    
    // 插入时会自动加密
    int insert(User user);
    
    // 更新时会自动加密
    int updateById(User user);
}

无需手动调用任何加解密方法,MyBatis 会自动处理。


四、手动加解密工具方法

除了 MyBatis 自动处理外,TypeHandler 还提供了手动加解密的静态工具方法。

4.1 单个字符串加解密

java 复制代码
// 加密
String encrypted = TypeHandler.encryptText("13800138000");
System.out.println(encrypted); // 5nJgY3X... (Base64密文)

// 解密(MyBatis查询时自动执行,一般无需手动调用)
// String decrypted = Sm4Utils.decryptFromBase64(encrypted, SM4_KEY);

4.2 对象字段批量解密

java 复制代码
// 从数据库查询出的对象,字段已是明文,通常不需要手动解密
User user = userMapper.selectById(1L);

// 但如果你直接从 ResultSet 或缓存中拿到的是密文对象,可以:
TypeHandler.decrypt(user); // 使用默认字段解密

// 或指定字段解密
TypeHandler.decrypt(user, "username", "phone");

// 支持带 @ 前缀的特殊格式(如 "email@密文")
// 解密后为 "email@明文"

默认解密字段列表:

java 复制代码
username, phone, nickname, realName, name, cardNo, email, 
wxOpenid, miniOpenid, ykbTalkOpenid, dingTalkOpenid

4.3 对象字段批量加密

java 复制代码
// 新增用户,手动加密(通常由 MyBatis 自动处理,特殊场景使用)
User user = new User();
user.setUsername("张三");
user.setPhone("13800138000");

TypeHandler.encrypt(user); // 使用默认字段加密

// 或指定字段加密
TypeHandler.encrypt(user, "username", "phone");

userMapper.insert(user); // 此时字段已是密文

注意: 如果实体类配置了 @TableField(typeHandler = TypeHandler.class)无需手动调用 encrypt(),MyBatis 会在执行 SQL 时自动加密。


4.4 函数式编程方式加解密

java 复制代码
// 灵活指定 getter/setter 进行加密
TypeHandler.encryptField(user, 
    User::getUsername,   // 获取原始值
    User::setUsername    // 设置加密值
);

五、@前缀特殊处理机制

处理器支持带前缀的加密存储格式,适用于需要保留标识符的场景。

5.1 存储格式

数据库存储格式:前缀@密文

例如邮箱字段:

复制代码
加密前:weimeilayer@gmail.com
加密后:weimeilayer@5nJgY3XzF8q...

5.2 解密行为

  • 自动识别 @ 符号 :保留 @ 之前的内容作为前缀
  • 仅解密 @ 之后的部分
  • 最终结果:前缀@明文

5.3 使用场景

java 复制代码
// 插入时自动加密
user.setEmail("weimeilayer@gmail.com");
userMapper.insert(user);
// 数据库存储: "weimeilayer@gmail.com" → "weimeilayer@5nJgY3X..."

// 查询时自动解密
User user = userMapper.selectById(1L);
System.out.println(user.getEmail()); 
// 输出: weimeilayer@gmail.com

注意: 此机制仅在 decryptField() 方法中生效。手动调用 encryptField() 时,不会添加 @ 前缀,直接存储纯密文。


六、常见问题

❓ 1. 插入时没有自动加密

  • 检查实体字段是否添加 @TableField(typeHandler = TypeHandler.class)
  • 检查 MyBatis 配置是否正确扫描了 TypeHandler

❓ 2. 查询时返回的字段仍是密文

  • 检查 resultMap 是否配置了 typeHandler
  • 确认数据库存储的确实是密文

❓ 3. 加密/解密失败

  • 确认 CommonConstants.SM4_PRIVATE_KEY 已正确配置
  • 密钥是原始字符串,不是 MD5 值(Sm4Utils 内部会自动 MD5)
  • 检查待加密/解密字符串是否为 null 或空字符串

❓ 4. 依赖冲突

  • 确保 ylc-rpamis-spring-boot-starter 版本为 1.0.3 或以上
  • 检查是否与其他加密库存在冲突

七、安全建议

  1. 密钥管理SM4_PRIVATE_KEY 不应硬编码在代码中,建议通过配置中心或环境变量注入
  2. 字段选择:仅对必要的敏感字段进行加解密,避免性能损耗
  3. 索引问题:加密字段无法直接使用数据库索引,如需查询请考虑其他方案(如密文索引、Hash 字段等)

八、完整示例代码

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public void addUser(User user) {
        // ✅ MyBatis 自动加密(字段上有 @TableField(typeHandler))
        userMapper.insert(user);
    }
    
    public User getUser(Long id) {
        // ✅ MyBatis 自动解密
        return userMapper.selectById(id);
    }
    
    public void batchDecrypt(List<User> users) {
        // ⚠️ 特殊场景手动解密(如从 Redis 缓存中取出)
        users.forEach(TypeHandler::decrypt);
    }
}

central https://central.sonatype.com/repository/maven-snapshots ---

总结: 只需添加依赖并在实体字段或 XML 中配置 typeHandler,即可实现全自动的字段级加解密,无需任何业务代码侵入。手动加解密方法主要用于特殊场景或批量处理。

相关推荐
皮皮林5519 小时前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
用户908324602733 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840824 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解4 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解4 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记4 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者5 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840825 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解5 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者6 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq