尝试使用返回{"next": boolean, "result": [some data]}
的端点,其中“ next”表示存在更多数据/页面。
我们使用vert.x的Web客户端和rxjava api,到目前为止,成功完成了以下代码:
public Single<JsonArray> getData() {
return Observable
.range(1, Integer.MAX_VALUE)
.flatMapSingle(page -> Single.just(webClient.getAbs(API_URL + "?page=" + page)
.rxSend()
.subscribeOn(Schedulers.newThread())
.blockingGet()))
.takeUntil(response -> response.bodyAsJsonObject().getBoolean("next") == false)
.map(response -> {
if (response.statusCode() == 200) {
return response.bodyAsJsonObject().getJsonArray("results");
}
})
.collect(JsonArray::new, JsonArray::addAll);
}
我们也确信这不是一个好方法……创建一个新线程然后将其阻止。任何人都可以提出正确的方法,谢谢。
更新:使用BehaviorSubject的非阻塞解决方案:
public Single<JsonArray> getData(Instant start, Instant end, Integer departmentId, Integer duration) {
BehaviorSubject<Integer> pageControl = BehaviorSubject.createDefault(1);
return pageControl
.concatMapSingle(page -> webClient.getAbs(API_URL + "?page=" + page)
.rxSend()
.doOnSuccess(response -> {
if (response.bodyAsJsonObject().getBoolean("next")) {
pageControl.onNext(pageControl.getValue() + 1);
} else {
pageControl.onComplete();
}
})
.doOnError(pageControl::onError))
.map(response -> {
if (response.statusCode() == 200) {
return response.bodyAsJsonObject().getJsonArray("results");
}
})
.collect(JsonArray::new, JsonArray::addAll);
}
答案 0 :(得分:1)
怀疑,blockingGet
将阻止事件循环,这将破坏Vert.x golden rule。
异步递归函数在这里会有所帮助:
public Single<JsonArray> getData() {
return loadPage(0).collect(JsonArray::new, JsonArray::addAll);
}
public Observable<JsonArray> loadPage(int page) {
return webClient.getAbs(API_URL + "?page=" + page)
.expect(ResponsePredicate.SC_OK)
.expect(ResponsePredicate.JSON)
.as(BodyCodec.jsonObject())
.rxSend()
.flatMapObservable(response -> {
JsonObject body = response.body();
Observable<JsonArray> results = Observable.just(body.getJsonArray("results"));
return !body.getBoolean("next") ? results : results.concatWith(loadPage(page + 1));
});
}
使用这种功能,页面将总是一个接一个地加载,并且不会产生额外的请求。
请注意,为简化状态,内容类型和正文处理,上面的代码段使用了响应谓词和正文编解码器。