Java数据脱敏案例

wen java案例 2

本文目录导读:

Java数据脱敏案例

  1. 核心脱敏工具类
  2. 注解定义
  3. 脱敏处理器
  4. 实体类示例
  5. 应用示例
  6. 配合Jackson序列化
  7. 配置中心方案

我将为您提供一个完整的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);
    }
}

这个完整的数据脱敏方案具有以下特点:

  1. 支持多种脱敏类型:姓名、手机号、身份证、银行卡、邮箱、地址、IP、密码等
  2. 注解驱动:通过注解配置需要脱敏的字段
  3. 自动处理嵌套对象:支持对象嵌套、集合、Map等复杂结构
  4. 可扩展性:支持自定义脱敏规则
  5. 性能优化:只处理带有注解的字段
  6. 与主流框架集成:支持Jackson等序列化框架

使用时只需在实体类字段上添加@MaskField注解,调用DataMaskingProcessor.mask()方法即可完成脱敏。

抱歉,评论功能暂时关闭!