我们的Spring Rest Controller处理的所有请求和响应都有一个Common部分,该部分具有某些值:
{
"common": {
"requestId": "foo-bar-123",
"otherKey1": "value1",
"otherKey2": "value2",
"otherKey3": "value3"
},
...
}
当前,我所有的控制器功能都在读取common
并将其手动复制到响应中。我想将其移至某种拦截器中。
我尝试使用ControllerAdvice
和ThreadLocal
:
@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;
}
}
当我一次测试一次发送一个请求时,此方法有效。但是,当有多个请求到来时,是否可以保证在同一线程中调用afterBodyRead
和beforeBodyWrite
?
如果不是,或者什至不是,最好的方法是什么?
如果仅是从请求复制到响应的元数据,则可以执行以下操作之一:
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);
}