Java - MyBatis-Plus 数据库字段 自动加密、解密
自定义 TypeHandler(简单稳定)
注意:如果发现没标记的字段也加密了。
检查一下,是不是有下面这种配置了扫描包,多个 handler 造成了冲突,如果这样,可以移到其它 package 下。
mybatis-plus:
type-handlers-package: com.vipsoft.base.handler
这是 MyBatis 官方推荐的字段级处理方式,MyBatis-Plus 完美支持,只需在字段上标注即可,零配置、零侵入。
1. 编写加密工具类(示例用 AES,密钥请放在配置中心)
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
public class CryptoUtil {
// 实际请从 application.yml 或配置中心获取,切勿硬编码!
private static final String KEY = "your-16-char-key";
public static String encrypt(String data) {
// 这里用你的加密逻辑(AES/SM4等)
AES aes = SecureUtil.aes(key.getBytes());
// 加密为16进制表示
return aes.encryptHex(content);
}
public static String decrypt(String data) {
try{
// 构建AES对象
AES aes = SecureUtil.aes(key.getBytes());
// 解密字符串
return aes.decryptStr(encryptStr);
}catch (Exception e){
e.printStackTrace();
return encryptStr;
}
}
}
2. 自定义 TypeHandler(继承 BaseTypeHandler)
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CryptoTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
// 存入数据库时:加密
ps.setString(i, CryptoUtil.encrypt(parameter));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 从数据库取出时:解密
String value = rs.getString(columnName);
return value == null ? null : CryptoUtil.decrypt(value);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
return value == null ? null : CryptoUtil.decrypt(value);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return value == null ? null : CryptoUtil.decrypt(value);
}
}
3. 在实体类中直接使用
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
@TableName(value = "sys_user", autoResultMap = true) //要加 autoResultMap = true 不然取出来的时候,不解密
public class UserInfo implements Serializable {
private String username;
private String password;
// 核心:指定 typeHandler
@TableField(typeHandler = CryptoTypeHandler.class)
private String phone;
// getter / setter ...
}
如果有 Mapper.xml 要加
<resultMap id="BaseResultMap" type="com.vipsoft.base.entity.SysUser" >
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="phone_no" property="phoneNo" jdbcType="VARCHAR" typeHandler="com.vipsoft.base.handler.CryptoTypeHandler"/>
</resultMap>
优点:
- 极度简洁,只影响该字段。
- 支持
Insert、Update、Select全场景(包括QueryWrapper条件查询,只要你传入的是明文,它也会自动加密后作为条件)。 - 无需额外配置,自动生效。
直接复制上面的方案一代码,替换你的加密逻辑,重启项目即可。保存时 phone 自动加密存储,查询时自动解密成明文,Service 层完全无感知。
⚠️ 安全提醒:无论哪种方案,加密密钥务必放在
application.yml或配置中心(如 Apollo、Nacos),配合@Value注入,或者通过环境变量设值,绝对不要硬编码在 Java 类中。
SET block_encryption_mode = 'aes-256-ecb';
加密
select phone_no, HEX(AES_ENCRYPT(phone_no,'your-16-char-key')) AS decrypted_data from sys_user;
解密
select phone_no, AES_DECRYPT(UNHEX(phone_no),'your-16-char-key') AS decrypted_data from sys_user;
本文来自博客园,作者:VipSoft 转载请注明原文链接:https://www.cnblogs.com/vipsoft/p/22041068
浙公网安备 33010602011771号