Vertx中的异步性,在设置之前列表returns为空

Asynchronicity in Vertx, list returns empty before it is set

在我的 MainVerticle 中设置了路由器

router.get("/persons").handler(ctx -> apiService.getPersons(ctx, client));

我想调用同一个主机两次,首先我需要获取人员id列表,然后调用同一主机的另一个方法来获取人员详细信息。 .所以,在这段代码中,我正在另一个代码中进行 get 调用。由于异步性,personList 是空的,因为 Vertx 不等待第二次调用的回复,第二次调用的回复稍后,但 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