基于自定义注解@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
相关产品推荐
相关产品推荐

