应将firstResponse
和secondResponse
合并为CombinationBothResponses
,并在调用GET端点127.0.0.1:8081/comb
时返回。但是,在第一次调用时返回正确组合的响应:
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit ...",
"bodySecondResponse": "est rerum tempore ..."
}
但是在以后的所有调用中只返回firstResponse:
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit ...",
"bodySecondResponse": null
}
如何实现总是返回组合响应?
@RestController
public class Controller {
@Autowired Service service;
@GetMapping("/comb")
public CompletableFuture<CombinationBothResponses> combine() {
CompletableFuture<CombinationBothResponses> resultCallback = new CompletableFuture<>();
service.sendTwoRequests(resultCallback);
return resultCallback;
}
}
@org.springframework.stereotype.Service
public class Service {
private final Jsonb jsonb = JsonbBuilder.create();
private final OkHttpClient client = new OkHttpClient();
public void sendTwoRequests(CompletableFuture<CombinationBothResponses> resultCallback) {
// 1. Send GET request 1
Request firstRequest =
new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/1").build();
client.newCall(firstRequest).enqueue(new firstCallback(resultCallback));
// 2. Send GET request 2
Request secondRequest =
new Request.Builder().url("https://jsonplaceholder.typicode.com/posts/2").build();
resultCallback.thenAccept(
firstResponse -> {
client.newCall(secondRequest).enqueue(new secondCallback(resultCallback));
});
}
}
public class firstCallback implements Callback {
private final Jsonb jsonb = JsonbBuilder.create();
private final CompletableFuture<CombinationBothResponses> resultCallback;
public firstCallback(CompletableFuture<CombinationBothResponses> resultCallback) {
this.resultCallback = resultCallback;
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
var firstResponse = jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
if (response.isSuccessful()) {
resultCallback.complete(firstResponse);
} else {
resultCallback.completeExceptionally(new RuntimeException());
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
resultCallback.completeExceptionally(e);
}
}
public class secondCallback implements Callback {
private final Jsonb jsonb = JsonbBuilder.create();
private final CompletableFuture<CombinationBothResponses> resultCallback;
public secondCallback(CompletableFuture<CombinationBothResponses> resultCallback) {
this.resultCallback = resultCallback;
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
var secondResponse = jsonb.fromJson(response.body().string(), CombinationBothResponses.class);
if (response.isSuccessful()) {
// 3. Combine firstResponse and secondResponse to the final response of the REST
// controller
resultCallback.thenApply(
firstResponse -> {
firstResponse.setBodySecondResponse(secondResponse.getBody());
System.out.println(firstResponse.getBodySecondResponse() != null); // true
return firstResponse;
});
} else {
resultCallback.completeExceptionally(new RuntimeException());
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
resultCallback.completeExceptionally(e);
}
}
@Data
@NoArgsConstructor
public class CombinationBothResponses {
private int userId;
private int id;
private String title;
private String body;
private String bodySecondResponse;
}
当您在firstCallback
中调用resultCallback.complete(firstResponse);
时,您完成了在控制器中发起的请求。
为什么第一次答案是正确的可能取决于第一个请求在代码到达secondCallback
上的thenApply
之前第一次完成的速度。(之后,可能缓存使第一个请求完成得更快,代码没有时间到达thenApply
)。
您需要在方法中拆分两个请求,每个请求返回一个CompletableFuture
,然后,在更高的级别上使用thenApply
或thenCombine
来链接两个请求。
看看我以前提供的类似答案。
创建两个不同的可完备化的供应商,然后把他们两人和返回最后由对象。
,
//Async supplier for the api calls
CompletableFuture<ResponseType1> cf1 = CompletableFuture.supplyAsync(() -> method(returnSyncResponseType1);
CompletableFuture<ResponseType2> cf2 = CompletableFuture.supplyAsync(() -> returnSyncResponseType2);
//composing result for these async supplier
CompleteableFuture.allOf(resp1, resp2).thenApply(new ComposedResponse(cf1.join, cf2.join));