spring-boot - 在Spring Reactive Programming中如何从两个Flux(Object)获取Flux或List?

标签 spring-boot spring-webflux project-reactor reactor

我是Spring Reactive Project的新手。在我的Spring Boot Controller类中

Flux<House> ( list of all houses in the database) and Flux<Image>



来自服务层,其中给定的Flux<Image>是给定房屋的图像,例如房屋列表,每个房屋都有自己的图像集合。这意味着我必须遍历Flux<House>以获得房屋的ID,然后在Image上调用findByHouseId以获得Flux<Image>,每个Image都具有houseId属性。每个图像对象都具有字符串值"is"或“否”的属性“cover”,以及具有诸如“bedroom”之类的各种字符串值的另一个属性“type”。我想收集一个
list of Flux<Image> like List<Flux<Image>> or List<List<Image>>

仅包含“封面” =="is"或“类型” ==“卧室”的那些图像。如何实现呢?编程代码将回答这个问题。

尝试将以下方法作为解决方案的一部分,但即使是部分解决方案也无法使用:
List<Flux<Image>> imagesList= new ArrayList<Flux<Image>>();
        Flux<House> houses = houseService.findAllHouses();

        houses.map(house ->  house.getId()).subscribe(id -> imageService.findByHouseId(id))
        .map(imageFlux ->imagesList.add(imageFlux));

请注意,除非这是唯一的方法,否则我正在寻找不涉及调用block()的解决方案(否定了被动响应的优势)。

在非 react 情况下,这就是我想要的:
List<House> houses  --> List of all houses
Map<String,List<Image>> mapOfImages  --> where key is houseId 

因此,对于每个房屋,我都可以在 View 模板中遍历房屋时轻松获取该房屋的图像。

这些(房屋和mapOfImages)将传递给模型,例如
model.addAttribute("houses",houses);
model.addAttribute("mapOfImages",mapOfImages);

现在,在thyemleaf View 模板中,我可以:
<div data-th-each="house : ${houses}">
        <h3 data-th-text="${house.title}"></h3>
        <div data-th-each="image : ${mapOfImages.get(house.houseId)}">
          <h5 data-th-text="${image.fileName}"></h5>
          <h5 data-th-text="${image.type}"></h5>
        </div>
 </div>   

正在使用的数据库是Mongodb,它具有两个独立的集合:房屋和图像,即没有嵌入式集合,并且将图像与房屋联系起来的唯一东西是图像上的houseId属性。

最佳答案

您基本上想将House对象流转换为Image对象流。

因此,请使用flatMap(),它将Flux<Flux<T>>(或Flux<Mono<T>>)转换为Flux<T>

Mono<List<Image>> images = houseService.findAllHouses() // returns Flux<House>
  .flatMap(house -> imageService.findByHouseId(id)      // returns Flux<Image>
                        .filter(image -> "yes".equals(image.getCover()) && ... )) 
  .collectList();                                       //returns Mono<List<Image>>

在这里使用collectList()是可以的,因为您很可能仍希望将images转换为单个Mono<ServerResponse>对象:
return images.map(imageList -> ServerResponse.ok()
                                       .body(fromObject(imageList)));

另外,我建议阅读有关Project Reactor referencewhen to use which operator

编辑:

因此,您需要一个Mono<Map<String, Collection<Image>>。我的答案将取决于Image类是否具有对House的引用。否则,仍然可以,但是答案会更加冗长。

我将描述一种很难的方法,其中Image不包含House id。我们需要……,它链接属于特定房屋的图像列表。您可以为此目的定义一个类,也可以只使用reactor.util.function.Tuple2。有了它,我们可以只使用collectMap():
Mono<Map<String, Collection<Image>>> images = houseService.findAllHouses()
     .flatMap(house -> imageService.findByHouseId(id)
                           .filter(...)
                           .map(image -> Tuples.of(id, image)))
     .collectMultiMap(tuple -> tuple.getT1(), 
                      tuple -> tuple.getT2());

当然,如果您有对House的引用,则可以再次省略map()并直接使用collectMultiMap:
...
    .collectMultiMap(image -> image.getHouseId(), image -> image);

关于spring-boot - 在Spring Reactive Programming中如何从两个Flux(Object)获取Flux或List?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49676422/

相关文章:

spring boot rest tomcat部署报错

java - Kafka 消费者在 SSL 上抛出 "OutOfMemoryError: Java heap space"错误

java - 如何将 Micrometer 计时器与 webflux 端点一起使用

maven - 使用 “spring-boot-starter-parent”时如何在Maven中使用较低的Elastic搜索版本

spring - 在 Spring Webflux 功能应用程序中验证请求的最佳方法是什么

java - Containing 可以用在 Spring Data 中的列表上吗?

java - Spring boot Redis @Cacheable 方法没有被另一个类调用

spring - 立即返回 Spring 网通量

java - 如何正确使用 Reactor Publisher

java - SubscribeOn 仅使用池中的 1 个线程