Java 中怎么利用注解标记敏感字段并在序列化时通过反射自动脱敏

胖明大大_4071

胖明大大_4071

2026-08-19

1010人浏览

原创

Java可通过自定义@Sensitive注解配合Jackson序列化器实现敏感字段自动脱敏:定义注解标记字段→序列化时反射识别→按枚举类型(PHONE/ID_CARD等)执行对应掩码逻辑→注册到ObjectMapper生效。

java 中怎么利用注解标记敏感字段并在序列化时通过反射自动脱敏

Java 中可以通过自定义注解 + 序列化框架(如 Jackson)的序列化器( JsonSerializer )或反射拦截,在序列化时自动对敏感字段脱敏。核心思路是:定义注解标记敏感字段 → 在序列化过程中通过反射识别该注解 → 动态替换字段值为脱敏后内容(如手机号中间四位变 *)。

1. 定义敏感字段注解

创建一个运行时保留的注解,用于标记需要脱敏的字段:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Sensitive {
    SensitiveType value() default SensitiveType.DEFAULT;
}

配套枚举定义常见脱敏类型(可扩展):

public enum SensitiveType {
    DEFAULT,      // 默认规则:手机号、身份证等按通用逻辑
    PHONE,        // 手机号:138****1234
    ID_CARD,      // 身份证:11010119900101123<strong>X</strong> → 110101**********123X
    EMAIL,        // 邮箱:a***@b.com
    BANK_CARD     // 银行卡:6228**********1234
}

2. 实现 Jackson 自定义序列化器

继承 JsonSerializer<object> </object>,在序列化每个对象前检查其字段是否含 @Sensitive,并根据类型执行对应脱敏逻辑:

public class SensitiveJsonSerializer extends JsonSerializer<object> {
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) 
            throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
<pre class="brush:php;toolbar:false;">    Class> clazz = value.getClass();
    Map<string object> result = new LinkedHashMap();

    // 遍历所有声明字段(含 private)
    for (Field field : clazz.getDeclaredFields()) {
        field.setAccessible(true);
        Object fieldValue;
        try {
            fieldValue = field.get(value);
        } catch (IllegalAccessException e) {
            continue;
        }

        // 检查是否标记了 @Sensitive
        Sensitive sensitive = field.getAnnotation(Sensitive.class);
        if (sensitive != null) {
            fieldValue = desensitize(fieldValue, sensitive.value());
        }
        result.put(field.getName(), fieldValue);
    }

    gen.writeStartObject();
    for (Map.Entry<string object> entry : result.entrySet()) {
        gen.writeStringField(entry.getKey(), Objects.toString(entry.getValue(), ""));
    }
    gen.writeEndObject();
}

private Object desensitize(Object raw, SensitiveType type) {
    if (raw == null) return null;
    String str = raw.toString();
    return switch (type) {
        case PHONE -> maskPhone(str);
        case ID_CARD -> maskIdCard(str);
        case EMAIL -> maskEmail(str);
        case BANK_CARD -> maskBankCard(str);
        default -> maskDefault(str);
    };
}

private String maskPhone(String s) {
    if (s.length() <p>}</p></string></string>

3. 注册全局序列化器(Spring Boot 示例)

在 Spring Boot 中,通过配置 ObjectMapper 注册该序列化器,使其对所有对象生效(注意:需配合 @JsonSerialize(using = ...) 或全局配置):

推荐方式是使用模块注册,避免手动加注解:

deep-java-review
deep-java-review

Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...

下载
@Configuration
public class JacksonConfig {
<pre class="brush:php;toolbar:false;">@Bean
@Primary
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    // 对所有 Object 类型启用敏感字段序列化(谨慎!更推荐按类注册)
    module.addSerializer(Object.class, new SensitiveJsonSerializer());
    mapper.registerModule(module);
    return mapper;
}

}

⚠️ 注意:直接注册 Object.class 会影响所有对象,可能带来性能与兼容性问题。更稳妥的做法是:

  • 让需要脱敏的 DTO 继承一个标记接口(如 Desensitizable),然后注册 SimpleModule.addSerializer(Desensitizable.class, ...)
  • 或在具体 VO 类上显式标注:@JsonSerialize(using = SensitiveJsonSerializer.class)
  • 也可结合 Jackson 的 BeanSerializerModifier,仅对含 @Sensitive 字段的类动态增强序列化逻辑(更精准但实现稍复杂)

4. 使用示例

在实体中使用注解:

public class UserVO {
    private String name;
<pre class="brush:php;toolbar:false;">@Sensitive(SensitiveType.PHONE)
private String phone;

@Sensitive(SensitiveType.ID_CARD)
private String idCard;

@Sensitive
private String password; // 使用默认脱敏

// getter/setter...

}

返回该对象时,Jackson 自动脱敏:

// 原始数据:phone="13812345678", idCard="11010119900101123X"
// 序列化后 JSON:
{
  "name": "张三",
  "phone": "138****5678",
  "idCard": "110101**********123X",
  "password": "pa***"
}

不复杂但容易忽略:脱敏逻辑应与业务强相关,建议将 desensitize 方法抽成可配置的服务(如支持正则自定义、长度阈值、空值策略),并在测试中覆盖边界情况(null、空字符串、超短字符串等)。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

9717

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

6882

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6072

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1064

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

888

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1276

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2549

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

19891

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1155

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习