實現原理:攔截ResultSetHandler 的返回結果集,對其脫敏處理
1. 首先定義一個注解,用來標注哪些字段需要脫敏
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface DataHide { }
2. 定義一個數據實體DO
@TableName("person") @Data public class PersonDO { @TableId private Integer id; private String firstName; @DataHide // 要做脫敏的字段 private String lastName; }
3. 寫一個插件(攔截器)
/** * @author yangxj * @date 2020-08-10 11:31 * <p> * 數據脫敏攔截器 */ @Component @Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)) public class DataHidePlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { List result = (List) invocation.proceed(); return dataHide(result); }
@SuppressWarnings("unchecked") private List dataHide(List result) { if (result.isEmpty()) return result; Class<?> clazz = result.get(0).getClass(); // 基本類型或者基本類型的包裝類型跳過 if (isWrapClass(clazz)) return result; // 獲取字段開始處理 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // 包含脫敏注解字段做脫敏處理 if (field.isAnnotationPresent(DataHide.class)) { result.forEach(originData -> doHide(originData, field)); } } return result; } private boolean isWrapClass(Class<?> clazz) { try { return clazz.isPrimitive() || ((Class) clazz.getField("TYPE").get(null)).isPrimitive(); } catch (Exception e) { return false; } } private void doHide(Object originData, Field field) { try { field.setAccessible(true);
//TODO 具體脫敏規則自行實現... field.set(originData, "**" + field.get(originData) + "**"); } catch (Exception e) { } } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }
5. over