1.添加注解DataMaskingClass和注解DataMaskingField分别作用在类和字段上面
/**
* 需要脱敏的类注解
*
*/
@Documented
@Inherited
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataMaskingClass {
}
/**
* 脱敏字段
*/
@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataMaskingField {
/**
* 脱敏类型
*
* @return {@link String}
*/
MaskingType type() default MaskingType.DEFAULT;
}
2.添加脱敏字段类型
/**
* 加密类型
*/
public enum MaskingType {
/**
* 默认的
*/
DEFAULT,
/**
* 姓名 eg: 李*
*/
NAME,
/**
* 身份证 显示前十位,不足十位的都变为*号
*/
IDDEN,
/**
* 电话 显示前三位和后四位,其他变为*号
*/
PHONE;
}
3.添加mybatisplus 结果拦截器
/**
* 结果拦截器
*/
@Slf4j
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class ResultInterceptor implements Interceptor {
@Autowired
private IDataMaskingService dataMaskingService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object result = invocation.proceed();
if (Objects.isNull(result)) {
return null;
}
if (result instanceof ArrayList) {
ArrayList resultList = (ArrayList) result;
if (CollectionUtils.isNotEmpty(resultList) && needToMasking(resultList.get(0))) {
for (Object obj : resultList) {
dataMaskingService.masking(obj);
}
}
} else {
if (needToMasking(result)) {
dataMaskingService.masking(result);
}
}
return result;
}
/**
* 是否需要脱敏
*
* @param object 对象
* @return boolean
*/
private boolean needToMasking(Object object) {
Class<?> objectClass = object.getClass();
DataMaskingClass encryptDecryptClass = AnnotationUtils.findAnnotation(objectClass, DataMaskingClass.class);
return Objects.nonNull(encryptDecryptClass);
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
4.添加结果拦截器服务
/**
* 数据标记服务
*
*/
public interface IDataMaskingService {
/**
* 脱敏
*
* @param result 结果
* @return {@link T}* @throws IllegalAccessException 非法访问异常
*/
<T> T masking(T result) throws IllegalAccessException;
}
/**
* 数据标记服务Impl
*
*/
@Service
public class DataMaskingServiceImpl implements IDataMaskingService {
/**
* 脱敏
*
* @param result 结果
* @return {@link T}
*/
@Override
public <T> T masking(T result) throws IllegalAccessException {
Class<?> parameterObjectClass = result.getClass();
Field[] declaredFields = parameterObjectClass.getDeclaredFields();
for (Field field : declaredFields) {
DataMaskingField annotation = field.getAnnotation(DataMaskingField.class);
if (Objects.isNull(annotation)) {
continue;
}
MaskingType type = annotation.type();
//允许通过反射访问该字段
field.setAccessible(true);
//返回指定对象result上此field表示的字段的值
Object object = field.get(result);
String value = MaskingUtils.getValue(object, type);
field.set(result, value);
}
return result;
}
}
5 .MybatisPlusConfig里面注入结果拦截器
/**
* 脱敏拦截器
*
* @return {@link ResultInterceptor}
*/
@Bean
@ConditionalOnMissingBean
public ResultInterceptor resultInterceptor() {
return new ResultInterceptor();
}
备注:脱敏工具类
/**
* 脱敏工具类
*/
public class MaskingUtils {
/**
* 获得的脱敏值
*
* @param object 对象
* @param type 类型
* @return {@link String}
*/
public static String getValue(Object object, MaskingType type) {
String value = (String) object;
switch (type) {
case DEFAULT:
if (Assert.isNotBlank(value)) {
value = "********";
}
break;
case NAME:
if (Assert.isNotBlank(value)) {
value = value.substring(0, 1) + value.substring(1).replaceAll(".", "*");
}
break;
case IDDEN:
if (value != null && !"".equals(value)) {
value = value.toUpperCase();
value = value.replaceAll("(\\d{4})\\d{10}([0-9X]{4})", "$1********$2");
}
break;
case PHONE:
if (value != null && !"".equals(value)) {
value = value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
break;
default:
break;
}
return value;
}
}