Spring Boot中如何根据环境配置不同的@JsonProperty属性值
解决方案
核心思路是利用Jackson的扩展能力实现动态字段名映射,结合多环境配置即可,不需要维护多套请求类,以下是3种常用的实现方案:
方案1:自定义环境感知的JsonProperty注解
通过自定义注解承载不同环境的字段ID,配合自定义序列化器动态输出对应Key。
步骤1:定义自定义注解
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface EnvJsonProperty { // 测试环境的字段ID String test(); // 生产环境的字段ID String prod(); }
步骤2:改造请求类
替换原有的@JsonProperty为自定义注解:
public class RequestClass { @EnvJsonProperty(test = "123-test", prod = "123") private String name; @EnvJsonProperty(test = "124-test", prod = "124") private String email; @EnvJsonProperty(test = "129-test", prod = "129") private String mobile; }
步骤3:实现自定义序列化器
根据当前激活的环境,动态读取对应注解值作为序列化Key:
public class EnvRequestSerializer extends StdSerializer<RequestClass> { // 从配置文件/配置中心读取当前激活环境,Spring项目可直接通过@Value注入 private final String activeEnv; public EnvRequestSerializer(String activeEnv) { super(RequestClass.class); this.activeEnv = activeEnv; } @Override public void serialize(RequestClass request, JsonGenerator gen, SerializerProvider provider) throws IOException, IllegalAccessException { gen.writeStartObject(); Field[] fields = RequestClass.class.getDeclaredFields(); for (Field field : fields) { EnvJsonProperty anno = field.getAnnotation(EnvJsonProperty.class); if (anno == null) continue; field.setAccessible(true); String key = "prod".equals(activeEnv) ? anno.prod() : anno.test(); gen.writeObjectField(key, field.get(request)); } gen.writeEndObject(); } }
步骤4:绑定序列化器
给请求类添加序列化注解即可生效:
@JsonSerialize(using = EnvRequestSerializer.class) public class RequestClass { // 字段定义不变 }
方案2:自定义Jackson字段命名策略
如果不想修改原有请求类的注解,可通过自定义PropertyNamingStrategy实现映射,映射关系完全放在配置文件中,改动量更小。
步骤1:配置多环境映射关系
将不同环境的字段映射放到对应环境的配置文件中,示例(YAML格式):
# 测试环境配置 field: mapping: name: "123-test" email: "124-test" mobile: "129-test"
# 生产环境配置 field: mapping: name: "123" email: "124" mobile: "129"
步骤2:实现自定义命名策略
public class EnvFieldNamingStrategy extends PropertyNamingStrategy { private final Map<String, String> fieldMapping; public EnvFieldNamingStrategy(Map<String, String> fieldMapping) { this.fieldMapping = fieldMapping; } @Override public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) { return fieldMapping.getOrDefault(defaultName, defaultName); } }
步骤3:绑定命名策略
将自定义命名策略设置到你用于序列化请求的ObjectMapper实例中即可:
// 从配置中读取当前环境的映射关系 Map<String, String> mapping = getEnvFieldMapping(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setPropertyNamingStrategy(new EnvFieldNamingStrategy(mapping));
方案3:请求拦截器动态替换Key
如果是老项目改造,不想修改序列化逻辑,可在请求发送前的拦截器中修改序列化后的参数Key:
- 先按原有逻辑序列化请求得到JSON字符串
- 读取当前环境的字段映射关系,遍历替换JSON的Key为对应环境的ID
- 将替换后的JSON作为请求体发送
方案选型建议
- 字段数量少、映射关系稳定:选方案1,逻辑直观,耦合度低
- 字段多、映射关系调整频繁:选方案2,修改配置即可生效,不需要动业务代码
- 老项目改造成本高:选方案3,完全不侵入原有请求类和序列化逻辑
内容的提问来源于stack exchange,提问作者smith
相关产品推荐
相关产品推荐

