问题:返回 ResponseEntity 类型的 Flux

Problem: Returning Flux of type ResponseEntity

我有以下片段,我想 return 来自 ResponseEntity<Response> 的 Flux:

@GetMapping("/{id}")
public Mono<ResponseEntity<Response>> findByDocumentClient(@PathVariable("id") String document){
    return Mono.just(new ResponseEntity<>(new Response(technomechanicalService.findByDocumentClient(document), HttpStatus.OK.value(), null), 
                            HttpStatus.OK))
            .onErrorResume(error -> {
                return Mono.just(new ResponseEntity<>(new Response(null, HttpStatus.BAD_REQUEST.value(), error.getMessage()), 
                                        HttpStatus.BAD_REQUEST));
            });
}

Response对象如下:

public class Response{
    private Object body;
    private Integer status;
    private String descStatus;

    public Response(Object body, Integer status, String descStatus) {
        this.body = body;
        this.status = status;
        this.descStatus = descStatus;
    }
}

使用 postman 的 Get 方法时,服务响应如下:

{
    "body": {
        "scanAvailable": true,
        "prefetch": -1
    },
    "status": 200,
    "descStatus": null
}

为什么会生成此响应?为什么对象列表没有响应?

这是因为您正在尝试命令式编码(传统 java)并且您正在序列化一个 Mono 而不是 return 从数据库中编辑的实际值。你应该在功能上编码,因为 reactor/webflux 使用这种类型的开发。

A Mono<T> 是一个 producer,当有人订阅它时会生成元素。订阅者是发起呼叫的人,在本例中为 client/browser.

这就是为什么你需要 return 一个 Mono<ResponseEntity> 因为当客户端 subscribes 它会发出一个 ResponseEntity

所以让我们看看你的代码:

@GetMapping("/{id}")
public Mono<ResponseEntity<Response>> findByDocumentClient(@PathVariable("id") String document){
    return Mono.just(new ResponseEntity<>(new Response(technomechanicalService.findByDocumentClient(document), HttpStatus.OK.value(), null), 
                            HttpStatus.OK))
            .onErrorResume(error -> {
                return Mono.just(new ResponseEntity<>(new Response(null, HttpStatus.BAD_REQUEST.value(), error.getMessage()), 
                                        HttpStatus.BAD_REQUEST));
            });
}

您要做的第一件事是使用 Mono#just 将您的回复直接放入 Mono 中。在 webflux 中,Mono 是可以发出某些东西的东西,一旦你把东西放进去,你也告诉服务器它可以自由地改变执行执行的线程。所以我们基本上想尽快进入 Mono,这样我们就可以利用 webflux 线程不可知的能力。

然后这一行:

technomechanicalService.findByDocumentClient(document)

returns a Mono<T> 然后你把它放在你的 Response body 中。因此它尝试将其序列化为 json,而您认为它采用其内部 Value 并序列化它实际上序列化 Mono.

所以让我们重写你的代码 *我现在忽略了错误处理,因为我是在移动设备上写的:

@GetMapping("/{id}")
public Mono<ServerResponse> findByDocumentClient(@PathVariable("id") String document){
    // We place our path variable in a mono so we can leverage 
    // webflux thread agnostic abilities
    return Mono.just(document)
               // We access the value by flatMapping and do our call to 
               // the database which will return a Mono<T>
               .flatMap(doc -> technomechanicalService.findByDocumentClient(doc)
                   // We flatmap again over the db response to a ServerResponse
                   // with the db value as the body
                   .flatMap(value -> ServerResponse.ok().body(value)));
}

所有这些都是非常基础的 reactor/webflux 内容。我假设这是您第一次使用 webflux。如果是这样,我强烈建议您了解 Reactor getting started 基础知识的工作原理,否则您将很难使用 Reactor,然后再理解 webflux。

同意@Toerktumlare 的回答。很全面。

@Juan David Báez Ramos 根据你的回答(如果是评论更好),你想要的似乎是将 technomechanicalService.findByDocumentClient(document) 结果作为 body 放入 Response 对象中.

如果是这样,您可以使用 Flux API 的 collectList() 运算符。

示例代码:

@GetMapping("/{id}")
public Mono<ResponseEntity<Response>> findByDocumentClient(@PathVariable("id") String document) {
    return technomechanicalService.findByDocumentClient(document)
        .collectList()
        .map(
            listOfDocuments -> {
              return new ResponseEntity<>(
                  new Response(listOfDocuments, HttpStatus.OK.value(), null), HttpStatus.OK);
            }
        )
        .onErrorResume(
            error -> {
              return Mono.just(new ResponseEntity<>(
                  new Response(null, HttpStatus.BAD_REQUEST.value(), error.getMessage()),
                  HttpStatus.BAD_REQUEST));
            }
        );
}