基于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,即可实现全自动的字段级加解密,无需任何业务代码侵入。手动加解密方法主要用于特殊场景或批量处理。

相关推荐
星空彼岸0072 小时前
SA-Token在SpringBoot中的实战指南
java·spring boot·后端
闻哥3 小时前
ConcurrentHashMap 1.7 源码深度解析:分段锁的设计与实现
java·开发语言·jvm·spring boot·面试·jdk·hash
哈库纳玛塔塔3 小时前
dbVisitor 统一数据库访问库,更新 v6.7.0,面向 AI 支持向量操作
数据库·spring boot·orm
xdpcxq10293 小时前
EF Core实体追踪Entry中记录的数据
服务器·数据库·oracle
csdn2015_4 小时前
mybatisplus自动生成id
java·mybatis
大模型玩家七七5 小时前
关系记忆不是越完整越好:chunk size 的隐性代价
java·前端·数据库·人工智能·深度学习·算法·oracle
一 乐5 小时前
林业资源管理|基于java + vue林业资源管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·林业资源管理系统
前路不黑暗@6 小时前
Java项目:Java脚手架项目的模板服务和网关服务的实现(三)
java·开发语言·spring boot·git·学习·spring cloud·maven
远方16096 小时前
114-Oracle Database 26ai在Oracle Linux 9上的OUI图形界面安装
linux·服务器·数据库·sql·oracle·database