如何将findByLibraryId返回的Mono传递至最后map?响应式代码改造疑问
响应式代码改造:传递中间结果及多值处理方案
一、修正单个值传递的响应式实现
先明确原有同步代码的核心逻辑:
- 根据
libraryId查询Book,得到Optional<Book> - 若存在
Book,则用其id+1作为新的bookId;若不存在则用0 - 根据新
bookId查询关联数据,最终用原Optional<Book>和查询结果创建BookInfo
你当前的响应式代码丢失了原Book的引用,可通过在flatMap内部保留原对象的方式解决,直接在嵌套的map中使用原Book实例:
public Mono<BookInfo> get(int libraryId) { // 修正参数笔误:原代码中误用bookId,替换为入参libraryId return bookRepository.findByLibraryId(libraryId) // 当查询到Book时,保留原对象并执行后续查询 .flatMap(book -> { int targetBookId = book.id() + 1; return bookRepository.findById(targetBookId) // 直接使用原Book对象创建BookInfo .map(pages -> new BookInfo(Optional.of(book), pages)); }) // 当未查询到Book时,用0作为bookId查询,并传入空Optional .switchIfEmpty(Mono.defer(() -> bookRepository.findById(0) .map(pages -> new BookInfo(Optional.empty(), pages)) )); }
如果希望更清晰地分离逻辑,也可以用Reactor提供的Tuple2打包原Book和查询结果,再在最终map中拆解:
import reactor.util.function.Tuples; public Mono<BookInfo> get(int libraryId) { return bookRepository.findByLibraryId(libraryId) .flatMap(book -> { int targetBookId = book.id() + 1; return bookRepository.findById(targetBookId) .map(pages -> Tuples.of(Optional.of(book), pages)); }) .switchIfEmpty(Mono.defer(() -> bookRepository.findById(0) .map(pages -> Tuples.of(Optional.empty(), pages)) )) .map(tuple -> new BookInfo(tuple.getT1(), tuple.getT2())); }
二、多值传递的处理方案
当需要传递3个及以上中间值时,有三种常用方案:
1. 使用Reactor Tuple系列类
Reactor提供了Tuple3到Tuple8,可直接打包多个值,适合值数量较少的场景:
import reactor.util.function.Tuples; // 示例:传递Book、Author、Pages三个值 Mono<BookDetailInfo> getBookDetail(int bookId) { return bookRepository.findById(bookId) .flatMap(book -> authorRepository.findByBookId(book.id()) .flatMap(author -> pagesRepository.findById(book.id() + 1) .map(pages -> Tuples.of(book, author, pages)))) .map(tuple -> new BookDetailInfo( tuple.getT1(), tuple.getT2(), tuple.getT3() )); }
2. 自定义容器类
当需要传递的值较多时,自定义一个上下文类来封装所有需要的中间值,代码可读性更高:
// 自定义上下文类,封装需要传递的多值 private static class BookQueryContext { private final Book book; private final Author author; private final Publisher publisher; public BookQueryContext(Book book, Author author, Publisher publisher) { this.book = book; this.author = author; this.publisher = publisher; } // 提供getter方法 public Book getBook() { return book; } public Author getAuthor() { return author; } public Publisher getPublisher() { return publisher; } } // 使用自定义类传递多值 Mono<BookFullInfo> getBookFullInfo(int bookId) { return bookRepository.findById(bookId) .flatMap(book -> authorRepository.findByBookId(book.id()) .flatMap(author -> publisherRepository.findByBookId(book.id()) .map(publisher -> new BookQueryContext(book, author, publisher)))) .map(context -> new BookFullInfo( context.getBook(), context.getAuthor(), context.getPublisher() )); }
3. 使用Mono.zip并行合并结果
如果多个异步操作之间没有顺序依赖(不需要前一个结果作为后一个的入参),可以用Mono.zip并行执行多个查询,再合并结果:
// 示例:并行查询Book、Author、Publisher Mono<BookFullInfo> getBookFullInfo(int bookId) { Mono<Book> bookMono = bookRepository.findById(bookId); Mono<Author> authorMono = authorRepository.findByBookId(bookId); Mono<Publisher> publisherMono = publisherRepository.findByBookId(bookId); return Mono.zip(bookMono, authorMono, publisherMono) .map(tuple -> new BookFullInfo( tuple.getT1(), tuple.getT2(), tuple.getT3() )); }
内容的提问来源于stack exchange,提问作者kylie.zoltan
相关产品推荐
相关产品推荐

