我想从spring的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
开箱即用,我只是搞砸了一些配置?或者我是否必须注册我的自定义处理程序或安装一些插件?
答案 0 :(得分:3)
您可以使用Spring MVC Reactive(但目前尚未作为最终版本发布)。它适用于Reactor和RxJava。你将能够编写这种控制器:
@Test
class ExampleController {
@RequestMapping("/hello")
public Single<String> hello() { return Single.just("world"); }
}
或者您可以编写自己的类适配器并将Single
转换为Spring DeferredResult
(请参阅此example)
此示例来自您可能希望直接使用的Spring Boot Starter。
答案 1 :(得分:0)
spring-cloud-netflix
中有一个返回值处理程序。 pom依赖项下面对我有用。
<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>
答案 2 :(得分:0)
如果您无法升级到弹簧反应式,则可以使用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;
}
}
答案 3 :(得分:0)
如果您使用的是Springboot 1.5 并想从restControllers返回Observable 并避免此消息: “找不到类型为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);
}