SpringBoot:拦截器,用于从请求中读取特定字段并在响应中进行设置

问题描述 投票:2回答:1

我们的Spring Rest Controller处理的所有请求和响应都有一个Common部分,该部分具有某些值:

{
    "common": {
        "requestId": "foo-bar-123",
        "otherKey1": "value1",
        "otherKey2": "value2",
        "otherKey3": "value3"
    },
    ...
}

当前,我所有的控制器功能都在读取common并将其手动复制到响应中。我想将其移至某种拦截器中。

我尝试使用ControllerAdviceThreadLocal

@ControllerAdvice
public class RequestResponseAdvice extends RequestBodyAdviceAdapter
    implements ResponseBodyAdvice<MyGenericPojo> {

  private ThreadLocal<Common> commonThreadLocal = new ThreadLocal<>();

  /* Request */

  @Override
  public boolean supports(
      MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
    return MyGenericPojo.class.isAssignableFrom(methodParameter.getParameterType());
  }

  @Override
  public Object afterBodyRead(
      Object body,
      HttpInputMessage inputMessage,
      MethodParameter parameter,
      Type targetType,
      Class<? extends HttpMessageConverter<?>> converterType) {
    var common = (MyGenericPojo)body.getCommon();
    if (common.getRequestId() == null) {
       common.setRequestId(generateNewRequestId()); 
    }
    commonThreadLocal(common);
    return body;
  }

  /* Response */

  @Override
  public boolean supports(
      MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return MyGenericPojo.class.isAssignableFrom(returnType.getParameterType());
  }

  @Override
  public MyGenericPojo beforeBodyWrite(
      MyGenericPojo body,
      MethodParameter returnType,
      MediaType selectedContentType,
      Class<? extends HttpMessageConverter<?>> selectedConverterType,
      ServerHttpRequest request,
      ServerHttpResponse response) {
    body.setCommon(commonThreadLocal.get());
    commonThreadLocal.remove();
    return body;
  }
}

当我一次测试一次发送一个请求时,此方法有效。但是,当有多个请求到来时,是否可以保证在同一线程中调用afterBodyReadbeforeBodyWrite

如果不是,或者什至不是,最好的方法是什么?

java spring spring-boot rest interceptor
1个回答
0
投票

如果仅是从请求复制到响应的元数据,则可以执行以下操作之一:

1-将元数据存储在请求/响应标头中,然后使用过滤器进行复制:

@WebFilter(filterName="MetaDatatFilter", urlPatterns ={"/*"})
public class MyFilter implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;        
    httpServletResponse.setHeader("metaData", httpServletRequest.getHeader("metaData"));        
}

}

2-将工作移到服务层,您可以在其中通过可重用的通用方法来完成该工作,或者使其通过AOP运行

public void copyMetaData(whatEverType request,whatEverType response) {
    response.setMeta(request.getMeta);

}
© www.soinside.com 2019 - 2024. All rights reserved.