如何使spring启动MVC理解可观察对象



我想从春天的mvc控制器返回Observable。它适用于Single:

@GetMapping Object a() {return Single.just(1);}

如预期的我得到1时,我查询服务器。但是当我对Observable做同样的事情时:

@GetMapping Object a() {return Observable.just(1);}

我得到的答案是{}。spring-mvc不订阅返回的Observable,而是简单地将其序列化为json。spring-mvc可以理解Observable开箱即用,我只是搞砸了一些配置?或者我必须注册自定义处理程序或安装一些插件吗?

你可以使用Spring MVC Reactive(但它目前不是最终版本)。它与Reactor和RxJava一起工作。您将能够编写这样的控制器:

 @Test
 class ExampleController {
         @RequestMapping("/hello")
         public Single<String> hello() { return Single.just("world"); }
 }

或者您可以编写自己的类适配器并将Single转换为Spring DeferredResult(参见此示例)

这个例子来自一个Spring Boot Starter,你可能想直接使用它

spring-cloud-netflix中有一个返回值处理程序。

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-netflix-core</artifactId>
    </dependency>

我用rx 1.x

测试了这个
    <dependency>
        <groupId>io.reactivex</groupId>
        <artifactId>rxjava</artifactId>
        <version>1.1.10</version>
    </dependency>

如果你不能升级到spring-reactive,你可以使用org.springframework.web.context.request.async.DeferredResult

public class ExampleController {
    @RequestMapping("/hello")
    public DeferredResult<ResponseEntity<String>> hello() {
        DeferredResult<ResponseEntity<String>> deferredResult = new DeferredResult<>();
        // your observable
        Observable.just("world")
              .subscribe(
                      text -> deferredResult.setResult(
                                    ResponseEntity.accepted()
                                                  .contentType(MediaType.TEXT_PLAIN)
                                                  .body(text)),
                      error -> deferredResult.setResult(
                                    ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT)
                                                  .build()
              );
        return deferredResult;
    }

}

如果您使用的是springboot 1.5并希望从你的restControllers返回Observable避免这样的信息:"没有找到类型为:class io.reactivex.internal.operators.observable.ObservableMap的返回值的转换器"你必须添加两个类

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"PACKAGE CONTROLLER"})
public class DispatcherContextConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        returnValueHandlers.add(new ObservableReturnValueHandler());
    }
}

public class ObservableReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
    @Override
    public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
        return returnValue != null && supportsReturnType(returnType);
    }
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return Observable.class.isAssignableFrom(returnType.getParameterType());
    }
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) throws Exception {
        if (returnValue == null) {
            mavContainer.setRequestHandled(true);
            return;
        }
        final Observable<?> observable = Observable.class.cast(returnValue);
        WebAsyncUtils.getAsyncManager(webRequest)
            .startDeferredResultProcessing(new ObservableAdapter<>(observable), mavContainer);
    }
    public class ObservableAdapter<T> extends DeferredResult<T> {
        public ObservableAdapter(Observable<T> observable) {
            observable.subscribe(this::setResult, this::setErrorResult);
        }
    }
}
然后

 @GetMapping(path = "{idDocument}/ropObs")
    public Observable<DocumentDto> getDocumentRopObs(@PathVariable String idDocument) {
    DocumentDto r = documentService.getDocumentRopInfo(idDocument)
        .map(dtoMapper::documentBusinessToDto)
        .doOnError(error -> {throw new ApiErrorServerError(error.getMessage());})
        .blockingSingle();
        return Observable.just(r);
    }

和更好的实践

@GetMapping(path = "{idDocument}/ropObs2")
    public Observable<DocumentDto> getDocumentRopObs2(@PathVariable String idDocument) {
      return documentService.getDocumentRopInfo(idDocument).map(dtoMapper::documentBusinessToDto);
    }

相关内容

  • 没有找到相关文章

最新更新