简体   繁体   English

Webflux链接多个Mono

[英]Webflux Chaining multiple Mono

I am new to reactive programming (Spring webflux) and wanted how to best handle this use case.我是响应式编程(Spring webflux)的新手,想知道如何最好地处理这个用例。 I have a reactive service call ( getAccount ) that returns Mono and I want to chain it with another service call getBooks that returns Mono<Set> and one final synchronous call transform that perform some kind of transformation and returns something like Mono<Set> How would I chain and return the transformed data in the form of Mono<Set> while logging warnings when getAccount or getBooks are returning empty?我有一个返回Mono的反应式服务调用( getAccount ),我想将它与另一个返回Mono<Set>的服务调用getBooks和一个执行某种转换并返回类似Mono<Set>的最终同步调用转换链接起来。当getAccountgetBooks返回空时记录警告时,我会以Mono<Set>的形式链接并返回转换后的数据吗? Here is a simplified version of what I am trying to do as an example.这是我试图做的一个简化版本的例子。

Given some fake services here鉴于这里有一些虚假服务

 public static Mono<String> getAccount(String name){
        return Mono.just(name);
    }
    public static Mono<Set<Book> getBooks(String title){
        return Mono.just(Sets.newHashSet(new Book(title + "One", "Author One"),
            new Book(title +"Two", "Author Two"),
            new Book(title + "Three", "Author Three")));

    }
    public static LibraryBook transform (Book a){
        return new LibraryBook(a.getTitle(), a.getAuthorName(), "someUniqueId");
    }

I wanted to get the account of a given user and find all the books that he/she borrowed and transform the books and return the value as a Mono<Set> while logging warnings where appropriate我想获取给定用户的帐户并找到他/她借的所有书籍并转换书籍并将值作为 Mono<Set> 返回值,同时在适当的地方记录警告

Here is my start这是我的开始

public Mono<Set<LibraryBook>> getBorrowedBooks(String userId) {
     return getAccount(userId)
            .flatMap(account ->  getBooks(account))
            .log()
            .map(books -> books.stream().map(book -> transform(book)).collect(Collectors.toSet()))
          
}

However, I am not sure if mixing reactive and stream is a bad thing and it just does not look right.但是,我不确定混合反应式和 stream 是否是一件坏事,而且看起来不正确。

Update:更新:

Since you cant modify the getBooks method, you can construct your getBorrowedBooks method in the following way to avoid dealing with stream.由于无法修改getBooks方法,因此可以按以下方式构造getBorrowedBooks方法,以避免与 stream 打交道。

Note- the loggers and exceptions are just for example.注意 - 记录器和异常只是示例。 You can handle empty scenarios in different ways too.你也可以用不同的方式处理空场景。

public class MyApp {

  private static final Logger LOGGER = LoggerFactory.getLogger(MyApp.class);

  public static void main(String[] args) {

    List<LibraryBook> libraryBooks = getBorrowedBooks("Abhi").collectList().block();
    libraryBooks.forEach(System.out::println);
  }

  public static Mono<String> getAccount(String name) {
    return Mono.just(name);
  }

  public static Mono<Set<Book>> getBooks(String title) {
    return Mono.just(Sets.newHashSet(new Book(title + "One", "Author One"),
        new Book(title + "Two", "Author Two"),
        new Book(title + "Three", "Author Three")));

  }

  public static LibraryBook transform(Book a) {
    return new LibraryBook(a.getTitle(), a.getAuthorName(), "someUniqueId");
  }

  public static Flux<LibraryBook> getBorrowedBooks(String userId) {
    return getAccount(userId)
        .switchIfEmpty(Mono.defer(() -> {
          LOGGER.error("No account found");
          return Mono.error(new NoAccountFoundException());
        }))
        .flatMap(account -> getBooks(account))
        .flatMapMany(Flux::fromIterable)
        .switchIfEmpty(Mono.defer(() -> {
          LOGGER.error("No books found for account");
          return Mono.error(new NoBooksFoundForGivenAccountException());
        }))
        .map(MyApp::transform);
  }

Compile wise this is correct.明智地编译这是正确的。 But logically, I think this is incorrect because you are not considering the definitions of mono and flux.但从逻辑上讲,我认为这是不正确的,因为您没有考虑 mono 和通量的定义。

Mono is a stream of 0..1 elements. Mono 是 0..1 个元素的 stream。 Flux is a stream which can emit 0..N elements. Flux 是一个 stream 可以发射 0..N 个元素。

The method getBooks (as the name suggests) should emit more than 1 element (which is Book here) for a given title. getBooks方法(顾名思义)应该为给定的标题发出超过 1 个元素(这里是 Book)。 So it's return type should be flux instead of Mono of a collection.所以它的返回类型应该是flux而不是集合的Mono。

Even you can take examples from the Spring's reactive repository methods:甚至您也可以从 Spring 的响应式存储库方法中获取示例:

ReactiveCrud 存储库

Now the idea of removing duplicates and storing a collection in a hashset, in reactive world, is synonymous to calling distinct() on a Flux of elements.现在,在响应式世界中,删除重复项并将集合存储在哈希集中的想法与在 Flux 元素上调用distinct()同义。

Flux.distinct()

So your getBooks method should look like:因此,您的getBooks方法应如下所示:

  public static Flux<Book> getBooks(String title){

    return Flux.just(new Book(title + "One", "Author One"),
        new Book(title +"Two", "Author Two"),
        new Book(title + "Three", "Author Three"))
        .distinct();

  }

And your getBorrowedBooks method should look like:您的getBorrowedBooks方法应如下所示:

  public Flux<LibraryBook> getBorrowedBooks(String userId) {
    return getAccount(userId)
        .flatMapMany(account -> getBooks(account))
        .log()
        .map(book -> transform(book));
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM