gpt4 book ai didi

java - Spring Boot : Interceptor to read particular field from request and set it in the response

转载 作者:行者123 更新时间:2023-12-01 11:57:45 24 4
gpt4 key购买 nike

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

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

目前我所有的 Controller 功能都在读取 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;
}
}

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

如果没有,或者甚至没有,这样做的最佳方法是什么?

最佳答案

我认为不需要你自己ThreadLocal您可以使用请求属性。

@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());
}

Optional.ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.map(ServletRequestAttributes::getRequest)
.ifPresent(request -> {request.setAttribute(Common.class.getName(), common);});

return body;
}


@Override
public MyGenericPojo beforeBodyWrite(
MyGenericPojo body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {

Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.map(rc -> rc.getAttribute(Common.class.getName(), RequestAttributes.SCOPE_REQUEST))
.ifPresent(o -> {
Common common = (Common) o;
body.setCommon(common);
});

return body;
}

编辑
Optional s 可以替换为
RequestContextHolder.getRequestAttributes().setAttribute(Common.class.getName(),common,RequestAttributes.SCOPE_REQUEST);

RequestContextHolder.getRequestAttributes().getAttribute(Common.class.getName(),RequestAttributes.SCOPE_REQUEST);

编辑 2

关于线程安全

1) 标准的基于 servlet 的 Spring Web 应用程序,我们有每请求一个线程的场景。请求由工作线程之一通过所有过滤器和例程处理。处理链将从头到尾由同一个线程执行。所以 afterBodyReadbeforeBodyWrite对于给定的请求,保证由同一个线程执行。

2)您的 RequestResponseAdvice 本身是无状态的。我们使用了 RequestContextHolder.getRequestAttributes()这是 ThreadLocal 并声明为
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");

和 ThreadLocal javadoc 指出:

his class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable.



所以我没有看到这个 sulotion 有任何线程安全问题。

关于java - Spring Boot : Interceptor to read particular field from request and set it in the response,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60488621/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com