问题:返回 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));
}
);
}
我有以下片段,我想 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));
}
);
}