[英]How to return a Mono<ServerResponse> (as a side effect?) of Mono.subscribe()?
我有以下代码,它“有效”......到目前为止。 通过“有效”,我的意思是Flux<DemoPOJO>
由service.getAll()
返回,并且“ hasElements().subscribe(this::foo)
”导致foo()
生成正确反映是否Flux<DemoPOJO>
有任何元素。
所需的最终状态是返回一个ServerResponse
对象,包装Flux<DemoPOJO>
,它反映返回的 Flux 是空的还是“hasElements”。
我的问题是Mono.subscribe()
返回一个reactor.core.Disposable
,我想以某种方式得到一个Mono<ServerResponse>
或者,我是“吠错树”了吗?
添加注意:我已经看到一些使用Flux.flatMap()
例子,但是如果返回的 Flux 有很多元素,这似乎有问题(即检查hasElements()
似乎比潜在地平面映射所有元素要好得多)。
@Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
@Autowired
private DemoPOJOService service;
public Mono<ServerResponse> getAll(ServerRequest request) {
Mono<ServerResponse> response = null;
Flux<DemoPOJO> entities = service.getAll();
entities.hasElements().subscribe(this::foo);
// just return something, for now
return ServerResponse.ok().build();
}
private Mono<ServerRequest> foo(Boolean hasElements) {
System.out.println("DEBUG >> Mono has elements -> " + hasElements);
return Mono.empty();
}
}
这是 DemoPOJOService 实现...
@Component
public class DemoPOJOService {
@Autowired
private DemoPOJORepo demoPOJORepo;
public Flux<DemoPOJO> getAll() {
return Flux.fromArray(demoPOJORepo.getAll());
}
// more implementation, omitted for brevity
}
而且,这里是 DemoPOJORepo 实现......
@Component
public class DemoPOJORepo {
private static final int NUM_OBJS =20;
private static DemoPOJORepo demoRepo = null;
private Map<Integer, DemoPOJO> demoPOJOMap;
private DemoPOJORepo() {
initMap();
}
public static DemoPOJORepo getInstance() {
if (demoRepo == null) {
demoRepo = new DemoPOJORepo();
}
return demoRepo;
}
public DemoPOJO[] getAll() {
return demoPOJOMap.values().toArray(new DemoPOJO[demoPOJOMap.size()]);
}
// more implementation, omitted for brevity
private void initMap() {
demoPOJOMap = new TreeMap<Integer, DemoPOJO>();
for(int ndx=1; ndx<( NUM_OBJS + 1 ); ndx++) {
demoPOJOMap.put(ndx, new DemoPOJO(ndx, "foo_" + ndx, ndx+100));
}
}
}
所以,我真的很想将先前的答案投反对票为“无响应”(因为我没有订阅Flux<DemoPOJO>
“实体”,而是订阅由'entities.hasElements()'产生的Mono 。而且,提供的“解决方案”并没有解决我对能够根据有/没有要返回的内容返回适当的ServerResponse的担忧。
然而,它确实让我进入了我认为解决我最初问题的“正确轨道”,所以......
我修改后的DemoPOJOHandler如下。 它似乎正确地返回,要么包装了“流量”的service.getAll(返回ServerResponse.ok()),或ServerResponse.noContent()如果通量是空的。
虽然这“有效”,并且似乎比我以前的要好得多,但非常感谢任何改进、评论或建议,因为我仍在尝试围绕 Reactor。
@Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
@Autowired
private DemoPOJOService service;
public Mono<ServerResponse> getAll(ServerRequest request) {
Flux<DemoPOJO> entities = service.getAll();
return entities.hasElements().flatMap(hasElement -> {
return hasElement ? ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(entities, DemoPOJO.class)
: ServerResponse.noContent().build();
});
}
}
@SoCal 您的答案似乎有效,但它有一个缺点: getAll()
DB 调用进行了两次。
困难在于您只能在开始接收数据后决定状态代码。
但由于您似乎并不真正需要主体的异步性质(您不是流式传输单个元素,而是生成一次性 JSON 响应),在这种情况下,您可以收集整个结果集并将其映射到响应.
所以调用数据库,收集Mono<List>
的元素,将其map
到 A) 404 空响应,如果列表为空,或者 B) 200 成功的 JSON 响应,否则(注意使用syncBody
):
@Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
@Autowired
private DemoPOJOService service;
public Mono<ServerResponse> getAll(ServerRequest request) {
Flux<DemoPOJO> entities = service.getAll();
Mono<List<DemoPOJO>> collected = entities.collectList();
return collected.map(list -> list.isEmpty() ?
ServerResponse.noContent().build() :
ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.syncBody(list)
);
}
}
旁注:我认为ResponseEntity
是带注释的控制器而不是ServerResponse
的首选类型,请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-ann-响应实体。
首先,您不负责订阅控制器中的通量。 获取数据并从控制器返回它只是整个管道的一小部分。 它基本上意味着您只需要提供业务逻辑,并且框架会向您的数据添加其他转换。 例如,它序列化响应,然后在完成后订阅它。
订阅业务代码中的flux意味着您启动了另一个管道,它可能完全独立于控制器返回的数据,但恰好在那里订阅了它。 如果你有相同的 Flux 并且你会在其他地方订阅它,结果将完全相同。
总结一下:您需要获取entities.hasElements()
(即Mono<Boolean>
)的返回值并将 bool 包装到响应中:
public Mono<ServerResponse> getAll(ServerRequest request) {
Mono<ServerResponse> response = null;
Flux<DemoPOJO> entities = service.getAll();
return entities.hasElements()
.flatMap(this::foo);
}
private Mono<ServerResponse> foo(Boolean hasElements) {
System.out.println("DEBUG >> Mono has elements -> " + hasElements);
return ServerResponse.ok().syncBody(hasElements);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.