今天遇到个需求需要对现有的数据进行脱敏处理。于是简单研究了下。
其实拦截器对脱敏处理主要处理两种数据,一种是bean类型,一种是map类型。
普通的javabean利用注解+反射来处理,map的数据自己维护需要脱敏的key以及规则。bean类型是用mybatis以及mybatis-plus自动生成的SQL映射的;map类型是手写的返回map类型的SQL和mybatis-plus的返回map类型的数据。
1.主要代码如下:
1.注解
packagecn.xm.exam.mybatis;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)public @interfaceDesensitization {
DesensitionType type();
String[] attach()default "";
}
2.定义枚举脱敏规则
packagecn.xm.exam.mybatis;public enumDesensitionType {
PHONE("phone", "11位手机号", "^(\\d{3})\\d{4}(\\d{4})$", "$1****$2"),//ID_CARD("idCard", "16或者18身份证号", "^(\\d{4})\\d{8,10}(\\w{4})$",//"$1****$2"),
ID_CARD("idCard", "16或者18身份证号", "^(\\d{4})\\d{11,13}(\\w{1})$", "$1****$2"), BANK_CARD("bankCardNo", "银行卡号","^(\\d{4})\\d*(\\d{4})$", "$1****$2"), ADDRESS("addrss", "地址", "(?<=.{3}).*(?=.{3})", "*"), REAL_NAME("realName", "真实姓名", "(?<=.{1}).*(?=.{1})", "*"), EMAIL("email", "电子邮箱", "(\\w+)\\w{5}@(\\w+)","$1***@$2"), CUSTOM("custom", "自定义正则处理", ""), TRUNCATE("truncate", "字符串截取处理", "");privateString type;privateString describe;privateString[] regular;
DesensitionType(String type, String describe, String... regular) {this.type =type;this.describe =describe;this.regular =regular;
}publicString getType() {returntype;
}public voidsetType(String type) {this.type =type;
}publicString getDescribe() {returndescribe;
}public voidsetDescribe(String describe) {this.describe =describe;
}publicString[] getRegular() {returnregular;
}public voidsetRegular(String[] regular) {this.regular =regular;
}
}
3.增加mybatis拦截器
packagecn.xm.exam.mybatis;importjava.lang.reflect.Field;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.Collections;importjava.util.LinkedHashMap;importjava.util.List;importjava.util.Map;importjava.util.Properties;importjava.util.Set;importorg.apache.commons.collections.CollectionUtils;importorg.apache.commons.collections.MapUtils;importorg.apache.commons.lang3.ArrayUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.ibatis.cache.CacheKey;importorg.apache.ibatis.executor.Executor;importorg.apache.ibatis.mapping.BoundSql;importorg.apache.ibatis.mapping.MappedStatement;importorg.apache.ibatis.plugin.Interceptor;importorg.apache.ibatis.plugin.Intercepts;importorg.apache.ibatis.plugin.Invocation;importorg.apache.ibatis.plugin.Plugin;importorg.apache.ibatis.plugin.Signature;importorg.apache.ibatis.session.ResultHandler;importorg.apache.ibatis.session.RowBounds;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;
@SuppressWarnings({"rawtypes", "unchecked"})
@Intercepts({
@Signature(type= Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class}),
@Signature(type= Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), })public class DesensitizationInterceptor implementsInterceptor {private static final Logger logger = LoggerFactory.getLogger(DesensitizationInterceptor.class);private boolean desensitization = false;//脱敏
private static final Map desensitionMap = new LinkedHashMap<>();static{
initDensensitionMap();
}
@Overridepublic Object intercept(Invocation invocation) throwsThrowable {
Object result=invocation.proceed();//如果需要对结果脱敏,则执行
if(desensitization) {//先对Map进行处理
if (result != null && result instanceofMap) {return this.desensitizationMap(result);
}//处理集合
if (result instanceof ArrayList>) {
List> list = (ArrayList>) result;return this.desensitization(list);
}//处理单个bean
return this.desensitization(result);
}returnresult;
}private static voidinitDensensitionMap() {
desensitionMap.put("idCode", DesensitionType.ID_CARD);
desensitionMap.put("idCard", DesensitionType.ID_CARD);
desensitionMap.put("userIDCard", DesensitionType.ID_CARD);
desensitionMap.put("userIdCard", DesensitionType.ID_CARD);
desensitionMap.put("username", DesensitionType.REAL_NAME);
desensitionMap.put("address", DesensitionType.ADDRESS);
}/** 对map脱敏*/
privateObject desensitizationMap(Object result) {
Map mapResult=(Map) result;if(MapUtils.isEmpty(mapResult)) {returnmapResult;
}
Set keySet =mapResult.keySet();for(String key : keySet) {if(desensitionMap.containsKey(key)) {
DesensitionType desensitionType=desensitionMap.get(key);
String replacedVal= getReplacedVal(desensitionType, MapUtils.getString(mapResult, key), null);
mapResult.put(key, replacedVal);
}
}returnresult;
}privateList desensitization(List list) {if(CollectionUtils.isEmpty(list)) {returnCollections.emptyList();
}
Class cls= null;for(Object o : list) {//脱敏map,改变引用地址(根据静态配置脱敏)
if (o != null && o instanceofMap) {
o=desensitizationMap(o);continue;
}//脱敏bean(根据注解脱敏)
if (cls == null) {
cls=o.getClass();
}
o=desensitization(o);
}returnlist;
}
@OverridepublicObject plugin(Object target) {//TODO Spring bean 方式配置时,如果没有配置属性就不会执行下面的 setProperties//方法,就不会初始化,因此考虑在这个方法中做一次判断和初始化
return Plugin.wrap(target, this);
}/*** 用于在Mybatis配置文件中指定一些属性的,注册当前拦截器的时候可以设置一些属性*/@Overridepublic voidsetProperties(Properties properties) {
}privateObject desensitization(Object obj) {if (obj == null) {returnobj;
}
Class cls=obj.getClass();
Field[] objFields=cls.getDeclaredFields();if(ArrayUtils.isEmpty(objFields)) {returnobj;
}for(Field field : objFields) {if ("serialVersionUID".equals(field.getName())) {continue;
}
Desensitization desensitization= null;if (String.class !=field.getType()|| (desensitization = field.getAnnotation(Desensitization.class)) == null) {continue;
}try{
field.setAccessible(true);
String value= field.get(obj) != null ? field.get(obj).toString() : null;if(StringUtils.isBlank(value)) {continue;
}
value=getReplacedVal(desensitization.type(), value, desensitization.attach());
field.set(obj, value);
}catch(Exception ignore) {
ignore.printStackTrace();
}
}returnobj;
}privateString getReplacedVal(DesensitionType type, String value, String[] attachs) {
List regular = null;switch(type) {caseCUSTOM:
regular=Arrays.asList(attachs);break;caseTRUNCATE:
regular=truncateRender(attachs);break;default:
regular=Arrays.asList(type.getRegular());
}if (regular != null && regular.size() > 1) {
String match= regular.get(0);
String result= regular.get(1);if (null != match && result != null && match.length() > 0) {
value=((String) value).replaceAll(match, result);returnvalue;
}
}return "";
}private ListtruncateRender(String[] attachs) {
List regular = new ArrayList<>();if (null != attachs && attachs.length > 1) {
String rule= attachs[0];
String size= attachs[1];
String template, result;if ("0".equals(rule)) {
template= "^(\\S{%s})(\\S+)$";
result= "$1";
}else if ("1".equals(rule)) {
template= "^(\\S+)(\\S{%s})$";
result= "$2";
}else{returnregular;
}try{if (Integer.parseInt(size) > 0) {
regular.add(0, String.format(template, size));
regular.add(1, result);
}
}catch(Exception e) {
logger.warn("ValueDesensitizeFilter truncateRender size {} exception", size);
}
}returnregular;
}public booleanisDesensitization() {returndesensitization;
}public void setDesensitization(booleandesensitization) {this.desensitization =desensitization;
}
}
解释:
(1)Interceptor接口有三个方法,如下:
packageorg.apache.ibatis.plugin;importjava.util.Properties;public interfaceInterceptor {
Object intercept(Invocation invocation)throwsThrowable;
Object plugin(Object target);voidsetProperties(Properties properties);
}
intercept方法中编写我们自己的处理逻辑。类似于AOP。
(2)@Intercepts注解:
packageorg.apache.ibatis.plugin;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/***@authorClinton Begin*/@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)public @interfaceIntercepts {
Signature[] value();
}
Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法。
(3)Signature注解指定需要拦截那个类对象的哪个方法
packageorg.apache.ibatis.plugin;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)public @interfaceSignature {
Class>type();
String method();
Class>[] args();
}
class:指定定义拦截的类 Executor、ParameterHandler、StatementHandler、ResultSetHandler当中的一个。
method:指定拦截的方法,方法名字即可
args:指定拦截的方法对应的参数,JAVA里面方法可能重载,不指定参数,不能确定调用那个方法。
4.mybatis的sqlSessionFactory中注册拦截器
helperDialect=mysql
reasonable=true
5.Javabean中增加注解,如果是查询返回的map,会根据desensitionMap的规则进行脱敏
public classEmployeeIn {privateString employeeid;/*** 员工编号*/
privateString employeenumber;privateString name;/*** 身份证号*/@Desensitization(type=DesensitionType.ID_CARD)privateString idcode;
...
}
至此就可以实现一些基本的数据脱敏,前台查看返回的信息如下:
2.原理简单介绍
Mybatis拦截器设计的初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。通过Mybatis拦截器我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。
Mybatis里面的核心对象还是比较多的,如下:
Mybatis拦截器并不是每个对象里面的方法都可以被拦截的。Mybatis拦截器只能拦截Executor、ParameterHandler、StatementHandler、ResultSetHandler四个对象里面的方法。
1.Executor接口如下:
/**Eclipse Class Decompiler plugin, Copyright (c) 2017 Chen Chao.*/
packageorg.apache.ibatis.executor;importjava.sql.SQLException;importjava.util.List;importorg.apache.ibatis.cache.CacheKey;importorg.apache.ibatis.mapping.BoundSql;importorg.apache.ibatis.mapping.MappedStatement;importorg.apache.ibatis.reflection.MetaObject;importorg.apache.ibatis.session.ResultHandler;importorg.apache.ibatis.session.RowBounds;importorg.apache.ibatis.transaction.Transaction;/***@authorClinton Begin*/
public interfaceExecutor {
ResultHandler NO_RESULT_HANDLER= null;int update(MappedStatement ms, Object parameter) throwsSQLException; List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throwsSQLException; List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throwsSQLException;
List flushStatements() throwsSQLException;void commit(boolean required) throwsSQLException;void rollback(boolean required) throwsSQLException;
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);booleanisCached(MappedStatement ms, CacheKey key);voidclearLocalCache();void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class>targetType);
Transaction getTransaction();void close(booleanforceRollback);booleanisClosed();voidsetExecutorWrapper(Executor executor);
}
Mybatis中所有的Mapper语句的执行都是通过Executor进行的。Executor是Mybatis的核心接口。从其定义的接口方法我们可以看出,对应的增删改语句是通过Executor接口的update方法进行的,查询是通过query方法进行的。
2.ParameterHandler
/**Eclipse Class Decompiler plugin, Copyright (c) 2017 Chen Chao.*/
packageorg.apache.ibatis.executor.parameter;importjava.sql.PreparedStatement;importjava.sql.SQLException;/*** A parameter handler sets the parameters of the {@codePreparedStatement}
*
*@authorClinton Begin*/
public interfaceParameterHandler {
Object getParameterObject();voidsetParameters(PreparedStatement ps)throwsSQLException;
}
ParameterHandler用来设置参数规则,当StatementHandler使用prepare()方法后,接下来就是使用它来设置参数。所以如果有对参数做自定义逻辑处理的时候,可以通过拦截ParameterHandler来实现。
3.StatementHandler
/**Eclipse Class Decompiler plugin, Copyright (c) 2017 Chen Chao.*/
packageorg.apache.ibatis.executor.statement;importjava.sql.Connection;importjava.sql.SQLException;importjava.sql.Statement;importjava.util.List;importorg.apache.ibatis.cursor.Cursor;importorg.apache.ibatis.executor.parameter.ParameterHandler;importorg.apache.ibatis.mapping.BoundSql;importorg.apache.ibatis.session.ResultHandler;/***@authorClinton Begin*/
public interfaceStatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)throwsSQLException;voidparameterize(Statement statement)throwsSQLException;voidbatch(Statement statement)throwsSQLException;intupdate(Statement statement)throwsSQLException; Listquery(Statement statement, ResultHandler resultHandler)throwsSQLException; CursorqueryCursor(Statement statement)throwsSQLException;
BoundSql getBoundSql();
ParameterHandler getParameterHandler();
}
StatementHandler负责处理Mybatis与JDBC之间Statement的交互。
4.ResultSetHandler
/**Eclipse Class Decompiler plugin, Copyright (c) 2017 Chen Chao.*/
packageorg.apache.commons.dbutils;importjava.sql.ResultSet;importjava.sql.SQLException;
public interface ResultSetHandler{T handle(ResultSet rs)throwsSQLException;
}
ResultSetHandler用于对查询到的结果做处理。所以如果你有需求需要对返回结果做特殊处理的情况下可以去拦截ResultSetHandler的处理。
3.常见的拦截器
PageInterceptor 分页插件
4.拦截器实现数据库查询完加密,编辑关联查询解密
今天遇到个需求是查询之后需要对身份证以及住址信息,并且在关联查询的时候需要使用原字符串,也就是需要解密。并且在编辑完保存的时候需要还原成原字符串。
1. 自定义注解Crypt
packagecn.xm.exam.mybatis;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** 加密解密注解
*
*@authorAdministrator
**/@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)public @interfaceCrypt {
}
2. 加密工具类
packagecn.xm.exam.mybatis;importjava.util.HashMap;importjava.util.Map;importorg.apache.commons.lang3.StringUtils;importcn.xm.exam.utils.SHAUtils;public classCryptUtils {/*** 加密后字符串-原字符串*/
private static final Map cryptedValues = new HashMap<>();public staticString crypt(String originValue) {
String encode= SHAUtils.sha1Hex(originValue + "mysalt");if (!cryptedValues.containsKey(encode)) {
cryptedValues.put(encode, originValue);
}returnencode;
}public static booleanhasCryptedVal(String value) {returncryptedValues.containsKey(value);
}public staticString decrypt(String value) {if (StringUtils.isBlank(value) || !hasCryptedVal(value)) {returnvalue;
}
String decodeVal=cryptedValues.get(value);if(StringUtils.isBlank(decodeVal)) {returndecodeVal;
}return StringUtils.substringBeforeLast(decodeVal, "mysalt");
}
}
SHA摘要算法如下:
packagecn.xm.exam.utils;importorg.apache.commons.codec.digest.DigestUtils;/*** 摘要算法:SHA算法Secure Hash Algorithm(安全hash算法) 安全散列算法(hash函数 将原始信息压缩
* 返回散列值)可以是SHA-1,SHA1是目前最安全 的摘要算法 摘要的长度为 20字节
*
* 其他的SHA 包括 SHA-256(32字节)
*
* 20byte = 160 bit,换成16进制字符串就是40位字符串
*
*@authorAdministrator
**/
public classSHAUtils {/***
*@paramsourceCode
*@return40位的16进制字符串*/
public staticString sha1Hex(String sourceCode) {returnDigestUtils.sha1Hex(sourceCode);
}/***
*@paramsourceCode
*@returnlength为20的字节数组,如果转为字符串需要new String(Hex.encodeHex(return))*/
public static byte[] sha1(String sourceCode) {//length为20的字节数组
returnDigestUtils.sha1(sourceCode);
}/***
*@paramsourceCode
*@return40位的16进制字符串*/
public staticString sha256Hex(String sourceCode) {returnDigestUtils.sha256Hex(sourceCode);
}/***
*@paramsourceCode
*@returnlength为20的字节数组,如果转为字符串需要new String(Hex.encodeHex(return))*/
public static byte[] sha256(String sourceCode) {//length为20的字节数组
returnDigestUtils.sha256(sourceCode);
}public static voidmain(String[] args) {
System.out.println(sha1Hex("qlq"));
}
}
SHA应该是不可逆的,我是将加密后的字符串作为key、原字符串作为value存入了map中来实现可逆。
3. 加密拦截器以及解密拦截器
加密拦截器,拦截 ResultSetHandler 的Statement 方法,对查出的数据进行加密。
packagecn.xm.exam.mybatis;importjava.lang.reflect.Field;importjava.sql.Statement;importjava.util.ArrayList;importjava.util.LinkedList;importjava.util.List;importjava.util.Map;importjava.util.Properties;importjava.util.Set;importorg.apache.commons.collections.CollectionUtils;importorg.apache.commons.collections.MapUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.commons.lang3.reflect.FieldUtils;importorg.apache.ibatis.executor.resultset.ResultSetHandler;importorg.apache.ibatis.plugin.Interceptor;importorg.apache.ibatis.plugin.Intercepts;importorg.apache.ibatis.plugin.Invocation;importorg.apache.ibatis.plugin.Plugin;importorg.apache.ibatis.plugin.Signature;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/*** 加密。出库后加密(加密后传到界面)
*
*@authorAdministrator
**/@Intercepts({ @Signature(type= ResultSetHandler.class, method = "handleResultSets", args = { Statement.class}) })public class EncryptInterceptor implementsInterceptor {private static final Logger log = LoggerFactory.getLogger(EncryptInterceptor.class);private static final List cryptedKeys = new LinkedList<>();static{
cryptedKeys.add("fullname");
cryptedKeys.add("idCode");
cryptedKeys.add("idCard");
cryptedKeys.add("userIDCard");
cryptedKeys.add("userIdCard");
cryptedKeys.add("username");
cryptedKeys.add("address");
}
@Overridepublic Object intercept(Invocation invocation) throwsThrowable {
Object resultObject=invocation.proceed();if (resultObject == null) {return null;
}//基于selectList
if (resultObject instanceofArrayList) {
ArrayList resultList=(ArrayList) resultObject;if(CollectionUtils.isNotEmpty(resultList)) {for(Object result : resultList) {
doEncrypt(result);
}
}
}else{
doEncrypt(resultObject);
}returnresultObject;
}private voiddoEncrypt(Object result) {if (result instanceofMap) {
Map resultMap=(Map) result;
doEncryptMap(resultMap);return;
}
doEncryptPlainBean(result);
}/*** 加密普通bean,用反射获取字段进行加密
*
*@paramresult*/
private voiddoEncryptPlainBean(Object result) {
List allFieldsList = FieldUtils.getFieldsListWithAnnotation(result.getClass(), Crypt.class);for(Field field : allFieldsList) {
field.setAccessible(true);try{
Class> type =field.getType();if (!type.equals(String.class)) {continue;
}
String value=(String) field.get(result);if(StringUtils.isBlank(value)) {continue;
}
value=encrypt(value);
field.set(result, value);
}catch(Exception e) {
log.error("doEncryptPlainBean error", e);
}
}
}privateString encrypt(String value) {returnCryptUtils.crypt(value);
}/*** 加密map
*
*@paramresultMap*/
private voiddoEncryptMap(Map resultMap) {if(MapUtils.isEmpty(resultMap)) {return;
}
Set keySet=resultMap.keySet();for(Object key : keySet) {
String keyStr=(String) key;if(cryptedKeys.contains(keyStr)) {
resultMap.put(key, encrypt(String.valueOf(resultMap.get(key))));
}
}
}
@OverridepublicObject plugin(Object target) {return Plugin.wrap(target, this);
}
@Overridepublic voidsetProperties(Properties properties) {
}
}
解密拦截器:对入参进行解密。先判断类型,只对string、list、map中的string、bean中的string属性进行解密
packagecn.xm.exam.mybatis;importjava.lang.reflect.Field;importjava.sql.PreparedStatement;importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;importjava.util.Map;importjava.util.Properties;importjava.util.Set;importorg.apache.commons.collections.CollectionUtils;importorg.apache.commons.collections.MapUtils;importorg.apache.commons.lang3.reflect.FieldUtils;importorg.apache.ibatis.executor.parameter.ParameterHandler;importorg.apache.ibatis.plugin.Interceptor;importorg.apache.ibatis.plugin.Intercepts;importorg.apache.ibatis.plugin.Invocation;importorg.apache.ibatis.plugin.Plugin;importorg.apache.ibatis.plugin.Signature;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;/*** 解密拦截器。(查询或者进行修改等操作时对参数进行解密)
*
*@authorAdministrator
**/@Intercepts({ @Signature(type= ParameterHandler.class, method = "setParameters", args = PreparedStatement.class) })public class DecryptInterceptor implementsInterceptor {private static final Logger log = LoggerFactory.getLogger(DecryptInterceptor.class);
@Overridepublic Object intercept(Invocation invocation) throwsThrowable {//@Signature 指定了 type= parameterHandler 后,这里的 invocation.getTarget()//便是parameterHandler//若指定ResultSetHandler ,这里则能强转为ResultSetHandler
ParameterHandler parameterHandler =(ParameterHandler) invocation.getTarget();//获取参数对像,即 mapper 中 paramsType 的实例
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);//取出实例(参数实例)
Object parameterObject =parameterField.get(parameterHandler);if (parameterObject != null) {int count = 0;
Class> parameterObjectClass =parameterObject.getClass();//集合
if (parameterObject instanceofList) {
ArrayList resultList=(ArrayList) parameterObject;if(CollectionUtils.isNotEmpty(resultList)) {for(Object result : resultList) {
result=doDecrypt(result);
}
}
}//普通的bean
parameterObject =doDecrypt(parameterObject);
}//重新赋值引用
parameterField.set(parameterHandler, parameterObject);
Object proceed=invocation.proceed();returnproceed;
}privateObject doDecrypt(Object result) {if (result == null) {returnresult;
}
Class extends Object> clazz =result.getClass();//String 类型
if (clazz != null && clazz.equals(String.class)) {returndecryptStr(result.toString());
}if (result instanceofMap) {returndecryptMap((Map) result);
}//普通bean
returndecryptPlainBean(result);
}privateObject decryptPlainBean(Object result) {
List allFieldsList = FieldUtils.getFieldsListWithAnnotation(result.getClass(), Crypt.class);for(Field field : allFieldsList) {
field.setAccessible(true);try{
Class> type =field.getType();if (!type.equals(String.class)) {continue;
}
Object object=field.get(result);
field.set(result, decryptStr((String) object));
}catch(Exception e) {
log.error("doEncryptPlainBean error", e);
}
}returnresult;
}privateObject decryptMap(Map result) {if (result == null ||MapUtils.isEmpty(result)) {returnresult;
}
Set keySet=result.keySet();
Iterator iterator=keySet.iterator();while(iterator.hasNext()) {
Object key=iterator.next();
Object object=result.get(key);if (object == null) {continue;
}if (object instanceofString) {
result.put(key, decryptStr((String) object));
}
}returnresult;
}privateObject decryptStr(String string) {returnCryptUtils.decrypt(string);
}
@OverridepublicObject plugin(Object target) {return Plugin.wrap(target, this);
}
@Overridepublic voidsetProperties(Properties properties) {
}
}
4. mybatis的会话工厂配置拦截器
helperDialect=mysql
reasonable=true
5.自定义的注解加在bean对应的实体类上,会被上面拦截器反射的时候读取到了
@Cryptprivate String useridcard;