本文目录导读:

我将为您提供一个完整的Java数据脱敏案例,涵盖常见的脱敏场景和实现方案。
核心脱敏工具类
import java.util.regex.Pattern;
/**
* 数据脱敏工具类
*/
public class DataMaskingUtil {
/**
* 姓名脱敏(保留姓,名用*代替)
* 张三 -> 张*
* 张三丰 -> 张*丰
*/
public static String maskName(String name) {
if (name == null || name.isEmpty()) {
return name;
}
if (name.length() == 1) {
return "*";
}
if (name.length() == 2) {
return name.charAt(0) + "*";
}
// 保留第一个和最后一个字符
return name.charAt(0) +
"*".repeat(name.length() - 2) +
name.charAt(name.length() - 1);
}
/**
* 手机号脱敏(保留前3后4)
* 13812345678 -> 138****5678
*/
public static String maskMobile(String mobile) {
if (mobile == null || mobile.length() != 11) {
return mobile;
}
return mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
/**
* 身份证号脱敏(保留前4后4)
* 110101199001011234 -> 1101**********1234
*/
public static String maskIdCard(String idCard) {
if (idCard == null || idCard.length() < 8) {
return idCard;
}
return idCard.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1**********$2");
}
/**
* 银行卡号脱敏(保留前4后4)
* 6222021234567890123 -> 6222************123
*/
public static String maskBankCard(String cardNo) {
if (cardNo == null || cardNo.length() < 8) {
return cardNo;
}
return cardNo.replaceAll("(\\d{4})\\d{10,}(\\d{4})", "$1****$2");
}
/**
* 邮箱脱敏(保留前缀前2和后缀域名)
* zhangsan@example.com -> zh***@example.com
*/
public static String maskEmail(String email) {
if (email == null || email.isEmpty()) {
return email;
}
int atIndex = email.indexOf('@');
if (atIndex <= 0) {
return email;
}
String prefix = email.substring(0, atIndex);
String suffix = email.substring(atIndex);
if (prefix.length() <= 2) {
return "***" + suffix;
}
return prefix.substring(0, 2) +
"***" +
suffix;
}
/**
* 地址脱敏(保留前几个字符)
* 北京市朝阳区xx街道xx小区 -> 北京市朝阳区***
*/
public static String maskAddress(String address) {
if (address == null || address.isEmpty()) {
return address;
}
if (address.length() <= 6) {
return "***";
}
return address.substring(0, 6) + "***";
}
/**
* IP地址脱敏
* 192.168.1.100 -> 192.168.*.*
*/
public static String maskIp(String ip) {
if (ip == null || ip.isEmpty()) {
return ip;
}
String[] parts = ip.split("\\.");
if (parts.length != 4) {
return ip;
}
return parts[0] + "." + parts[1] + ".*.*";
}
/**
* 密码脱敏
* 123456 -> ******
*/
public static String maskPassword(String password) {
if (password == null || password.isEmpty()) {
return password;
}
return "*".repeat(password.length());
}
}
注解定义
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 脱敏注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MaskField {
/**
* 脱敏类型
*/
MaskType type() default MaskType.DEFAULT;
/**
* 自定义脱敏正则表达式(当type为CUSTOM时使用)
*/
String regex() default "";
/**
* 脱敏替换字符串
*/
String replacement() default "***";
/**
* 是否脱敏
*/
boolean enabled() default true;
/**
* 脱敏类型枚举
*/
enum MaskType {
DEFAULT, // 默认不脱敏
NAME, // 姓名
MOBILE, // 手机号
ID_CARD, // 身份证号
BANK_CARD, // 银行卡号
EMAIL, // 邮箱
ADDRESS, // 地址
IP, // IP地址
PASSWORD, // 密码
CUSTOM // 自定义
}
}
脱敏处理器
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
/**
* 数据脱敏处理器
*/
public class DataMaskingProcessor {
/**
* 处理脱敏(通用方法)
* @param object 需要脱敏的对象
* @return 脱敏后的对象
*/
public static <T> T mask(T object) {
if (object == null) {
return null;
}
processObject(object);
return object;
}
/**
* 处理集合
*/
public static <T> Collection<T> maskCollection(Collection<T> collection) {
if (collection == null || collection.isEmpty()) {
return collection;
}
for (T item : collection) {
mask(item);
}
return collection;
}
/**
* 递归处理对象
*/
private static void processObject(Object object) {
if (object == null) {
return;
}
// 处理基本类型和包装类
if (isBasicType(object) || object instanceof String) {
return;
}
// 处理Collection
if (object instanceof Collection) {
for (Object item : (Collection<?>) object) {
processObject(item);
}
return;
}
// 处理Map
if (object instanceof Map) {
for (Object value : ((Map<?, ?>) object).values()) {
processObject(value);
}
return;
}
// 处理数组
if (object.getClass().isArray()) {
Object[] array = (Object[]) object;
for (Object item : array) {
processObject(item);
}
return;
}
// 处理普通对象
Class<?> clazz = object.getClass();
// 跳过JDK类
if (clazz.getName().startsWith("java.") || clazz.getName().startsWith("javax.")) {
return;
}
// 获取所有字段(包括父类)
while (clazz != null && clazz != Object.class) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
processField(field, object);
}
clazz = clazz.getSuperclass();
}
}
/**
* 处理字段
*/
private static void processField(Field field, Object object) {
try {
// 检查是否有脱敏注解
if (field.isAnnotationPresent(MaskField.class)) {
MaskField maskField = field.getAnnotation(MaskField.class);
if (!maskField.enabled()) {
return;
}
field.setAccessible(true);
Object value = field.get(object);
// 处理字符串类型字段
if (value instanceof String) {
String maskedValue = maskValue((String) value, maskField);
field.set(object, maskedValue);
}
// 处理其他类型字段
else if (value != null) {
processObject(value);
}
}
// 没有注解但字段类型需要处理的
else {
field.setAccessible(true);
Object value = field.get(object);
if (value != null && !isBasicType(value)) {
processObject(value);
}
}
} catch (IllegalAccessException e) {
// 忽略访问权限异常
}
}
/**
* 根据注解配置执行脱敏
*/
private static String maskValue(String value, MaskField maskField) {
if (value == null || value.isEmpty()) {
return value;
}
switch (maskField.type()) {
case NAME:
return DataMaskingUtil.maskName(value);
case MOBILE:
return DataMaskingUtil.maskMobile(value);
case ID_CARD:
return DataMaskingUtil.maskIdCard(value);
case BANK_CARD:
return DataMaskingUtil.maskBankCard(value);
case EMAIL:
return DataMaskingUtil.maskEmail(value);
case ADDRESS:
return DataMaskingUtil.maskAddress(value);
case IP:
return DataMaskingUtil.maskIp(value);
case PASSWORD:
return DataMaskingUtil.maskPassword(value);
case CUSTOM:
return maskCustom(value, maskField);
default:
return value;
}
}
/**
* 自定义脱敏
*/
private static String maskCustom(String value, MaskField maskField) {
String regex = maskField.regex();
String replacement = maskField.replacement();
if (regex != null && !regex.isEmpty()) {
return value.replaceAll(regex, replacement);
}
return value.substring(0, Math.min(2, value.length())) +
"*".repeat(Math.max(0, value.length() - 2));
}
/**
* 判断是否为基本类型
*/
private static boolean isBasicType(Object object) {
return object instanceof Number ||
object instanceof Boolean ||
object instanceof Character ||
object instanceof Byte;
}
}
实体类示例
import lombok.Data;
/**
* 用户实体类
*/
@Data
public class User {
private Long id;
@MaskField(type = MaskField.MaskType.NAME)
private String name;
@MaskField(type = MaskField.MaskType.MOBILE)
private String mobile;
@MaskField(type = MaskField.MaskType.ID_CARD)
private String idCard;
@MaskField(type = MaskField.MaskType.EMAIL)
private String email;
@MaskField(type = MaskField.MaskType.ADDRESS)
private String address;
@MaskField(type = MaskField.MaskType.PASSWORD)
private String password;
@MaskField(type = MaskField.MaskType.IP)
private String lastLoginIp;
private Integer age;
}
应用示例
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 使用示例
*/
public class MaskingExample {
public static void main(String[] args) {
// 单个对象脱敏
User user = new User();
user.setId(1L);
user.setName("张三丰");
user.setMobile("13812345678");
user.setIdCard("110101199001011234");
user.setEmail("zhangsan@example.com");
user.setAddress("北京市朝阳区某某街道某某小区");
user.setPassword("123456abc");
user.setLastLoginIp("192.168.1.100");
user.setAge(30);
System.out.println("=== 原始数据 ===");
printUser(user);
// 执行脱敏
DataMaskingProcessor.mask(user);
System.out.println("\n=== 脱敏后数据 ===");
printUser(user);
// 集合脱敏
System.out.println("\n=== 集合脱敏示例 ===");
List<User> users = Arrays.asList(user);
DataMaskingProcessor.maskCollection(users);
// 直接调用工具类
System.out.println("\n=== 直接调用工具类 ===");
System.out.println("姓名: " + DataMaskingUtil.maskName("张三丰"));
System.out.println("手机号: " + DataMaskingUtil.maskMobile("13812345678"));
System.out.println("身份证: " + DataMaskingUtil.maskIdCard("110101199001011234"));
System.out.println("邮箱: " + DataMaskingUtil.maskEmail("zhangsan@example.com"));
System.out.println("地址: " + DataMaskingUtil.maskAddress("北京市朝阳区某某街道某某小区"));
}
private static void printUser(User user) {
System.out.println("ID: " + user.getId());
System.out.println("姓名: " + user.getName());
System.out.println("手机号: " + user.getMobile());
System.out.println("身份证: " + user.getIdCard());
System.out.println("邮箱: " + user.getEmail());
System.out.println("地址: " + user.getAddress());
System.out.println("密码: " + user.getPassword());
System.out.println("IP: " + user.getLastLoginIp());
System.out.println("年龄: " + user.getAge());
}
}
配合Jackson序列化
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
/**
* Jackson脱敏序列化器
*/
public class MaskingSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
gen.writeString(DataMaskingUtil.maskMobile(value));
}
}
}
/**
* 使用Jackson注解的实体类
*/
public class UserWithJackson {
private Long id;
// 使用Jackson注解实现脱敏
@JsonSerialize(using = MaskingSerializer.class)
private String mobile;
private String name;
// getters and setters
}
配置中心方案
import java.util.HashMap;
import java.util.Map;
/**
* 脱敏配置管理
*/
public class MaskingConfigManager {
private static final Map<String, Boolean> ENABLED_MASKING = new HashMap<>();
/**
* 初始化默认配置
*/
static {
// 默认启用手机号、身份证、密码脱敏
ENABLED_MASKING.put(MaskField.MaskType.MOBILE.name(), true);
ENABLED_MASKING.put(MaskField.MaskType.ID_CARD.name(), true);
ENABLED_MASKING.put(MaskField.MaskType.PASSWORD.name(), true);
}
/**
* 更新配置
*/
public static void updateConfig(String maskType, boolean enabled) {
ENABLED_MASKING.put(maskType, enabled);
}
/**
* 检查是否启用
*/
public static boolean isEnabled(MaskField.MaskType maskType) {
return ENABLED_MASKING.getOrDefault(maskType.name(), false);
}
}
这个完整的数据脱敏方案具有以下特点:
- 支持多种脱敏类型:姓名、手机号、身份证、银行卡、邮箱、地址、IP、密码等
- 注解驱动:通过注解配置需要脱敏的字段
- 自动处理嵌套对象:支持对象嵌套、集合、Map等复杂结构
- 可扩展性:支持自定义脱敏规则
- 性能优化:只处理带有注解的字段
- 与主流框架集成:支持Jackson等序列化框架
使用时只需在实体类字段上添加@MaskField注解,调用DataMaskingProcessor.mask()方法即可完成脱敏。