信息脱敏工具类
/**
* 脱敏工具类
*
*/
@Component
public class DesensitizationUtil {
private static final Integer ZERO = 0;
/**
* 脱敏类型map
* key:脱敏类型
* value:lambda表达式,脱敏方法
* Function<搜索条件,返回结果>
*/
private final static Map<DesensitizationEnum, Function<String, String>> DES_MAP = new HashMap<>();
/**
*初始化分派逻辑,代替if-else
*/
@PostConstruct
public void desMapInit() {
//姓名
DES_MAP.put(DesensitizationEnum.USER_NAME, DesensitizationUtil::getDecName);
//身份证号码普通脱敏
DES_MAP.put(DesensitizationEnum.COMMON_ID_CARD, DesensitizationUtil::getDecIdNum);
//身份证号码强脱敏
DES_MAP.put(DesensitizationEnum.STRONG_ID_CARD, DesensitizationUtil::getDecIdNumStrongEn);
//手机号码
DES_MAP.put(DesensitizationEnum.MOBILE_PHONE, DesensitizationUtil::getDecMobile);
//固定电话
DES_MAP.put(DesensitizationEnum.FIXED_TELEPHONE, DesensitizationUtil::getDecTelephone);
//邮箱
DES_MAP.put(DesensitizationEnum.MAIL, DesensitizationUtil::getDecEmail);
//银行卡号
DES_MAP.put(DesensitizationEnum.BANK_NO, DesensitizationUtil::getDecBankNum);
//住址
DES_MAP.put(DesensitizationEnum.ADDRESS, DesensitizationUtil::getDecAddr);
//其它脱敏(军官证号、护照号等其他身份证件)
DES_MAP.put(DesensitizationEnum.OTHER, DesensitizationUtil::getDecOther);
}
/**
* 脱敏方法入口
*
* @param type 脱敏类型
* @param src 源数据
* @return String 脱敏后数据
*/
public static String getDesString(DesensitizationEnum type, String src) {
Function<String, String> function = DES_MAP.get(type);
if (!ObjectUtils.isEmpty(function)) {
return function.apply(src);
}
return "";
}
/**
* 姓名脱敏
*
* @param name 姓名
* @return String
*/
public static String getDecName(String name) {
if (!StringUtils.isEmpty(name)) {
name = "*" + name.substring(1);
}
return name;
}
/**
* 身份证号普通脱敏
* <p>
* 显示前1、5、6、7、8、9、10、11、12、18位,其余用*号代替
*
* @param idNum 身份证号
* @return String
*/
public static String getDecIdNum(String idNum) {
//显示前1、5、6、7、8、9、10、11、12、18位,其余用*号代替。
if (idNum != null && idNum.length() > 12) {
idNum = idNum.substring(0, 1) + "***" + idNum.substring(4, 12) + "*****" + idNum.substring(idNum.length() - 1);
}
return idNum;
}
/**
* 身份证号强脱敏
* <p>
* 3****************8
*
* @param idNum 身份证号
* @return String
*/
public static String getDecIdNumStrongEn(String idNum) {
//3****************8
if (idNum != null && idNum.length() > 12) {
idNum = idNum.substring(0, 1) + "****************" + idNum.substring(idNum.length() - 1);
}
return idNum;
}
/**
* 手机号码脱敏
*
* @param mobile 手机号
* @return String
*/
public static String getDecMobile(String mobile) {
if (mobile != null && mobile.length() == 11) {
mobile = mobile.substring(0, 3) + "****" + mobile.substring(mobile.length() - 4);
}
return mobile;
}
/**
* 固定电话脱敏
*
* @param telephone 固定电话
* @return String
*/
public static String getDecTelephone(String telephone) {
if (telephone != null) {
if (telephone.length() > 10) {
telephone = String.format("%s****%s", telephone.substring(0, 4), telephone.substring(telephone.length() - 4));
} else if (telephone.length() > 4) {
telephone = "****" + telephone.substring(telephone.length() - 4);
}
}
return telephone;
}
/**
* 邮箱脱敏
* <p>
* 前面的字符显示3位,3位后显示3个*,@后面完整显示 如:con***@163.com
* 如果少于三位,则全部显示,@前加***,例如tt@163.com 则显示为tt***@163.com
*
* @param email 邮箱
* @return String
*/
public static String getDecEmail(String email) {
String[] emialSplit = email.split("@");
String befor = "";
if (emialSplit[0].length() > 2) {
befor = emialSplit[0].substring(0, 3) + "***" + "@" + emialSplit[1];
} else {
befor = emialSplit[0] + "***" + "@" + emialSplit[1];
}
return befor;
}
/**
* 银行卡号脱敏
* <p>
* 显示前6位+ *(实际位数)+后4位。 如:622575******1496
*
* @param bankNum 银行卡号
* @return String
*/
public static String getDecBankNum(String bankNum) {
if (bankNum.length() > 10) {
String xy = bankNum.substring(0, 6) + bankNum.substring(bankNum.length() - 4);
int length = bankNum.length() - xy.length();
String slip = "";
for (int i = 0; i < length; i++) {
slip += "*";
}
bankNum = bankNum.substring(0, 6) + slip + bankNum.substring(bankNum.length() - 4);
}
return bankNum;
}
/**
* 住址脱敏
* <p>
* 将最后一个数字脱敏
*
* @param address 住址
* @return String
*/
public static String getDecAddr(String address) {
if (!StringUtils.isEmpty(address)) {
for (int i = 0; i < address.length(); i++) {
boolean needDec = (address.charAt(i) >= 48 && address.charAt(i) <= 57)
|| (address.charAt(i) >= 65296 && address.charAt(i) <= 65305);
if (needDec) {
address = address.replace(String.valueOf(address.charAt(i)), "*");
}
}
}
return address;
}
/**
* 其它脱敏
* <p>
* 显示前1/3和后1/3
* <p>
* 军官证号、护照号等其他身份证件
*
* @param src 源数据
* @return String
*/
public static String getDecOther(String src) {
String rtn = src;
if (!StringUtils.isEmpty(src)) {
int b = src.length() / 3;
rtn = src.substring(0, b);
for (int i = b; i < src.length() - b; i++) {
rtn += "*";
}
rtn += src.substring(b * 2);
}
return rtn;
}
/**
* 根据身份号码获取生日
*
* @param idNum 身份证号
* @return String 生日 yyyy-MM-dd
*/
public static String getBirthByIdNum(String idNum) {
String birth = "";
if (idNum != null && idNum.length() == 18) {
String year = idNum.substring(6, 10);
String moth = idNum.substring(10, 12);
String day = idNum.substring(12, 14);
birth = year + "-" + moth + "-" + day;
}
return birth;
}
/**
* 根据身份证号码获取性别
*
* @param idNum 身份证号
* @return String 性别类别 1-男,2-女
*/
public static int getSexByIdNum(String idNum) {
int sex = 0;
if (idNum != null && idNum.length() == 18) {
String sCardNum = idNum.substring(16, 17);
if (Integer.parseInt(sCardNum) % 2 != 0) {
//男
sex = 1;
} else {
//女
sex = 2;
}
}
return sex;
}
/**
* 根据身份证号获取年龄
*
* @param idNum 身份证号
* @return String 年龄
*/
public static int getAgeByIdNum(String idNum) {
if (StringUtils.isBlank(idNum)) {
return ZERO;
}
String birthday = getBirthByIdNum(idNum);
return getAgeByBirthday(birthday);
}
/**
* 根据出生日期获取年龄
*
* @param birthday 出生日期
* @return int
*/
public static int getAgeByBirthday(String birthday) {
if (StringUtils.isBlank(birthday)) {
return ZERO;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date birth = new Date();
try {
birth = sdf.parse(birthday);
} catch (ParseException e) {
e.printStackTrace();
}
return getAgeByBirthday(birth);
}
/**
* 根据出生日期获取年龄
*
* @param birthday 出生日期
* @return int
*/
public static int getAgeByBirthday(Date birthday) {
Calendar cal = Calendar.getInstance();
//出生日期晚于当前时间,无法计算
if (cal.before(birthday)) {
return ZERO;
}
//当前年份
int yearNow = cal.get(Calendar.YEAR);
//当前月份
int monthNow = cal.get(Calendar.MONTH);
//当前日期
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
cal.setTime(birthday);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
//计算整岁数
int age = yearNow - yearBirth;
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
//当前日期在生日之前,年龄减一
if (dayOfMonthNow < dayOfMonthBirth) {
age--;
}
} else {
//当前月份在生日之前,年龄减一
age--;
}
}
return age;
}
/**
* 根据出生日期和指定日期获取年龄
*
* @param birthday 出生日期
* @param appointedDay 指定日期
* @return int
*/
public static int getAgeByBirthday(Date birthday, Date appointedDay) {
Calendar cal = Calendar.getInstance();
cal.setTime(appointedDay);
//出生日期晚于当前时间,无法计算
if (cal.before(birthday)) {
return ZERO;
}
//当前年份
int yearNow = cal.get(Calendar.YEAR);
//当前月份
int monthNow = cal.get(Calendar.MONTH);
//当前日期
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
cal.setTime(birthday);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
//计算整岁数
int age = yearNow - yearBirth;
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
//当前日期在生日之前,年龄减一
if (dayOfMonthNow < dayOfMonthBirth) {
age--;
}
} else {
//当前月份在生日之前,年龄减一
age--;
}
}
return age;
}
}
自定义注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerializer.class)
public @interface Desensitization {
/**
* 脱敏类型
*/
DesensitizationEnum type() default DesensitizationEnum.OTHER;
/**
* 判断是否需要返回前端未脱敏的值 默认不需要
*/
boolean originalFieldValue() default false;
}
自定义序列化类
/**
* 序列化脱敏字段
*
* @version 版 本 号:1.0
* @since 2022-08-19 14:15
*/
public class DesensitizationSerializer extends StdSerializer<Object> implements ContextualSerializer {
private static final long serialVersionUID = 3205040278266130966L;
/**
* 脱敏类型
*/
private DesensitizationEnum type;
/**
* 判断是否需要返回前端未脱敏的值
*/
private Boolean originalFieldValue;
public DesensitizationSerializer() {
super(Object.class);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
if (Objects.isNull(beanProperty)) {
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
Desensitization annotation = beanProperty.getAnnotation(Desensitization.class);
if (Objects.nonNull(annotation)) {
type = annotation.type();
originalFieldValue = annotation.originalFieldValue();
return this;
}
return serializerProvider.findNullValueSerializer(null);
}
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (Objects.isNull(o)) {
return;
}
String label = DesensitizationUtil.getDesString(type, o.toString());
//判断是否需要将未脱敏值返回前端
if (originalFieldValue) {
//原文base64加密
String encodeToString = Base64.getEncoder().encodeToString(o.toString().getBytes());
jsonGenerator.writeObject(encodeToString);
} else {
jsonGenerator.writeObject("");
}
jsonGenerator.writeFieldName(jsonGenerator.getOutputContext().getCurrentName() + "Des");
jsonGenerator.writeObject(label);
}
}
使用
将注解加在需要脱敏的字段上
/**
* 手机号
*/
@Desensitization(type = DesensitizationEnum.MOBILE_PHONE)
private String ownerPhone;