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

基于Spring Boot+JsonView实现多客户端接口字段动态控制

实现基于请求头自动匹配JsonView的方案

1. 定义客户端与JsonView的映射关系

先创建枚举类,将请求头中的客户端标识与对应的JsonView视图类绑定,同时提供默认视图兜底:

public enum ClientViewMapping {
    CLIENT_A("client-a", ClientAView.class),
    CLIENT_B("client-b", ClientBView.class),
    DEFAULT("default", DefaultView.class);

    private final String clientId;
    private final Class<?> viewClass;

    ClientViewMapping(String clientId, Class<?> viewClass) {
        this.clientId = clientId;
        this.viewClass = viewClass;
    }

    public static Class<?> getViewByClientId(String clientId) {
        for (ClientViewMapping mapping : values()) {
            if (mapping.clientId.equals(clientId)) {
                return mapping.viewClass;
            }
        }
        return DEFAULT.viewClass;
    }
}

2. 自定义ResponseBodyAdvice动态切换视图

利用Spring的ResponseBodyAdvice拦截响应,根据请求头获取对应视图并设置到Jackson序列化配置中:

@ControllerAdvice
public class DynamicJsonViewAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 仅处理Jackson格式的响应转换器
        return MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        // 从请求头提取客户端标识
        String clientId = request.getHeaders().getFirst("X-Client-Id");
        Class<?> targetView = ClientViewMapping.getViewByClientId(clientId);

        // 将响应包装为MappingJacksonValue并设置视图
        if (body instanceof MappingJacksonValue) {
            ((MappingJacksonValue) body).setSerializationView(targetView);
            return body;
        } else {
            MappingJacksonValue container = new MappingJacksonValue(body);
            container.setSerializationView(targetView);
            return container;
        }
    }
}

3. 控制器与实体类配置

控制器无需手动指定@JsonView,直接返回实体即可:

@RestController
@RequestMapping("/api/data")
public class DataController {

    @GetMapping
    public DataEntity getData() {
        DataEntity entity = new DataEntity();
        // 填充业务数据
        return entity;
    }
}

实体类保留@JsonView注解,对应各客户端视图:

public class DataEntity {
    @JsonView({DefaultView.class, ClientAView.class, ClientBView.class})
    private String id;

    @JsonView({DefaultView.class, ClientAView.class})
    private String commonField;

    @JsonView(ClientAView.class)
    private String clientAField;

    @JsonView(ClientBView.class)
    private String clientBField;

    // getter、setter方法
}

// 视图类定义(可通过继承复用字段规则)
public class DefaultView {}
public class ClientAView extends DefaultView {}
public class ClientBView extends DefaultView {}

4. 验证逻辑

  • 客户端请求时添加请求头X-Client-Id: client-a,将返回包含id、commonField、clientAField的响应
  • 添加请求头X-Client-Id: client-b,将返回包含id、commonField、clientBField的响应
  • 无该请求头时,默认返回id、commonField字段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:17:20