使用Flux从单个有效负载中获取项目

时间:2018-01-25 22:11:35

标签: spring flux project-reactor spring-webflux

我有一个查询远程服务的方法。此服务返回一个包含许多项的有效负载。

如何使用FluxflatMapMany取出这些商品?

目前我的“从服务中获取”方法如下:

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

任何有关我出错的地方的帮助都会很棒;

干杯!

2 个答案:

答案 0 :(得分:0)

你的json与你的模型类不完全匹配,即Stack。与Stack一起创建另一个类

public class Data {
  List<Stack> data;
   // Getters and Setters.... 
}

现在,您可以在webclient中执行此操作

Mono<Data> listMono = webClient
                .get()
                .uri("/product/projects")
                .exchange()
                .flatMap(clientResponse -> clientResponse.bodyToMono(Data.class));

现在,如果你执行listMono.block(),你将获得具有所有Stack对象的Data对象。

答案 1 :(得分:0)

我想我已经解决了它,仍然使用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);
}

返回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();
}

我没有测试过这是否阻止,但似乎没有问题。