使用 Flux 从单个负载中获取项目
Get items from a single payload using a Flux
我有一个查询远程服务的方法。此服务 returns 包含许多项目的单个有效载荷。
如何使用 Flux
和 flatMapMany
取出这些物品?
目前我的 "fetch from service" 方法如下所示:
public Flux<Stack> listAll() {
return this.webClient
.get()
.uri("/projects")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMapMany(response -> response.bodyToFlux(Stack.class));
}
Stack 只是一个 POJO,看起来像:
public class Stack {
String id;
String name;
String title;
String created;
}
这里没什么特别的,但我认为我的解串器是错误的:
protected Stack deserializeObject(JsonParser jsonParser, DeserializationContext deserializationContext, ObjectCodec objectCodec, JsonNode jsonNode) throws IOException {
log.info("JsonNode {}", jsonNode);
return Stack.builder()
.id(nullSafeValue(jsonNode.findValue("id"), String.class))
.name(nullSafeValue(jsonNode.findValue("name"), String.class))
.title(nullSafeValue(jsonNode.findValue("title"), String.class))
.created(nullSafeValue(jsonNode.findValue("created"), String.class))
.build();
}
我注意到发生的事情是第一个对象被正确序列化,但随后它似乎再次被序列化,而不是负载中的下一个对象。
传入的有效负载遵循标准 JSON API 规范,看起来像:
{
"data":[
{
"type":"stacks",
"id":"1",
"attributes":{
"name":"name_1",
"title":"title_1",
"created":"2017-03-31 12:27:59",
"created_unix":1490916479
}
},
{
"type":"stacks",
"id":"2",
"attributes":{
"name":"name_2",
"title":"title_2",
"created":"2017-03-31 12:28:00",
"created_unix":1490916480
}
},
{
"type":"stacks",
"id":"3",
"attributes":{
"name":"name_3",
"title":"title_3",
"created":"2017-03-31 12:28:01",
"created_unix":1490916481
}
}
]
}
我将此模式基于 spring-reactive-university
任何关于我哪里出错的帮助都很棒;
干杯!
您 json 与您的模型 class 不完全匹配,即 Stack。与 Stack 一起创建另一个 class 像这样
public class Data {
List<Stack> data;
// Getters and Setters....
}
现在在您的网络客户端中,您可以这样做
Mono<Data> listMono = webClient
.get()
.uri("/product/projects")
.exchange()
.flatMap(clientResponse -> clientResponse.bodyToMono(Data.class));
现在,如果您这样做 listMono.block()
,您将获得包含所有 Stack 对象的 Data 对象。
我想我已经解决了,仍然使用 Flux
。
public Flux<Stack> listAllStacks() {
return this.webClient
.get()
.uri("/naut/projects")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(response -> response.toEntity(String.class))
.flatMapMany(this::transformPayloadToStack);
}
将传入的有效负载转换为 String
,然后我可以在其中使用 jsonapi library
对其进行解析
private Flux<Stack> transformPayloadToStack(ResponseEntity<String> payload) {
ObjectMapper objectMapper = new ObjectMapper();
ResourceConverter resourceConverter = new ResourceConverter(objectMapper, Stack.class);
List<Stack> stackList = resourceConverter.readDocumentCollection(payload.getBody().getBytes(), Stack.class).get();
return Flux.fromIterable(stackList);
}
其中returns一个Flux
。感谢图书馆,我也不需要创建一堆域,我仍然可以使用我简单的 Stack
POJO
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@Type("stacks")
public class Stack {
@com.github.jasminb.jsonapi.annotations.Id
String id;
String name;
String title;
String created;
}
而这又是从控制器调用的
@GetMapping("/stacks")
@ResponseBody
public Flux<Stack> findAll() {
return this.stackService.listAllStacks();
}
我还没有测试这是否阻塞,但似乎工作正常。
我有一个查询远程服务的方法。此服务 returns 包含许多项目的单个有效载荷。
如何使用 Flux
和 flatMapMany
取出这些物品?
目前我的 "fetch from service" 方法如下所示:
public Flux<Stack> listAll() {
return this.webClient
.get()
.uri("/projects")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMapMany(response -> response.bodyToFlux(Stack.class));
}
Stack 只是一个 POJO,看起来像:
public class Stack {
String id;
String name;
String title;
String created;
}
这里没什么特别的,但我认为我的解串器是错误的:
protected Stack deserializeObject(JsonParser jsonParser, DeserializationContext deserializationContext, ObjectCodec objectCodec, JsonNode jsonNode) throws IOException {
log.info("JsonNode {}", jsonNode);
return Stack.builder()
.id(nullSafeValue(jsonNode.findValue("id"), String.class))
.name(nullSafeValue(jsonNode.findValue("name"), String.class))
.title(nullSafeValue(jsonNode.findValue("title"), String.class))
.created(nullSafeValue(jsonNode.findValue("created"), String.class))
.build();
}
我注意到发生的事情是第一个对象被正确序列化,但随后它似乎再次被序列化,而不是负载中的下一个对象。
传入的有效负载遵循标准 JSON API 规范,看起来像:
{
"data":[
{
"type":"stacks",
"id":"1",
"attributes":{
"name":"name_1",
"title":"title_1",
"created":"2017-03-31 12:27:59",
"created_unix":1490916479
}
},
{
"type":"stacks",
"id":"2",
"attributes":{
"name":"name_2",
"title":"title_2",
"created":"2017-03-31 12:28:00",
"created_unix":1490916480
}
},
{
"type":"stacks",
"id":"3",
"attributes":{
"name":"name_3",
"title":"title_3",
"created":"2017-03-31 12:28:01",
"created_unix":1490916481
}
}
]
}
我将此模式基于 spring-reactive-university
任何关于我哪里出错的帮助都很棒;
干杯!
您 json 与您的模型 class 不完全匹配,即 Stack。与 Stack 一起创建另一个 class 像这样
public class Data {
List<Stack> data;
// Getters and Setters....
}
现在在您的网络客户端中,您可以这样做
Mono<Data> listMono = webClient
.get()
.uri("/product/projects")
.exchange()
.flatMap(clientResponse -> clientResponse.bodyToMono(Data.class));
现在,如果您这样做 listMono.block()
,您将获得包含所有 Stack 对象的 Data 对象。
我想我已经解决了,仍然使用 Flux
。
public Flux<Stack> listAllStacks() {
return this.webClient
.get()
.uri("/naut/projects")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(response -> response.toEntity(String.class))
.flatMapMany(this::transformPayloadToStack);
}
将传入的有效负载转换为 String
,然后我可以在其中使用 jsonapi library
private Flux<Stack> transformPayloadToStack(ResponseEntity<String> payload) {
ObjectMapper objectMapper = new ObjectMapper();
ResourceConverter resourceConverter = new ResourceConverter(objectMapper, Stack.class);
List<Stack> stackList = resourceConverter.readDocumentCollection(payload.getBody().getBytes(), Stack.class).get();
return Flux.fromIterable(stackList);
}
其中returns一个Flux
。感谢图书馆,我也不需要创建一堆域,我仍然可以使用我简单的 Stack
POJO
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@Type("stacks")
public class Stack {
@com.github.jasminb.jsonapi.annotations.Id
String id;
String name;
String title;
String created;
}
而这又是从控制器调用的
@GetMapping("/stacks")
@ResponseBody
public Flux<Stack> findAll() {
return this.stackService.listAllStacks();
}
我还没有测试这是否阻塞,但似乎工作正常。