首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring + DeferredResult添加Hateoas

Spring + DeferredResult添加Hateoas
EN

Stack Overflow用户
提问于 2015-02-16 11:27:53
回答 2查看 1.3K关注 0票数 5

对于rest接口,使用了从控制器返回的Spring + RxJava + DeferredResult。

我正在考虑在端点中添加Hateoas支持。自然的选择是春天的Hateoas。问题是Spring在异步/多线程环境中无法工作,因为它使用ThreadLocal。

有什么办法可以解决这个限制吗?我不这么认为,但也许有人有任何建议。

是否有人使用其他API将Hateoas支持添加到其他端点?

谢谢。

EN

回答 2

Stack Overflow用户

发布于 2015-11-09 15:12:12

因此,我使用的解决方案是关闭请求属性,然后将它们作为lift操作符的一部分应用

代码语言:javascript
复制
public class RequestContextStashOperator<T> implements Observable.Operator<T, T> {

    private final RequestAttributes attributes;

    /**
     * Spring hateoas requires the request context to be set but observables may happen on other threads
     * This operator will reapply the context of the constructing thread on the execution thread of the subscriber
     */
    public RequestContextStashOperator() {
        attributes = RequestContextHolder.currentRequestAttributes();
    }
    @Override
    public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
        return new Subscriber<T>() {
            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }

            @Override
            public void onNext(T t) {
                RequestContextHolder.setRequestAttributes(attributes);
                subscriber.onNext(t);
            }
        };
    }
}

然后你可以用在一个可以观察到的

代码语言:javascript
复制
lift(new RequestContextStashOperator<>())

只要对象是在与请求相同的线程中创建的。然后,您可以在可观察到的链中使用一个映射,将您的对象映射为一个资源,并在其中添加仇恨链接。

票数 4
EN

Stack Overflow用户

发布于 2015-10-28 14:31:54

所以答案有点晚了,但可能有人会发现它有用。关于ThreadLocal,您是正确的--如果您在不同的线程中生成仇恨链接,那么它会在异常情况下失败。我找到了一些解决办法:

代码语言:javascript
复制
@RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
DeferredResult<ResponseEntity<ProductResource>> example(@PathVariable("id") final String productId, final HttpServletRequest request) {

    final DeferredResult<ResponseEntity<ProductResource>> deferredResult = new DeferredResult<>();

    request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());
    final RequestAttributes requestAttributes = new ServletRequestAttributes(request);

    productByIdQuery.byId(UUID.fromString(productId)).subscribe(productEntity -> {
        RequestContextHolder.setRequestAttributes(requestAttributes);
            deferredResult.setResult(result, HttpStatus.OK))
    }, deferredResult::setErrorResult);

    return deferredResult;
}

因此,正如您所看到的,我保存了RequestAttributes,以便稍后在回调中设置它们。这仅仅解决了问题的一部分-您将得到另一个异常,因为您将失去contextPath属性。为了避免这种情况,显式地保存它:

代码语言:javascript
复制
request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());

在这些变化之后,一切看起来都正常,当然看起来很混乱。我希望有人能提供更优雅的解决方案。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28540421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档