You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于自定义注解@PIIData实现PII字段加解密工具的技术咨询

针对PII字段注解驱动加解密的实现方案

问题1:实现utility.apply()拦截对象并处理带注解的字段

核心思路是用Java反射扫描对象的所有字段,识别带有@PIIData注解的字段,对其执行加解密后赋值回原对象,最终返回原对象(保持引用一致性,无需创建新实例)。

步骤1:定义自定义注解@PIIData

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 PIIData {
}

步骤2:定义示例实体类Employee

public class Employee {
    @PIIData
    private String name;
    
    @PIIData
    private String email;
    
    private String department; // 无注解,不参与加解密
    
    // 构造器、getter/setter、toString方法省略
    public Employee(String name, String email, String department) {
        this.name = name;
        this.email = email;
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', email='" + email + "', department='" + department + "'}";
    }
}

步骤3:实现PiiUtility的apply()方法

import java.lang.reflect.Field;

public class PiiUtility {
    // 模拟加密逻辑(实际项目请用标准加密算法如AES)
    private String encrypt(String plainText) {
        return "encrypted_" + plainText;
    }

    // 模拟解密逻辑
    private String decrypt(String cipherText) {
        return cipherText.replace("encrypted_", "");
    }

    public <T> T apply(T target) throws IllegalAccessException {
        if (target == null) {
            return null;
        }
        
        // 获取对象所有字段(包括私有字段)
        Field[] fields = target.getClass().getDeclaredFields();
        
        for (Field field : fields) {
            // 判断字段是否带有@PIIData注解
            if (field.isAnnotationPresent(PIIData.class)) {
                field.setAccessible(true); // 开启私有字段访问权限
                Object value = field.get(target);
                
                if (value instanceof String) {
                    // 这里以加密为例,可根据需求切换解密逻辑
                    String processedValue = encrypt((String) value);
                    field.set(target, processedValue);
                }
            }
        }
        
        return target;
    }
}

测试验证

public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        Employee emp = new Employee("Alice", "alice@example.com", "Engineering");
        System.out.println("处理前: " + emp);
        
        PiiUtility utility = new PiiUtility();
        Employee processedEmp = utility.apply(emp);
        System.out.println("处理后: " + processedEmp);
    }
}

输出结果:

处理前: Employee{name='Alice', email='alice@example.com', department='Engineering'}
处理后: Employee{name='encrypted_Alice', email='encrypted_alice@example.com', department='Engineering'}

问题2:给@PIIData添加参数指定加解密操作

完全可以实现,建议用枚举类型约束操作类型,避免字符串硬编码的错误。

步骤1:修改@PIIData注解,添加操作参数

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 PIIData {
    // 定义操作枚举,限定仅能选择加密/解密
    enum Operation {
        ENCRYPT, DECRYPT
    }
    
    // 设置默认操作(可选,也可强制要求必须指定)
    Operation value() default Operation.ENCRYPT;
}

步骤2:修改实体类,为不同字段指定操作

public class Employee {
    @PIIData(PIIData.Operation.ENCRYPT)
    private String name;
    
    @PIIData(PIIData.Operation.DECRYPT)
    private String email;
    
    private String department;
    
    // 构造器、toString等方法省略
}

步骤3:更新apply()方法,根据注解参数执行对应操作

public <T> T apply(T target) throws IllegalAccessException {
    if (target == null) {
        return null;
    }
    
    Field[] fields = target.getClass().getDeclaredFields();
    
    for (Field field : fields) {
        PIIData annotation = field.getAnnotation(PIIData.class);
        if (annotation != null) {
            field.setAccessible(true);
            Object value = field.get(target);
            
            if (value instanceof String) {
                String processedValue;
                // 根据注解指定的操作分支处理
                switch (annotation.value()) {
                    case ENCRYPT:
                        processedValue = encrypt((String) value);
                        break;
                    case DECRYPT:
                        processedValue = decrypt((String) value);
                        break;
                    default:
                        processedValue = (String) value; // 默认不处理
                }
                field.set(target, processedValue);
            }
        }
    }
    
    return target;
}

测试验证(假设email为加密后字符串)

public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        Employee emp = new Employee("Bob", "encrypted_bob@example.com", "HR");
        System.out.println("处理前: " + emp);
        
        PiiUtility utility = new PiiUtility();
        Employee processedEmp = utility.apply(emp);
        System.out.println("处理后: " + processedEmp);
    }
}

输出结果:

处理前: Employee{name='Bob', email='encrypted_bob@example.com', department='HR'}
处理后: Employee{name='encrypted_Bob', email='bob@example.com', department='HR'}

额外优化建议

  • 若需要处理父类字段,可通过Class.getSuperclass()递归扫描父类的字段。
  • 实际项目中,建议使用成熟的加密库(如BouncyCastle)实现加解密,避免示例中的简单拼接逻辑。
  • 可缓存反射获取的字段信息,避免每次调用apply()重复扫描字段,提升性能。

内容的提问来源于stack exchange,提问作者Dev-vruper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:20:26