反射+Jackson数据动态脱敏
我有两个字段,name和type,我想要在type为1对数据脱敏,而其他情况不脱敏:
在网上看到了很多使用Jackson的,但是并没有根据不同情况脱敏,以下是参考了deepseek的实现:
@CustomSerializer注解
@Target(ElementType.FIELD) //表示这个注解只能用在字段上
@Retention(RetentionPolicy.RUNTIME) //注解在运行时保留,可以通过反射读取
@JacksonAnnotationsInside //表示这是一个Jackson组合注解
@JsonSerialize(using = DesensitizeSerializer.class)
public @interface CustomSerializer {DesensitizeRuleEnum function();String condition() default "";
}
DesensitizeSerializer, 根据 SpEL 表达式判断是否脱敏:
public class DesensitizeSerializer extends JsonSerializer<String> implements ContextualSerializer {/*** 脱敏规则*/private DesensitizeRuleEnum rule;private String condition; // SpEL 表达式private BeanProperty property; // 当前字段属性@Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {Object currentObject = getCurrentObject(gen); // 获取当前对象boolean shouldMask = evaluateCondition(currentObject); if (shouldMask) {// 条件满足时脱敏gen.writeString(rule.function().apply(value));} else {// 条件不满足时保留原值gen.writeString(value);}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {//获取对象属性上的自定义注解CustomSerializer annotation = property.getAnnotation(CustomSerializer.class);if (annotation != null && String.class == property.getType().getRawClass()) {DesensitizeSerializer serializer = new DesensitizeSerializer();serializer.rule = annotation.function();// 注入条件表达式serializer.condition = annotation.condition();serializer.property = property;return serializer;}return prov.findValueSerializer(property.getType(), property);}private boolean evaluateCondition(Object target) {if (StringUtils.isEmpty(condition)) {return true; // 无条件默认脱敏}try {// 创建SpEL解析器ExpressionParser parser = new SpelExpressionParser();// 设置上下文(target是被序列化的对象)EvaluationContext context = new StandardEvaluationContext(target);// 执行表达式并返回布尔结果return Boolean.TRUE.equals(parser.parseExpression(condition).getValue(context, Boolean.class));} catch (Exception e) {log.warn("脱敏条件表达式执行失败: {}", condition, e);return false; // 表达式错误时不脱敏}}private Object getCurrentObject(JsonGenerator gen) {try {// 获取序列化器上下文中的输出层(底层为 BeanSerializer)Object outputContext = gen.getOutputContext();if (outputContext instanceof JsonWriteContext) {JsonWriteContext context = (JsonWriteContext) outputContext;// 通过反射获取当前对象实例Field currentValueField = JsonWriteContext.class.getDeclaredField("_currentValue");currentValueField.setAccessible(true);return currentValueField.get(context);}} catch (Exception e) {log.warn("无法获取当前对象", e);}return null;}
}
实体类:
public class Person{@CustomSerializer(function = DesensitizeRuleEnum.USERNAME, condition = "type == '1'.toString()")@Schema(description = "姓名")private String name;@Schema(description = "类别,1:xxxx,0:xxxx")private String type;
}
实现需求,结果涉及公司生产数据,就不放了