====== MaskToStringBuilder ======
package com.xiaosq.common;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Map;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* @author Morgan.L
* @version 1.0
* @date 2019/7/9 17:10
*/
public class MaskToStringBuilder extends ReflectionToStringBuilder {
public MaskToStringBuilder(Object object) {
super(object);
}
public MaskToStringBuilder(Object object, ToStringStyle style) {
super(object, style);
}
public MaskToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
super(object, style, buffer);
}
public MaskToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass, boolean outputTransients, boolean outputStatics) {
super(object, style, buffer, reflectUpToClass, outputTransients, outputStatics);
}
@Override
protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException {
for (Annotation annotation : field.getDeclaredAnnotations()) {
if (annotation instanceof SensitiveF && field.get(this.getObject()) != null) {
SensitiveF.Type type = ((SensitiveF) annotation).type();
if (String.class.equals(field.get(this.getObject()).getClass())) {
String fieldValue = (String) field.get(this.getObject());
return MaskUtil.doMask(type, fieldValue);
//注意在使用的时候,List中必须是String,而不能是其他对象,不然会抛错
} else if (field.get(this.getObject()) instanceof Iterable) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('[');
boolean appended = false;
for (String fieldValue : (Iterable) field.get(this.getObject())) {
if (appended) {
stringBuilder.append(',');
}
stringBuilder.append(MaskUtil.doMask(type, fieldValue));
appended = true;
}
stringBuilder.append(']');
return stringBuilder.toString();
//注意在使用的时候,Map的key或者value不是String的时候就不做任何掩码操作
} else if (field.get(this.getObject()) instanceof Map) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('{');
boolean appended = false;
for (Map.Entry
====== SensitiveF ======
package com.xiaosq.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Morgan.L
* @version 1.0
* @date 4/9/2020 4:15 PM
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface SensitiveF {
enum Type {PhoneNo, Password, IdNo, BankCardNo, RealName}
Type type();
}
====== MaskUtil ======
package com.xiaosq.common;
import com.spcredit.core.util.SensitiveF;
import org.apache.commons.lang3.StringUtils;
public class MaskUtil {
private static int[] generateMaskRule(SensitiveF.Type type, String fieldValue) {
//第一个表示前面需显示的长度 prefixShowLength,第二表示后面需显示的长度 suffixShowLength
//默认全部掩码,所以两个值都是0
int[] result = {0, 0};
if (SensitiveF.Type.PhoneNo.equals(type)
|| SensitiveF.Type.IdNo.equals(type)
|| SensitiveF.Type.BankCardNo.equals(type)) {
result[0] = 4;
result[1] = 4;
} else if (SensitiveF.Type.RealName.equals(type)) {
if (StringUtils.isNotBlank(fieldValue)) {
if (fieldValue.length() > 2) {
result[0] = 1;
result[1] = 1;
} else {
result[0] = 1;
result[1] = 0;
}
}
} else {
//没有写SensitiveField.Type.Password的判断,因为安全从严的角度:默认全部掩码。
}
return result;
}
/**
* liaowenyue:此方法只用于掩码中间字符。如果要掩码两边的字符,请重新加方法,或者有其他规则的话
* fieldValue 需要掩码的字段的值
* prefixShowLength 前面需要显示的字符数
* type 敏感数据类型
*/
public static String doMask(SensitiveF.Type type, String fieldValue) {
int[] maskRule = generateMaskRule(type, fieldValue);
String maskStr = "*"; //默认用 * 填充字符。
if (StringUtils.isBlank(fieldValue)) {
return fieldValue;
}
int showLength = maskRule[0] + maskRule[1];
if (showLength < fieldValue.length()) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < fieldValue.length(); j++) {
if (j < maskRule[0]) {
sb.append(fieldValue.charAt(j));
continue;
}
if (j > (fieldValue.length() - 1 - maskRule[1])) {
sb.append(fieldValue.charAt(j));
continue;
}
sb.append(maskStr);
}
return sb.toString();
} else {
return fieldValue;
}
}
}