簡體   English   中英

我可以將 Flux 作為 ServerResponse 正文的一個字段嗎?

[英]Can I have Flux as a field of ServerResponse body?

我是 Spring Reactive Web 的新手,我遇到了以下問題。 我想創建一個帶有接受數字 N 的端點的微服務 A,向微服務 B 發送 N 個請求(它為每個請求返回一個字符串),將字符串包裝成對象,將它們組合成 List/Flux(?)並返回帶有這些對象的 JSON,例如:

{
  "number": 4,
  "objects": [
    {
       "name": "first"
    },
    {
       "name": "second"
    },
    {
       "name": "third"
    },
    {
       "name": "fourth"
    }
  ]
}

我想為此使用功能端點。 所以我嘗試了以下方法(盡我所能簡化它):

public class MyObject {
    private String name; // here should be a value received from B
    // ...
}
public class MyResponse {
    private int number;
    private Flux<MyObject> objects; // or List?
    // ...
}
@Component
@RequiredArgsConstructor
public class MyHandler {

    private final MyClient client;

    public Mono<ServerResponse> generate(ServerRequest serverRequest) {
        return serverRequest.bodyToMono(MyRequestBody.class)
                .flatMap(request -> buildServerResponse(HttpStatus.OK, buildResponseBody(request)));
    }

    private Mono<ServerResponse> buildServerResponse(HttpStatus status, Mono<MyResponse> responseBody) {
        return ServerResponse.status(status)
                .contentType(MediaType.APPLICATION_JSON)
                .body(responseBody, MyResponse.class);
    }

    private Mono<MyResponse> buildResponseBody(MyRequestBody request) {
        return Mono.just(MyResponse.builder()
                .number(request.getNumber())
                .objects(getObjects(request.getNumber())
                .build());
    }

    private Flux<MyObject> getObjects(int n) {
        // how to receive n strings from MyClient, make MyObject from each of them and then combine them together to a Flux/List?
    }
public class MyClient {
    public Mono<String> getName() {
        WebClient client = WebClient.builder().baseUrl(getUrl()).build();

        return client.get()
                // ...
                .retrieve()
                .bodyToMono(String.class);
    }

    private String getUrl() {
        // ...
    }
}

所以,如果我在 MyResponse 中使用 Flux,我會收到如下響應:

{
  "number": 4,
  "objects": {
    "prefetch": 2147483647,
    "scanAvailable": true
  }
}

另一方面,如果我嘗試使用列表,它似乎需要在某些時候阻塞,並且我收到與之相關的錯誤。 那么,我該怎么做呢?

提前致謝!


更新:如果我使用collectList().block()從 Flux 中創建一個列表,我會收到以下信息:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread <...>

正如我從這個問題的答案中了解到的那樣,當我的方法返回Mono / Flux時,我永遠不應該阻止。 block()調用提取到從返回Mono / Flux的方法調用的單獨方法沒有幫助。 如果我在block() share() ) ,那么我的請求將永遠執行,出於某種我還不明白的原因。

好吧,我做到了。

Flux作為一個字段不能以期望的方式工作,所以我需要一個List

public class MyResponse {
    private int number;
    private List<MyObject> objects;
    // ...
}

現在我需要一種方法從多個Mono<String>中創建一個List<MyObject> ,其中每個MyObject都有一個String字段。

問題是我們永遠不會擺脫MonoFlux ,所以我們首先為Flux<MyObject>刪除 go 。

private Flux<MyObject> getObjects(int n) {
    return Flux.range(0, n) // Flux<Integer>
            .map(i -> myClient.getName()) // Flux<String>
            .map(name -> new MyObject(name)); // Flux<MyObject>
}

然后我們制作通量:

private Mono<MyResponse> buildResponseBody(MyRequestBody request) {
    return getObjects(request.getNumber()) // Flux<MyObject>
            .collectList() // Mono<List<MyObject>>
            .map(objects -> MyResponse.builder() // Mono<MyResponse>
                    .number(request.getNumber())
                    .objects(objects)
                    .build()));
}

這樣它就可以工作,因為我們不必阻止任何東西。

只有當我們想在某個時候擺脫Mono / Flux時,問題才會出現,就像我們想要一個純List<MyObject>一樣。 但只要我們有Mono和/或Flux作為輸入和 output,我們就可以使用這些類的方法進行所有操作,在每個階段保留MonoFlux

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM