当前位置:首页 > 文章列表 > 文章 > java教程 > Java数据脱敏注解实现与使用解析

Java数据脱敏注解实现与使用解析

2025-07-13 22:48:29 0浏览 收藏

学习文章要努力,但是不要急!今天的这篇文章《Java数据脱敏注解方案详解》将会介绍到等等知识点,如果你想深入学习文章,可以关注我!我会持续更新相关文章的,希望对大家都能有所帮助!

Java数据脱敏通过注解式实现,保护敏感信息不被随意暴露。1.定义@SensitiveInfo注解标记需脱敏字段,并配置脱敏类型及策略;2.编写工具类SensitiveInfoUtils,实现常见脱敏逻辑如中文名、身份证号、手机号等的处理;3.使用AOP切面拦截方法返回值,遍历对象字段并根据注解配置执行脱敏;4.支持嵌套对象脱敏,递归处理集合、数组及复杂对象中的敏感字段;5.支持自定义脱敏策略,通过扩展SensitiveType枚举和实现SensitiveHandler接口定义个性化规则;6.优化性能,采用缓存、异步处理、并行流等方式提升脱敏效率。

Java数据脱敏的注解式实现方案详解

Java数据脱敏,本质上就是保护敏感信息,避免在不必要的场景下暴露真实数据。注解式实现,则提供了一种优雅、便捷的方式来完成这个任务。

Java数据脱敏的注解式实现方案详解

解决方案

注解式脱敏的核心思想是:通过自定义注解标记需要脱敏的字段,然后在数据序列化或展示前,利用AOP或反射等机制,根据注解配置的脱敏策略对字段值进行处理。

  1. 定义脱敏注解:

    Java数据脱敏的注解式实现方案详解
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface SensitiveInfo {
        SensitiveType type() default SensitiveType.NONE; // 默认不脱敏
        String replaceChar() default "*"; // 默认替换字符
        int prefixNoMaskLen() default 0; // 前置不需要打码的长度
        int suffixNoMaskLen() default 0; // 后置不需要打码的长度
    }

    这里SensitiveType是一个枚举,定义了常见的脱敏类型,例如:

    public enum SensitiveType {
        NONE, // 不脱敏
        CHINESE_NAME, // 中文名
        ID_CARD, // 身份证号
        FIXED_PHONE, // 固定电话
        MOBILE_PHONE, // 手机号
        ADDRESS, // 地址
        EMAIL, // 邮箱
        BANK_CARD, // 银行卡
        PASSWORD, // 密码
        CUSTOM // 自定义
    }

    replaceChar指定替换字符,prefixNoMaskLensuffixNoMaskLen分别指定前后保留的长度。

    Java数据脱敏的注解式实现方案详解
  2. 编写脱敏策略工具类:

    public class SensitiveInfoUtils {
    
        private static final String ASTERISK = "*";
    
        public static String chineseName(String fullName) {
            if (StringUtils.isBlank(fullName)) {
                return fullName;
            }
            String name = StringUtils.left(fullName, 1);
            return StringUtils.rightPad(name, StringUtils.length(fullName), ASTERISK);
        }
    
        public static String idCard(String idCard) {
            if (StringUtils.isBlank(idCard)) {
                return idCard;
            }
            return StringUtils.left(idCard, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(idCard, 4), StringUtils.length(idCard) - 6, ASTERISK), null));
        }
    
        public static String mobilePhone(String mobile) {
            if (StringUtils.isBlank(mobile)) {
                return mobile;
            }
            return StringUtils.left(mobile, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(mobile, 4), StringUtils.length(mobile) - 3, ASTERISK), null));
        }
    
        // 其他脱敏方法...
    
        public static String custom(String str, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
            if (StringUtils.isBlank(str)) {
                return str;
            }
            if (prefixNoMaskLen < 0 || suffixNoMaskLen < 0) {
                return str;
            }
            int maskLen = StringUtils.length(str) - prefixNoMaskLen - suffixNoMaskLen;
            if (maskLen <= 0) {
                return str;
            }
            String mask = StringUtils.repeat(maskStr, maskLen);
            return StringUtils.left(str, prefixNoMaskLen) + mask + StringUtils.right(str, suffixNoMaskLen);
        }
    }

    这个工具类包含了各种脱敏方法,可以根据实际需求进行扩展。

  3. 使用AOP实现自动脱敏:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Field;
    
    @Aspect
    @Component
    public class SensitiveInfoAspect {
    
        @Around("@annotation(com.example.SensitiveData)") // 假设有个@SensitiveData注解标记需要脱敏的方法
        public Object maskSensitiveData(ProceedingJoinPoint joinPoint) throws Throwable {
            Object result = joinPoint.proceed();
            if (result != null) {
                processObject(result);
            }
            return result;
        }
    
        private void processObject(Object obj) throws IllegalAccessException {
            Class<?> clazz = obj.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(SensitiveInfo.class)) {
                    SensitiveInfo sensitiveInfo = field.getAnnotation(SensitiveInfo.class);
                    field.setAccessible(true);
                    Object value = field.get(obj);
                    if (value instanceof String) {
                        String maskedValue = maskString(sensitiveInfo, (String) value);
                        field.set(obj, maskedValue);
                    } // 可以添加对其他类型数据的支持
                }
            }
        }
    
        private String maskString(SensitiveInfo sensitiveInfo, String value) {
            if (StringUtils.isBlank(value)) {
                return value;
            }
            switch (sensitiveInfo.type()) {
                case CHINESE_NAME:
                    return SensitiveInfoUtils.chineseName(value);
                case ID_CARD:
                    return SensitiveInfoUtils.idCard(value);
                case MOBILE_PHONE:
                    return SensitiveInfoUtils.mobilePhone(value);
                case CUSTOM:
                    return SensitiveInfoUtils.custom(value, sensitiveInfo.prefixNoMaskLen(), sensitiveInfo.suffixNoMaskLen(), sensitiveInfo.replaceChar());
                // 其他类型...
                default:
                    return value; // NONE类型不脱敏
            }
        }
    }

    这个AOP切面拦截带有@SensitiveData注解的方法,获取返回值,然后遍历对象的字段,如果字段带有@SensitiveInfo注解,则根据注解配置的类型进行脱敏。需要注意的是,为了访问私有字段,需要设置field.setAccessible(true)

  4. 在实体类中使用注解:

    public class User {
        private String name;
    
        @SensitiveInfo(type = SensitiveType.ID_CARD)
        private String idCard;
    
        @SensitiveInfo(type = SensitiveType.MOBILE_PHONE)
        private String phone;
    
        @SensitiveInfo(type = SensitiveType.ADDRESS)
        private String address;
    
        // getter 和 setter 方法
    }

    现在,当带有@SensitiveData注解的方法返回User对象时,idCardphone字段会自动脱敏。

如何处理嵌套对象的数据脱敏?

嵌套对象脱敏,简单来说,就是当你的实体类中包含其他实体类作为字段时,如何递归地对这些嵌套对象中的敏感数据进行脱敏。

修改AOP切面中的processObject方法,使其能够递归处理嵌套对象:

private void processObject(Object obj) throws IllegalAccessException {
    if (obj == null) {
        return;
    }

    Class<?> clazz = obj.getClass();

    // 如果是集合类型,则遍历集合中的元素进行处理
    if (obj instanceof Collection) {
        Collection<?> collection = (Collection<?>) obj;
        for (Object item : collection) {
            processObject(item); // 递归处理集合中的每个元素
        }
        return;
    }

    // 如果是数组类型,则遍历数组中的元素进行处理
    if (obj.getClass().isArray()) {
        Object[] array = (Object[]) obj;
        for (Object item : array) {
            processObject(item); // 递归处理数组中的每个元素
        }
        return;
    }


    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        field.setAccessible(true);
        Object fieldValue = field.get(obj);

        if (field.isAnnotationPresent(SensitiveInfo.class)) {
            SensitiveInfo sensitiveInfo = field.getAnnotation(SensitiveInfo.class);
            if (fieldValue instanceof String) {
                String maskedValue = maskString(sensitiveInfo, (String) fieldValue);
                field.set(obj, maskedValue);
            }
        } else if (fieldValue != null && !field.getType().isPrimitive() &&
                   !(fieldValue instanceof String) && !(fieldValue instanceof Number) &&
                   !(fieldValue instanceof Boolean) && !(fieldValue instanceof Enum)) {
            // 递归处理嵌套对象
            processObject(fieldValue);
        }
    }
}

这里,我们添加了对集合和数组类型的判断,并递归调用processObject方法处理集合和数组中的每个元素。对于非基本类型、非String/Number/Boolean/Enum类型的字段,我们也递归调用processObject方法,实现嵌套对象的脱敏。

如何支持自定义脱敏策略?

自定义脱敏策略允许开发者根据特定业务需求,灵活地定义脱敏规则。

  1. 扩展SensitiveType枚举:

    添加一个CUSTOM类型,并允许用户指定自定义的脱敏方法。

    public enum SensitiveType {
        NONE,
        CHINESE_NAME,
        ID_CARD,
        // ...
        CUSTOM
    }
  2. 修改SensitiveInfo注解:

    添加一个customHandler属性,用于指定自定义脱敏策略的类。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface SensitiveInfo {
        SensitiveType type() default SensitiveType.NONE;
        Class<? extends SensitiveHandler> customHandler() default DefaultSensitiveHandler.class; // 默认使用默认处理器
    }

    这里SensitiveHandler是一个接口,定义了自定义脱敏策略的方法:

    public interface SensitiveHandler {
        String mask(String value);
    }

    DefaultSensitiveHandler是一个默认实现,不做任何脱敏处理:

    public class DefaultSensitiveHandler implements SensitiveHandler {
        @Override
        public String mask(String value) {
            return value;
        }
    }
  3. 修改AOP切面:

    maskString方法中,根据SensitiveType选择对应的脱敏策略。

    private String maskString(SensitiveInfo sensitiveInfo, String value) {
        if (StringUtils.isBlank(value)) {
            return value;
        }
        if (sensitiveInfo.type() == SensitiveType.CUSTOM) {
            try {
                SensitiveHandler handler = sensitiveInfo.customHandler().getDeclaredConstructor().newInstance();
                return handler.mask(value);
            } catch (Exception e) {
                // 处理异常,例如记录日志
                return value; // 发生异常时,返回原始值
            }
        }
        // 其他类型...
        return value;
    }
  4. 使用自定义脱敏策略:

    创建一个自定义的脱敏策略类,实现SensitiveHandler接口。

    public class MyCustomSensitiveHandler implements SensitiveHandler {
        @Override
        public String mask(String value) {
            // 实现自定义的脱敏逻辑
            if (value != null && value.length() > 4) {
                return "prefix_" + value.substring(value.length() - 4);
            }
            return "default_value";
        }
    }

    在实体类中使用@SensitiveInfo注解,指定customHandler属性。

    public class User {
        @SensitiveInfo(type = SensitiveType.CUSTOM, customHandler = MyCustomSensitiveHandler.class)
        private String customField;
    }

如何处理性能问题?

脱敏操作,特别是当数据量很大时,可能会对性能产生影响。

  1. 缓存脱敏结果:

    对于一些静态数据,例如枚举值,可以缓存脱敏结果,避免重复计算。可以使用Guava Cache或Caffeine等缓存库。

  2. 异步脱敏:

    对于一些非实时性要求的数据,可以采用异步脱敏的方式,将脱敏操作放入消息队列中,由专门的消费者进行处理。

  3. 选择合适的脱敏算法:

    不同的脱敏算法的性能差异很大,例如,使用正则表达式进行脱敏的性能通常比使用字符串截取的性能要差。

  4. 避免过度脱敏:

    只对真正需要脱敏的数据进行脱敏,避免对所有数据都进行脱敏。

  5. 优化AOP切面:

    AOP切面的性能也很重要,可以优化切面表达式,减少切面的执行次数。

  6. 批量脱敏:

    如果需要对大量数据进行脱敏,可以采用批量脱敏的方式,例如,一次性处理1000条数据。

  7. 使用并行流:

    对于集合类型的数据,可以使用Java 8的并行流进行脱敏,提高脱敏效率。

    List<User> users = ...;
    users.parallelStream().forEach(user -> {
        // 对user对象进行脱敏
    });

今天关于《Java数据脱敏注解实现与使用解析》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!

AI剪辑工具助力自媒体高效出片AI剪辑工具助力自媒体高效出片
上一篇
AI剪辑工具助力自媒体高效出片
PHPMyAdmin磁盘空间不足解决方法
下一篇
PHPMyAdmin磁盘空间不足解决方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    511次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    498次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • AI边界平台:智能对话、写作、画图,一站式解决方案
    边界AI平台
    探索AI边界平台,领先的智能AI对话、写作与画图生成工具。高效便捷,满足多样化需求。立即体验!
    412次使用
  • 讯飞AI大学堂免费AI认证证书:大模型工程师认证,提升您的职场竞争力
    免费AI认证证书
    科大讯飞AI大学堂推出免费大模型工程师认证,助力您掌握AI技能,提升职场竞争力。体系化学习,实战项目,权威认证,助您成为企业级大模型应用人才。
    421次使用
  • 茅茅虫AIGC检测:精准识别AI生成内容,保障学术诚信
    茅茅虫AIGC检测
    茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
    559次使用
  • 赛林匹克平台:科技赛事聚合,赋能AI、算力、量子计算创新
    赛林匹克平台(Challympics)
    探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
    660次使用
  • SEO  笔格AIPPT:AI智能PPT制作,免费生成,高效演示
    笔格AIPPT
    SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
    567次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码