[英]Asynchronicity in Vertx, list returns empty before it is set
在我的MainVerticle中,設置路由器
router.get("/persons").handler(ctx -> apiService.getPersons(ctx, client));
我想兩次調用同一主機,首先我需要獲取人員ID列表,然后調用同一主機的另一種方法以獲取人員詳細信息。 。 因此,在這段代碼中,我正在另一個代碼中進行get調用。 由於異步性,由於Vertx不等待第二個呼叫的答復,所以personList為空,第二個呼叫的答復稍后出現,但是personList當然為空。 在我的測試案例中,迭代器有兩個元素。 我應該如何實現它,以確保可以正確返回列表?
public void getPersons(RoutingContext routingContext, WebClient client){
logger.info("getpersons");
routingContext.response().headers().add("content-type", "application/json");
String wshost= ConfigUtils.getStringConfig(vertx,"personws.url");
String url = wshost+"/persons";
client.getAbs(url).send(response -> {
try {
if (response.succeeded() && response.result().statusCode()==200) {
List<Person> personList = new ArrayList<Person>();
logger.info("Server content " + response.result().bodyAsString());
Iterator<Object> iterator = response.result().bodyAsJsonArray().iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
JsonObject jsonPerson = (JsonObject) obj ;
logger.debug("personId: {}", jsonPerson.getString("id"));
Person person = new Person();
person.setId(jsonPerson.getString("id"));
String url2 = wshost+"/persons/"+jsonPerson.getString("id");
logger.info("Calling ws to get person details for : {}", jsonPerson.getString("id"), url2);
client.getAbs(url2).send(response2 -> {
if (response2.succeeded() && response2.result().statusCode()==200) {
JsonObject jsonDetails = response2.result().bodyAsJsonObject();
person.setDetail(jsonDetails);
personList.add(person);
logger.info("person is {} ", person);
logger.info("iterator.hasNext():{}", iterator.hasNext());
}
else{
routingContext.response().setStatusCode(500);
routingContext.response().end(buildError("Failed to get json ", 600).encode());
}
});
};
logger.info("personList: {} ", personList);
logger.info("personList size {} ", personList.size());
routingContext.response().setStatusCode(200).end(new JsonArray(personList).toString());
} else {
logger.error("Cannot get persons");
routingContext.response().setStatusCode(500);
routingContext.response().end(buildError("Failed to get persons", 100).encode());
}
} catch (Exception e) {
e.printStackTrace();
routingContext.response().setStatusCode(500);
routingContext.response().end(buildError("Exception in API- Failed to get get persons for fleet "+routingContext.request().headers().get("fleet"), 300).encode());
}
});
}
首先,您不會只兩次呼叫主機。 您將其稱為n + 1次,即您最初請求中的人數。
實現您所需的最簡單方法是計算您希望獲得的人數:
int expected = response.result().bodyAsJsonArray().size();
Iterator<Object> iterator = response.result().bodyAsJsonArray().iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
JsonObject jsonPerson = (JsonObject) obj ;
logger.debug("personId: {}", jsonPerson.getString("id"));
Person person = new Person();
person.setId(jsonPerson.getString("id"));
String url2 = wshost+"/persons/"+jsonPerson.getString("id");
logger.info("Calling ws to get person details for : {}", jsonPerson.getString("id"), url2);
client.getAbs(url2).send(response2 -> {
if (response2.succeeded() && response2.result().statusCode()==200) {
JsonObject jsonDetails = response2.result().bodyAsJsonObject();
person.setDetail(jsonDetails);
personList.add(person);
logger.info("person is {} ", person);
logger.info("iterator.hasNext():{}", iterator.hasNext());
// That's the last one
if (personList.size() == expected) {
// Only now complete the request
routingContext.response().setStatusCode(200).end(new JsonArray(personList).toString());
}
}
else{
routingContext.response().setStatusCode(500);
routingContext.response().end(buildError("Failed to get json ", 600).encode());
}
});
};
logger.info("personList: {} ", personList);
logger.info("personList size {} ", personList.size());
// Moved inside callback
其他方法是使用CompositeFuture: http : //vertx.io/docs/vertx-core/groovy/#_concurrent_composition
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.