1.注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Author: xiaoxin* @Date: 2023/7/21 17:15*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface Encrypt {Type type() default Type.MOBILE_PHONE;enum Type {//用户idUSER_ID,//中文名CHINESE_NAME,//身份证号ID_CARD,//座机号FIXED_PHONE,//手机号MOBILE_PHONE,//地址ADDRESS,//电子邮件EMAIL,//密码PASSWORD,//中国大陆车牌,包含普通车辆、新能源车辆CAR_LICENSE,//银行卡BANK_CARD,//字符串STR}}
2.EncryptUtil工具
import cn.hutool.core.util.DesensitizedUtil;
import io.ctc.commons.tools.utils.StringUtils;import java.lang.reflect.Field;/*** @Author: xiaoxin* @Date: 2023/7/21 17:16*/
public class EncryptUtil {public static void encryptFields(Object obj) {Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Encrypt.class)) {Encrypt encryptAnnotation = field.getAnnotation(Encrypt.class);Encrypt.Type type = encryptAnnotation.type();field.setAccessible(true);try {String value = (String) field.get(obj);String encryptedValue = encryptValue(type, value);field.set(obj, encryptedValue);} catch (IllegalAccessException e) {e.printStackTrace();}}}}/**** 根据类型进行脱敏处理* @param type* @param value* @return*/public static String encryptValue(Encrypt.Type type, String value) {StringBuffer sb = new StringBuffer();switch (type) {case USER_ID:sb.append(DesensitizedUtil.userId());break;case CHINESE_NAME:sb.append(DesensitizedUtil.chineseName(value));break;case ID_CARD:sb.append(DesensitizedUtil.idCardNum(value, 1, 2));break;case FIXED_PHONE:sb.append(DesensitizedUtil.fixedPhone(value));break;case MOBILE_PHONE:sb.append(DesensitizedUtil.mobilePhone(value));break;case ADDRESS:sb.append(DesensitizedUtil.address(value,6));break;case EMAIL:sb.append(DesensitizedUtil.email(value));break;case PASSWORD:sb.append(DesensitizedUtil.password(value));break;case CAR_LICENSE:sb.append(DesensitizedUtil.carLicense(value));break;case BANK_CARD:sb.append(DesensitizedUtil.bankCard(value));break;case STR:if (StringUtils.isNotBlank(encryptionStr(value))){sb.append(encryptionStr(value));}break;}return sb.toString();}/**** 自定义字符串处理* @param str* @return*/public static String encryptionStr(String str) {if (StringUtils.isBlank(str)){return "";}int length = str.length();if (length <= 4){return str;}// 替换的起始位置int startIndex = (length - 3) / 2;// 替换的结束位置int endIndex = startIndex + 3;// 替换为4个*String replacement = "****";StringBuilder sb = new StringBuilder(str);sb.replace(startIndex, endIndex, replacement);return sb.toString();}
}
3.EncryptAspect切面类
import io.ctc.commons.tools.utils.Result;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Objects;/*** @author xiaoxin*/
@Aspect
@Component
public class EncryptAspect {protected Logger logger = LoggerFactory.getLogger(getClass());@Pointcut("@annotation(io.util.test.Encrypt)")public void encryptDataPointCut() {}/**** 后置增强,返回数据脱敏切面类,页面上有部分数据是不能对外展示的,此方法不支持反脱敏* 示例:原数据19879835555 脱敏后198****5555* @param point* @throws Throwable*/@AfterReturning(value = "encryptDataPointCut()",returning = "returnValue")public void around(JoinPoint point, Object returnValue){logger.info("---------------后置增强~~~~对部分数据脱敏---------------");if (Objects.nonNull(returnValue)){//1.判断object是否可以转换为List<?>类型if (returnValue instanceof List<?>){List list = (List) returnValue;list.stream().forEach(a->{EncryptUtil.encryptFields(a);});}else//2.result对象,属性有code、msg、dataif (returnValue instanceof Result){try{Result result = (Result) returnValue;Object data = result.getData();if (Objects.nonNull(data)){if (data instanceof List<?>){List list = (List) data;list.stream().forEach(a->{EncryptUtil.encryptFields(a);});}else {EncryptUtil.encryptFields(data);}}}catch (ClassCastException e){throw new ClassCastException("数据脱敏转换失败");}}else {EncryptUtil.encryptFields(returnValue);}}}
}
4.User对象(需要脱敏的属性)
import io.util.test.Encrypt;
import lombok.Data;/*** 测试* @Author: xiaoxin* @Date: 2023/7/21 17:16*/
@Data
public class User {@Encrypt(type = Encrypt.Type.USER_ID)private String user_id;@Encrypt(type = Encrypt.Type.CHINESE_NAME)private String chinese_name;@Encrypt(type = Encrypt.Type.ID_CARD)private String id_card;@Encrypt(type = Encrypt.Type.FIXED_PHONE)private String fixed_phone;@Encrypt(type = Encrypt.Type.MOBILE_PHONE)private String mobile_phone;@Encrypt(type = Encrypt.Type.ADDRESS)private String address;@Encrypt(type = Encrypt.Type.EMAIL)private String email;@Encrypt(type = Encrypt.Type.PASSWORD)private String password;@Encrypt(type = Encrypt.Type.CAR_LICENSE)private String car_license;@Encrypt(type = Encrypt.Type.BANK_CARD)private String bank_card;@Encrypt(type = Encrypt.Type.STR)private String str;}
5.下面为测试:
Controller
service
结果:
统一返回结果就上面这样子的,controller上打上注解,实体类上根据类型打上注解就可以了。可以支持返回对象、List集合,分页的谁要的话在切面里写一下就好了,DesensitizedUtil是hutool的。