您的位置:首页 > 房产 > 家装 > mybatis、mybatis-plus插件开发,实现数据脱敏功能

mybatis、mybatis-plus插件开发,实现数据脱敏功能

2024/12/23 16:18:20 来源:https://blog.csdn.net/qq_41712271/article/details/140126598  浏览:    关键词:mybatis、mybatis-plus插件开发,实现数据脱敏功能

首先说一下mybatis中四大组件的作用,下面开发的插件拦截器会使用
四大组件Executor、StatementHandler、ParameterHandler、ResultSetHandler


Executor:

Executor 是 MyBatis 中的执行器,负责 SQL 语句的执行工作。它通过调度 StatementHandler、ParameterHandler 和 ResultSetHandler 来完成 SQL 的增删改查操作。Executor 管理事务和缓存,可以是 SimpleExecutor、ReuseExecutor、BatchExecutor 或在开启二级缓存时的 CachingExecutor。

ParameterHandler:

ParameterHandler 用于处理 SQL 语句的参数设置。它将 Mapper 接口方法的参数封装,并负责将这些参数值传递给 PreparedStatement,以便进行预编译和执行。ParameterHandler 通过 TypeHandler 接口完成 Java 类型到 JDBC 类型的转换。

ResultSetHandler:

ResultSetHandler 负责处理 SQL 执行后的返回结果集(ResultSet)。它将结果集转换并映射到 Java 对象,完成从数据库字段到 Java 实体属性的映射工作。ResultSetHandler 能够处理多种结果集的复杂映射关系。

StatementHandler:

StatementHandler 是 MyBatis 中的语句处理器,它是四大对象的核心,起到承上启下的作用。StatementHandler 负责使用 JDBC 的 Statement(包括 PreparedStatement 和 CallableStatement)执行实际的数据库操作。它通过调用 ParameterHandler 来设置 SQL 参数,并通过调用 ResultSetHandler 来处理查询结果。



实现思路:


1 首先我们需要对数据的结果集进行拦截,也就是说需要拦截这个接口的方法

2 得到数据返回的结果集后,对结果集转换成 List 进行遍历脱敏

3 脱敏的时候我们还需要判断一下哪些字段需要进行脱敏,这里我们定义注解来标识需要脱敏的字段(在这个注解里面可以定义一些脱敏策略,比如对手机号的脱敏规则、身份证的脱敏规则等等)

4 遍历的时候通过反射,获取所有属性

5 我这里的脱敏有三个条件

        a、必须带有 脱敏标识注解
        b、必须是 String 类型
        c、不得为空,这里直接使用工具类来判断 StringUtils.isEmpty()


6 脱敏条件达成后,就获取该注解上的 脱敏策略,根据脱敏策略 对属性进行脱敏

7 将脱敏后的结果重新设置到属性上


具体实现步骤


定义注解和不同的脱敏策略

import java.util.function.Function;//这里的Function是jdk8新特性,自己了解一哈子
//提示:传入一个函数执行
public interface Desensitizer extends Function<String,String> {}
//这里定义脱敏策略
public enum TuoMinStrategy {/*手机号*/PHONE(s->s.replaceAll("^(\\\\d{3})\\\\d{4}(\\\\d{4})$","$1****$2")),/*用户名 匹配中文全部替换*/USERNAME(s->s.replaceAll("[\\u4e00-\\u9fa5]","*"));private final Desensitizer desensitizer;TuoMinStrategy(Desensitizer d) {desensitizer = d;}public Desensitizer getDesensitizer() {return desensitizer;}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//作用于属性上
@Target(ElementType.FIELD)
//运行时生效
@Retention(RetentionPolicy.RUNTIME)
public @interface TuoMin {/*** 脱敏策略* @return*/TuoMinStrategy strategy();}

脱敏插件核心类
注意:注解中的属性,method和args不是硬背的,有技巧,如这个,
ResultSetHandler类,点进去,要拦截哪个方法,方法名直接复制,方法里的参数,直接copy 引用

import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.stream.Stream;@Component //需要放入到 ioc 容器中拦截器才会生效哦
//指定要拦截的目标方法的注解
//<h1>1、这个就是指定需要拦截的方法,这里我们指定拦截返回结果集的方法</h1>
@Intercepts(@Signature(type = ResultSetHandler.class,method = "handleResultSets",args= Statement.class))
public class TongMinPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {//<h1>2、得到数据返回的结果集,对结果集转换成 List<Object> 进行遍历脱敏</h1>List<Object> records = (List<Object>) invocation.proceed();System.out.println("records = " + records);// 遍历数据 调用 tuoMin 这个方法records.forEach(this::tuoMin);return records;}private void tuoMin(Object source) {Class<?> sourceClass = source.getClass();System.out.println("sourceClass = " + sourceClass);MetaObject metaObject = SystemMetaObject.forObject(source);//这个东东是 mybatis 提供的,通过这个玩意我们可以得到属性的值System.out.println("metaObject = " + metaObject);// 使用 stream 流/*** 1、得到所有属性* 2、筛选出带有 TuoMin.class 注解的属性* 3、调用doTuoMin方法将这些属性脱敏*/Stream.of(sourceClass.getDeclaredFields()).filter(field -> field.isAnnotationPresent(TuoMin.class)).forEach(field->doTuoMin(metaObject,field));}private void doTuoMin(MetaObject metaObject, Field field) {System.out.println("metaObject = " + metaObject);System.out.println("field = " + field);String name = field.getName();System.out.println("name = " + name);Object value = metaObject.getValue(name);//根据属性名得到属性值System.out.println("value = " + value);// 脱敏条件:必须为String类型,值不等于空if (String.class == metaObject.getGetterType(name) && StringUtils.hasText(value.toString())) {//获取脱敏策略TuoMin tuoMin = field.getAnnotation(TuoMin.class);System.out.println("tuoMin = " + tuoMin);TuoMinStrategy type = tuoMin.strategy();System.out.println("type = " + type);// 调用策略正则表达式脱敏,得到结果Object apply = type.getDesensitizer().apply((String) value);System.out.println("apply = " + apply);// 将脱敏后的结果重新设置到属性上metaObject.setValue(name,apply);}}}

3 在需要脱敏的pojo的字段上加上注解,如

@TableField(value = "title")
@TuoMin(strategy = TuoMinStrategy.USERNAME) //加上注解并指定脱敏策略
private String title;

测试,举例

脱敏前:
张三达美脱敏后:
张 * * 美


部分文字和代码引用博文
【MyBatis】脱敏插件_前端脱敏插件是什么-CSDN博客

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com