MyBatis插件可通过拦截ParameterHandler(写入前加密)和ResultSetHandler(查询后解密)实现敏感字段自动加解密;需定义@Sensitive注解标记字段,编写对应拦截器递归处理POJO/Map/List,结合配置中心管理密钥并保证幂等性。

MyBatis 插件拦截器可以拦截 Executor、StatementHandler、ParameterHandler 和 ResultSetHandler 四类对象的方法调用,其中最常用且适合做敏感字段加解密的是 ParameterHandler(写入前加密)和 ResultSetHandler(查询后解密)。
一、定义加解密规则与注解
先定义一个自定义注解,标记实体类中需要加解密的字段:
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Sensitive {
String algorithm() default "AES"; // 加解密算法
String keyProperty() default "secretKey"; // 密钥来源属性名(可选)
}
在实体类中使用:
public class User {
private Long id;
private String username;
@Sensitive(algorithm = "AES")
private String phone;
@Sensitive(algorithm = "AES")
private String idCard;
// getter/setter...
}
二、编写 ParameterHandler 拦截器(写入时自动加密)
拦截 ParameterHandler.setParameters() 方法,在参数绑定到 SQL 前对标注字段进行加密:
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 获取待执行的
MappedStatement,从中解析出参数对象(如 POJO 或 Map) - 递归遍历对象属性,找到所有带
@Sensitive注解的字段 - 对字段值调用统一加密工具(如 AES/SM4),替换原值
- 注意:若参数是 Map 类型,需按 key 匹配字段名;若为 List<POJO>,需遍历每个元素
三、编写 ResultSetHandler 拦截器(读取时自动解密)
拦截 ResultSetHandler.handleResultSets() 方法,在结果映射完成后对敏感字段解密:
- 获取查询返回的结果列表(通常是 List<Object>)
- 对每个对象,反射查找所有
@Sensitive字段 - 对字段当前值执行解密,并通过 setter 或 Unsafe 写回
- 推荐使用 setter(兼容性好),避免直接操作私有字段引发 SecurityManager 问题
四、注册插件并配置密钥管理
在 MyBatis 配置中注册两个插件(顺序无关,但建议 ParameterHandler 在前):
<plugins> <plugin interceptor="com.example.SensitiveParameterPlugin"/> <plugin interceptor="com.example.SensitiveResultPlugin"/> </plugins>
密钥不建议硬编码,应从配置中心或环境变量加载,例如:
- 使用 Spring 的
@Value("${cipher.aes.key}")注入密钥 - 支持密钥轮换:在注解中增加 version 属性,解密时根据 version 选择对应密钥
- 敏感字段加解密需保持幂等性,避免重复加解密(如已加密字段再被加密)
不复杂但容易忽略。

















