自己动手编写一个Mybatis插件之Mybatis脱敏插件
1.前言
在日常开发中,身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机。但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一样,实际上不能是真的。我以前的公司就因为不重视脱敏,一名员工在离职的时候通过后台的导出功能导出了核心的客户资料卖给了竞品,给公司造成了重大的损失。当然这里有数据管理的原因,但是脱敏仍旧是不可忽略的一环,脱敏可以从一定程度上保证数据的合规使用。下面就是一份经过脱敏的数据:
2.Mybatis脱敏插件
最近在研究Mybatis的插件,所以考虑能不能在ORM中搞一搞脱敏,所以就尝试了一下,这里分享一下思路。借此也分享一下Mybatis插件开发的思路。
2.1Mybatis插件接口
Mybatis中使用插件,需要实现接口org.apache.ibatis.plugin.Interceptor,如下所示:
publicinterfaceInterceptor{ Objectintercept(Invocationinvocation)throwsThrowable; defaultObjectplugin(Objecttarget){ returnPlugin.wrap(target,this); } defaultvoidsetProperties(Propertiesproperties){ //NOP } }
这里其实最核心的是Objectintercept(Invocationinvocation)方法,这是我们需要实现的方法。
2.2Invocation对象
那么核心方法中的Invocation是个什么概念呢?
publicclassInvocation{ privatefinalObjecttarget; privatefinalMethodmethod; privatefinalObject[]args; publicInvocation(Objecttarget,Methodmethod,Object[]args){ this.target=target; this.method=method; this.args=args; } publicObjectgetTarget(){ returntarget; } publicMethodgetMethod(){ returnmethod; } publicObject[]getArgs(){ returnargs; } publicObjectproceed()throwsInvocationTargetException,IllegalAccessException{ returnmethod.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.5MetaObject
Mybatis提供了一个工具类org.apache.ibatis.reflection.MetaObject。它通过反射来读取和修改一些重要对象的属性。我们可以利用它来处理四大对象的一些属性,这是Mybatis插件开发的一个常用工具类。
- ObjectgetValue(Stringname)根据名称获取对象的属性值,支持OGNL表达式。
- voidsetValue(Stringname,Objectvalue)设置某个属性的值。
- Class>getSetterType(Stringname)获取setter方法的入参类型。
- Class>getGetterType(Stringname)获取getter方法的返回值类型。
通常我们使用SystemMetaObject.forObject(Objectobject)来实例化MetaObject对象。你会在接下来的实战DEMO中看到我使用它。
3.Mybatis脱敏插件实战
接下来我就把开头的脱敏需求实现一下。首先需要对脱敏字段进行标记并确定使用的脱敏策略。
编写脱敏函数:
/** *具体策略的函数 *@authorfelord.cn *@since11:24 **/ publicinterfaceDesensitizerextendsFunction{ }
编写脱敏策略枚举:
/** *脱敏策略. * *@authorfelord.cn *@since11:25 */ publicenumSensitiveStrategy{ /** *Usernamesensitivestrategy. */ USERNAME(s->s.replaceAll("(\\S)\\S(\\S*)","$1*$2")), /** *Idcardsensitivetype. */ ID_CARD(s->s.replaceAll("(\\d{4})\\d{10}(\\w{4})","$1****$2")), /** *Phonesensitivetype. */ PHONE(s->s.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2")), /** *Addresssensitivetype. */ ADDRESS(s->s.replaceAll("(\\S{8})\\S{4}(\\S*)\\S{4}","$1****$2****")); privatefinalDesensitizerdesensitizer; SensitiveStrategy(Desensitizerdesensitizer){ this.desensitizer=desensitizer; } /** *Getsdesensitizer. * *@returnthedesensitizer */ publicDesensitizergetDesensitizer(){ returndesensitizer; } }
编写脱敏字段的标记注解:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public@interfaceSensitive{ SensitiveStrategystrategy(); }
我们的返回对象中如果某个字段需要脱敏,只需要通过标记就可以了。例如下面这样:
@Data publicclassUserInfo{ privatestaticfinallongserialVersionUID=-8938650956516110149L; privateLonguserId; @Sensitive(strategy=SensitiveStrategy.USERNAME) privateStringname; privateIntegerage; }
然后就是编写插件了,我可以确定的是需要拦截的是ResultSetHandler对象的handleResultSets方法,我们只需要实现插件接口Interceptor并添加签名就可以了。全部逻辑如下:
@Slf4j @Intercepts(@Signature(type=ResultSetHandler.class, method="handleResultSets", args={Statement.class})) publicclassSensitivePluginimplementsInterceptor{ @SuppressWarnings("unchecked") @Override publicObjectintercept(Invocationinvocation)throwsThrowable{ List
然后配置脱敏插件使之生效:
@Bean publicSensitivePluginsensitivePlugin(){ returnnewSensitivePlugin(); }
操作查询获得结果UserInfo(userId=123123,name=李*龙,age=28),成功将指定字段进行了脱敏。
补充一句,其实脱敏也可以在JSON序列化的时候进行。
4.总结
今天对编写Mybatis插件的一些要点进行了说明,同时根据说明实现了一个脱敏插件。但是请注意一定要熟悉四大对象的生命周期,否则自写插件可能会造成意想不到的结果。
到此这篇关于自己动手编写一个Mybatis插件之Mybatis脱敏插件的文章就介绍到这了,更多相关Mybatis脱敏插件内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。