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

Posted

技术标签:

【中文标题】使用 Flux 从单个有效负载中获取项目【英文标题】:Get items from a single payload using a Flux 【发布时间】:2018-07-05 06:48:41 【问题描述】:

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

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

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

public Flux<Stack> listAll() 
    return this.webClient
            .get()
            .uri("/projects")
            .accept(MediaType.APPLICATION_JSON)
            .exchange()
            .flatMapMany(response -> response.bodyToFlux(Stack.class));

堆栈只是一个 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 建立了这种模式

任何关于我哪里出错的帮助都会很棒;

干杯!

【问题讨论】:

这个网络服务是返回一个通量还是只返回一个实体? 【参考方案1】:

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

我还没有测试这是否阻塞,但似乎工作正常。

【讨论】:

【参考方案2】:

您的 json 与您的模型类(即 Stack)不完全匹配。与 Stack 一起创建另一个这样的类

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 对象。

【讨论】:

感谢您的回答,将试一试并报告。你能解释一下为什么我链接的例子虽然使用了助焊剂吗?它也从 github 获得了一个有效载荷。另外,从我读过的所有内容来看,除了测试之外,您不应该阻止其他任何事情? 关于阻塞,你是对的,在做响应式编程时不建议做阻塞。但是在测试中没有其他方法可以不阻塞地执行代码。关于为什么它会在有效负载中获取单个项目,嗯,这有点棘手,需要进行更多调查。但是是的,这很奇怪,为什么它会获取第一个项目。

以上是关于使用 Flux 从单个有效负载中获取项目的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Gitlab webhook 事件负载中获取项目名称

使用 laravel 为不同的 API 制作单个端点

如何使用 JSON.net 处理同一属性的单个项目和数组

如何使用 JJWT 从有效负载中获取自定义字段

如何从单个项目DataFrame中获取值[重复]

StompFrameHandler 没有从消息中获取有效负载