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

基于Jackson ObjectMapper实现无注解通用JSON掩码的方案问询

Jackson ObjectMapper实现无注解字段名掩码方案

Jackson提供了完善的扩展钩子机制,可以满足你在首次序列化时基于字段名自动完成掩码的需求,无需业务代码添加注解。核心是通过**自定义BeanSerializerModifier和JsonSerializer**来实现,具体步骤如下:

核心扩展组件

1. 自定义掩码序列化器

实现JsonSerializer,封装不同字段的掩码逻辑:

// 掩码策略接口,定义不同字段的掩码规则
public interface MaskStrategy {
    String mask(String original);
}

// 手机号掩码实现示例
public class PhoneMaskStrategy implements MaskStrategy {
    @Override
    public String mask(String original) {
        return original.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
}

// 邮箱掩码实现示例
public class EmailMaskStrategy implements MaskStrategy {
    @Override
    public String mask(String original) {
        return original.replaceAll("(^[^@]{3})[^@]+@", "$1***@");
    }
}

// 通用掩码序列化器
public class MaskingSerializer extends JsonSerializer<Object> {
    private final MaskStrategy strategy;

    public MaskingSerializer(MaskStrategy strategy) {
        this.strategy = strategy;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }
        // 对非字符串类型先转为字符串再掩码
        String maskedValue = strategy.mask(value.toString());
        gen.writeString(maskedValue);
    }
}

2. 自定义SerializerModifier

通过BeanSerializerModifier拦截序列化过程,根据字段名替换对应的序列化器:

public class MaskingSerializerModifier extends BeanSerializerModifier {
    private final Map<String, MaskStrategy> fieldMaskMapping;

    public MaskingSerializerModifier(Map<String, MaskStrategy> fieldMaskMapping) {
        this.fieldMaskMapping = fieldMaskMapping;
    }

    @Override
    public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
        if (!(serializer instanceof BeanSerializer)) {
            return super.modifySerializer(config, beanDesc, serializer);
        }

        BeanSerializer beanSerializer = (BeanSerializer) serializer;
        List<BeanPropertyWriter> propertyWriters = new ArrayList<>(beanSerializer.getProperties());

        for (int i = 0; i < propertyWriters.size(); i++) {
            BeanPropertyWriter writer = propertyWriters.get(i);
            String fieldName = writer.getName();
            
            // 匹配掩码字段映射表,替换为自定义序列化器
            if (fieldMaskMapping.containsKey(fieldName)) {
                MaskStrategy strategy = fieldMaskMapping.get(fieldName);
                propertyWriters.set(i, new MaskingPropertyWriter(writer, new MaskingSerializer(strategy)));
            }
        }

        // 返回修改后的BeanSerializer
        return beanSerializer.withProperties(propertyWriters);
    }

    // 包装BeanPropertyWriter,替换字段序列化逻辑
    private static class MaskingPropertyWriter extends BeanPropertyWriter {
        private final JsonSerializer<Object> maskingSerializer;

        public MaskingPropertyWriter(BeanPropertyWriter baseWriter, JsonSerializer<Object> maskingSerializer) {
            super(baseWriter);
            this.maskingSerializer = maskingSerializer;
        }

        @Override
        public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
            Object fieldValue = get(bean);
            if (fieldValue != null) {
                gen.writeFieldName(_name);
                maskingSerializer.serialize(fieldValue, gen, prov);
                return;
            }
            // 字段值为空时沿用原有逻辑
            super.serializeAsField(bean, gen, prov);
        }
    }
}

3. 配置自定义ObjectMapper(Spring Boot场景)

将自定义的SerializerModifier注册到ObjectMapper中,并通过自动配置让其全局生效:

@Configuration
public class MaskingAutoConfiguration {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer maskingJacksonCustomizer() {
        // 构建字段名与掩码策略的映射表
        Map<String, MaskStrategy> fieldMaskMap = new HashMap<>();
        fieldMaskMap.put("phone", new PhoneMaskStrategy());
        fieldMaskMap.put("email", new EmailMaskStrategy());
        fieldMaskMap.put("idCard", original -> original.replaceAll("(\\d{6})\\d{8}(\\d{4})", "$1********$2"));
        // 可根据需求添加更多字段映射

        return builder -> builder.modules(new SimpleModule()
                .setSerializerModifier(new MaskingSerializerModifier(fieldMaskMap)));
    }
}

方案优势

  • 无侵入性:无需业务代码添加任何注解,完全在框架层实现,对开发人员透明
  • 性能优化:直接在首次序列化过程中处理,避免了先转Map再遍历修改的额外开销
  • 扩展性强:可通过修改fieldMaskMap灵活添加/调整字段的掩码策略,适配不同业务场景

内容的提问来源于stack exchange,提问作者matthenry87

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:45:37