自己动手编写一个Mybatis插件之Mybatis脱敏插件

1. 前言

在日常开发中,身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机。但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一样,实际上不能是真的。我以前的公司就因为不重视脱敏,一名员工在离职的时候通过后台的导出功能导出了核心的客户资料卖给了竞品,给公司造成了重大的损失。当然这里有数据管理的原因,但是脱敏仍旧是不可忽略的一环,脱敏可以从一定程度上保证数据的合规使用。下面就是一份经过脱敏的数据:

2. Mybatis 脱敏插件

最近在研究Mybatis的插件,所以考虑能不能在ORM中搞一搞脱敏,所以就尝试了一下,这里分享一下思路。借此也分享一下Mybatis插件开发的思路。

2.1 Mybatis 插件接口

Mybatis中使用插件,需要实现接口org.apache.ibatis.plugin.Interceptor,如下所示:

public interface Interceptor {

 Object intercept(Invocation invocation) throws Throwable;

 default Object plugin(Object target) {
 return Plugin.wrap(target, this);
 }

 default void setProperties(Properties properties) {
 // NOP
 }

}

这里其实最核心的是Object intercept(Invocation invocation)方法,这是我们需要实现的方法。

2.2 Invocation 对象

那么核心方法中的Invocation 是个什么概念呢?

public class Invocation {

 private final Object target;
 private final Method method;
 private final Object[] args;

 public Invocation(Object target, Method method, Object[] args) {
 this.target = target;
 this.method = method;
 this.args = args;
 }

 public Object getTarget() {
 return target;
 }

 public Method getMethod() {
 return method;
 }

 public Object[] getArgs() {
 return args;
 }

 public Object proceed() throws InvocationTargetException, IllegalAccessException {
 return method.invoke(target, args);
 }

}

这个东西包含了四个概念:

  • target 拦截的对象
  • method 拦截target中的具体方法,也就是说Mybatis插件的粒度是精确到方法级别的。
  • args 拦截到的参数。
  • proceed 执行被拦截到的方法,你可以在执行的前后做一些事情。

2.3 拦截签名

既然我们知道了Mybatis插件的粒度是精确到方法级别的,那么疑问来了,插件如何知道轮到它工作了呢?

所以Mybatis设计了签名机制来解决这个问题,通过在插件接口上使用注解@Intercepts标注来解决这个问题。

@Intercepts(@Signature(type = ResultSetHandler.class,
  method = "handleResultSets",
  args = {Statement.class})

就像上面一样,事实上就等于配置了一个Invocation

2.4 插件的作用域

那么问题又来了,Mybatis插件能拦截哪些对象,或者说插件能在哪个生命周期阶段起作用呢?它可以拦截以下四大对象:

  • Executor 是SQL执行器,包含了组装参数,组装结果集到返回值以及执行SQL的过程,粒度比较粗。
  • StatementHandler 用来处理SQL的执行过程,我们可以在这里重写SQL非常常用。
  • ParameterHandler 用来处理传入SQL的参数,我们可以重写参数的处理规则。
  • ResultSetHandler 用于处理结果集,我们可以重写结果集的组装规则。

你需要做的就是明确的你的业务需要在上面四个对象的哪个处理阶段拦截处理即可。

2.5 MetaObject

Mybatis提供了一个工具类org.apache.ibatis.reflection.MetaObject。它通过反射来读取和修改一些重要对象的属性。我们可以利用它来处理四大对象的一些属性,这是Mybatis插件开发的一个常用工具类。

  • Object getValue(String name) 根据名称获取对象的属性值,支持OGNL表达式。
  • void setValue(String name, Object value) 设置某个属性的值。
  • Class<?> getSetterType(String name) 获取setter方法的入参类型。
  • Class<?> getGetterType(String name) 获取getter方法的返回值类型。

通常我们使用SystemMetaObject.forObject(Object object)来实例化MetaObject对象。你会在接下来的实战DEMO中看到我使用它。

3. Mybatis 脱敏插件实战

接下来我就把开头的脱敏需求实现一下。首先需要对脱敏字段进行标记并确定使用的脱敏策略。

编写脱敏函数:

/**
 * 具体策略的函数
 * @author felord.cn
 * @since 11:24
 **/
public interface Desensitizer extends Function<String,String> {

}

编写脱敏策略枚举:

/**
 * 脱敏策略.
 *
 * @author felord.cn
 * @since 11 :25
 */
public enum SensitiveStrategy {
 /**
  * Username sensitive strategy.
  */
 USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
 /**
  * Id card sensitive type.
  */
 ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
 /**
  * Phone sensitive type.
  */
 PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),

 /**
  * Address sensitive type.
  */
 ADDRESS(s -> s.replaceAll("(\\S{8})\\S{4}(\\S*)\\S{4}", "$1****$2****"));

 private final Desensitizer desensitizer;

 SensitiveStrategy(Desensitizer desensitizer) {
  this.desensitizer = desensitizer;
 }

 /**
  * Gets desensitizer.
  *
  * @return the desensitizer
  */
 public Desensitizer getDesensitizer() {
  return desensitizer;
 }
}

编写脱敏字段的标记注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sensitive {
 SensitiveStrategy strategy();
}

我们的返回对象中如果某个字段需要脱敏,只需要通过标记就可以了。例如下面这样:

@Data
public class UserInfo {

 private static final long serialVersionUID = -8938650956516110149L;
 private Long userId;
 @Sensitive(strategy = SensitiveStrategy.USERNAME)
 private String name;
 private Integer age;
}

然后就是编写插件了,我可以确定的是需要拦截的是ResultSetHandler对象的handleResultSets方法,我们只需要实现插件接口Interceptor并添加签名就可以了。全部逻辑如下:

@Slf4j
@Intercepts(@Signature(type = ResultSetHandler.class,
  method = "handleResultSets",
  args = {Statement.class}))
public class SensitivePlugin implements Interceptor {
 @SuppressWarnings("unchecked")
 @Override
 public Object intercept(Invocation invocation) throws Throwable {
  List<Object> records = (List<Object>) invocation.proceed();
  // 对结果集脱敏
  records.forEach(this::sensitive);
  return records;
 }

 private void sensitive(Object source) {
  // 拿到返回值类型
  Class<?> sourceClass = source.getClass();
  // 初始化返回值类型的 MetaObject
  MetaObject metaObject = SystemMetaObject.forObject(source);
  // 捕捉到属性上的标记注解 @Sensitive 并进行对应的脱敏处理
  Stream.of(sourceClass.getDeclaredFields())
    .filter(field -> field.isAnnotationPresent(Sensitive.class))
    .forEach(field -> doSensitive(metaObject, field));
 }

 private void doSensitive(MetaObject metaObject, Field field) {
  // 拿到属性名
  String name = field.getName();
  // 获取属性值
  Object value = metaObject.getValue(name);
  // 只有字符串类型才能脱敏 而且不能为null
  if (String.class == metaObject.getGetterType(name) && value != null) {
   Sensitive annotation = field.getAnnotation(Sensitive.class);
   // 获取对应的脱敏策略 并进行脱敏
   SensitiveStrategy type = annotation.strategy();
   Object o = type.getDesensitizer().apply((String) value);
   // 把脱敏后的值塞回去
   metaObject.setValue(name, o);
  }
 }
}

然后配置脱敏插件使之生效:

@Bean
public SensitivePlugin sensitivePlugin(){
 return new SensitivePlugin();
}

操作查询获得结果 UserInfo(userId=123123, name=李*龙, age=28) ,成功将指定字段进行了脱敏。

补充一句,其实脱敏也可以在JSON序列化的时候进行。

4. 总结

今天对编写Mybatis插件的一些要点进行了说明,同时根据说明实现了一个脱敏插件。但是请注意一定要熟悉四大对象的生命周期,否则自写插件可能会造成意想不到的结果。

到此这篇关于自己动手编写一个Mybatis插件之Mybatis脱敏插件的文章就介绍到这了,更多相关Mybatis脱敏插件内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java简单实现SpringMVC+MyBatis分页插件

    1.封装分页Page类 package com.framework.common.page.impl; import java.io.Serializable; import com.framework.common.page.IPage; /** * * * */ public abstract class BasePage implements IPage, Serializable { /** * */ private static final long serialVersionUID

  • Mybatis分页插件PageHelper的使用详解

    1.说明 如果你也在用Mybatis,建议尝试该分页插件,这个一定是最方便使用的分页插件. 该插件目前支持Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库分页. 2.使用方法 第一步:在Mybatis配置xml中配置拦截器插件: <plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pageh

  • SpringBoot集成MyBatis的分页插件PageHelper实例代码

    昨天给各位总结了本人学习springboot整合mybatis第一阶段的一些学习心得和源码,主要就算是敲了一下SpringBoot的门儿,希望能给各位的入门带给一点儿捷径,今天给各位温习一下MyBatis的分页插件PageHelper和SpringBoot的集成,它的使用也非常简单,开发更为高效.因为PageHelper插件是属于MyBatis框架的,所以相信很多哥们儿都已经用烂了,下面带着各位吃一下回头草. 首先说说MyBatis框架的PageHelper插件吧,它是一个非常好用的分页插件,通

  • 自己动手写的mybatis分页插件(极其简单好用)

    刚开始项目,需要用到mybatis分页,网上看了很多插件,其实实现原理基本都大同小异,但是大部分都只给了代码,注释不全,所以参考了很多篇文章(每篇文章偷一点代码,评出来自己的,半抄袭),才自己模仿着写出了一个适合自己项目的分页插件,话不多说,直接上代码,相比大部分文章,注释算很完整了 最重要的拦截器 package com.dnkx.interceptor; import java.sql.*; import java.util.HashMap; import java.util.Propert

  • mybatis分页插件pageHelper详解及简单实例

    mybatis分页插件pageHelper详解及简单实例 工作的框架spring springmvc mybatis3 首先使用分页插件必须先引入maven依赖,在pom.xml中添加如下 <!-- 分页助手 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>3.7.5

  • 详解MyBatis自定义Plugin插件

    作用 官方说明: MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用. 什么意思呢?就是你可以对执行某些方法之前进行拦截,做自己的一些操作,如: 1.记录所有执行的SQL(通过对 MyBatis org.apache.ibatis.executor.statement.StatementHandler 中的prepare 方法进行拦截) 2.修改SQL(org.apache.ibatis.executor.Executor中query方法进行拦截)等. 但拦截的方法调用有限制,My

  • Mybatis常用分页插件实现快速分页处理技巧

    在未分享整个查询分页的执行代码之前,先了解一下执行流程. 1.总体上是利用mybatis的插件拦截器,在sql执行之前拦截,为查询语句加上limit X X 2.用一个Page对象,贯穿整个执行流程,这个Page对象需要用Java编写前端分页组件 3.用一套比较完整的三层entity,dao,service支持这个分页架构 4.这个分页用到的一些辅助类 注:分享的内容较多,这边的话我就不把需要的jar一一列举,大家使用这个分页功能的时候缺少什么就去晚上找什么jar包即可,尽可能用maven包导入

  • 使用mybatis插件PageHelper实现分页效果

    最近都在忙着写一个网站项目,今天做一个分页功能的时候,遇到了分页效果实现不了的问题,查了好久的资料,后来终于是成功解决啦,记录一下~ 1.在pom.xml中添加分页插件依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.5</version> </depend

  • 自己动手编写一个Mybatis插件之Mybatis脱敏插件

    1. 前言 在日常开发中,身份证号.手机号.卡号.客户号等个人信息都需要进行数据脱敏.否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机.但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一样,实际上不能是真的.我以前的公司就因为不重视脱敏,一名员工在离职的时候通过后台的导出功能导出了核心的客户资料卖给了竞品,给公司造成了重大的损失.当然这里有数据管理的原因,但是脱敏仍旧是不可忽略的一环,脱敏可以从一定程度上保证数据的合规使用.下面就是一份经过脱敏的数据: 2. Mybatis 脱敏插

  • intellij idea中安装、配置mybatis插件Free Mybatis plugin的教程详解

    场景: 使用intellij idea开发,持久层dao使用了mybatis,经常需要编辑mybatis的××Mapper.java和××Mapper.xml,因为是接口里一个方法对应xml里的一个SQL的id,当需要找找个方法时候得拷贝找个方法名,然后在对应文件中ctrl+f全文查找,相当麻烦.本篇讲述的使用mybatis的插件后将极大的提高效率.效果如图: 即从××Mapper.java接口和××Mapper.xml中能由箭头直接点进去查看相对应的方法及SQL. 步骤: 1.ctrl+alt

  • Mybatis generator自动生成代码插件实例解析

    mybatis自动生成代码(实体类.Dao接口等)是很成熟的了,就是使用mybatis-generator插件. 它是一个开源的插件,使用maven构建最好,可以很方便的执行 插件官方简介: http://www.mybatis.org/generator/index.html 插件的GitHub地址: https://github.com/mybatis/generator 如何使用mybatis-generator插件呢?只需要三步: 1.修改pom.xml配置文件 网上大部分说法都要添加依

  • IDEA插件之Mybatis Log plugin 破解及安装方法

    前言 今天重新装了IDEA2020,顺带重装了一些插件,毕竟这些插件都是习惯一直在用,其中一款就是Mybatis Log plugin,按照往常的思路,在IDEA插件市场搜索安装,艹,眼睛一瞟,竟然收费了,对于我这种支持盗版的人来说太难了,于是自己开始捣鼓各种尝试破解,下文分享自己的破解方式. 什么是Mybatis Log plugin 举个栗子,通常在找bug的时候都会查看执行了什么SQL,想把这条SQL拼接出来执行调试,可能有些小白还在傻傻的把各个参数复制出来,补到?占位符中,哈哈. 简单的

  • mybatis 自定义实现拦截器插件Interceptor示例

    首先熟悉一下Mybatis的执行过程,如下图: 类型 先说明Mybatis中可以被拦截的类型具体有以下四种: 1.Executor:拦截执行器的方法. 2.ParameterHandler:拦截参数的处理. 3.ResultHandler:拦截结果集的处理. 4.StatementHandler:拦截Sql语法构建的处理. 规则 Intercepts注解需要一个Signature(拦截点)参数数组.通过Signature来指定拦截哪个对象里面的哪个方法.@Intercepts注解定义如下: @D

  • IDEA 使用mybatis插件Free Mybatis plugin的步骤(推荐)

    1.打开idea -> file -> settings ->Plugins 搜索Free Mybatis plugin,然后install,完成之后重启idea即可. 2.打开idea -> 右侧database-> 配置数据库连接 -> 右击数据库表 在需要生成配置文件的数据库上右键,就会出现mybatis-generator选项如图 3.打开如上图所示配置窗口,这里我们使用默认的就行,也可以选择自己需要的路径生成.如果不想使用lombok去掉这个勾选即可,然后我们

  • Mybatis源码分析之插件模块

    Mybatis插件模块 插件这个东西一般用的比较少,就算用的多的插件也算是PageHelper分页插件: PageHelper官网:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md 官网上这个也有谈到Mybatis的插件流程分析. 使用示例 插件类 记录SQL执行的时间, 1.在JDK8之前必须实现Interceptor接口中的三个方法,在JDK8之后只需要实现intercept方法即可: 2.加上

  • Spring mvc整合mybatis(crud+分页插件)操作mysql

    一.web.xml配置 我们都知道java ee的项目启动的第一件事就是读取web.xml,spring mvc 的web.xml我在上一篇文章中也做了详细讲解,不懂的可以回头看看,讲解的这个项目源码我也会放到github上,也可以去那里看看,这里就不做介绍了. web.xml 配置 <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/c

  • 用Maven插件生成Mybatis代码的实现方法

    现在代码管理基本上是采用Maven管理,Maven的好处此处不多说,大家用百度搜索会有很多介绍,本文介绍一下用Maven工具如何生成Mybatis的代码及映射的文件. 一.配置Maven pom.xml 文件 在pom.xml增加以下插件: <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId>

  • 详解使用webpack打包编写一个vue-toast插件

    本文介绍了使用webpack打包编写一个vue插件,分享给大家.具体如下: 一.说明: 需求:创建一个toast插件 思路:利用vue组件创建模板,使用webpack打包生成插件再全局使用. # 项目目录: |_ package.json |_ webpack.config.js |_ .babelrc |_ dist |_ src |_ index.html |_ lib |_ index.js |_ vue-toast.vue 1.1 webpack基础 1.基础插件 - html-webp

随机推荐