Spring Data Reactive不支持Page返回类型,如何组合查询实现分页?
实现Reactive环境下的分页返回
Mono<Page<Person>> 当然可以实现!Spring Data Reactive确实不直接支持返回Page类型,但我们可以借助Reactive的异步组合操作手动构造出Mono<Page<Person>>,具体思路和代码示例如下:
核心思路
Spring Data的Page接口本质上需要三个核心信息:分页后的内容列表、分页参数(Pageable)、总记录数。而PageImpl是Page的默认实现类,我们可以用它来组装这些信息。
我们需要做的就是:
- 将获取结果列表的
Flux<Person>转换为Mono<List<Person>>(因为Page需要完整的列表数据) - 合并列表数据和总记录数这两个异步结果
- 用这两个结果加上分页参数构造
PageImpl实例
代码实现
1. Repository层定义
首先确保你的Reactive Repository里有对应的列表查询和计数方法:
public interface PersonRepository extends ReactiveMongoRepository<Person, String> { // 带分页参数的列表查询(如果有过滤条件,要在这里加上) Flux<Person> findAllBy(Pageable pageable); // 总记录数查询(如果有过滤条件,要和列表查询保持一致) Mono<Long> count(); }
2. Service层组合结果
在Service里通过Reactive的zip操作符合并两个异步查询结果,再构造Page:
@Service public class PersonService { private final PersonRepository personRepository; // 构造注入Repository public PersonService(PersonRepository personRepository) { this.personRepository = personRepository; } public Mono<Page<Person>> getPersonPage(Pageable pageable) { // 把Flux转成包含列表的Mono Mono<List<Person>> contentMono = personRepository.findAllBy(pageable).collectList(); // 获取总记录数的Mono Mono<Long> totalCountMono = personRepository.count(); // 合并两个Mono,当两者都完成时构造PageImpl return Mono.zip(contentMono, totalCountMono) .map(resultTuple -> new PageImpl<>( resultTuple.getT1(), // 分页后的内容列表 pageable, // 分页参数 resultTuple.getT2() // 总记录数 )); } }
关键注意事项
- 条件一致性:如果你的列表查询带有过滤条件(比如按姓名关键词查询),那总记录数的查询必须使用完全相同的条件!比如列表查询是
findByNameContaining(String keyword, Pageable pageable),那计数方法就要是countByNameContaining(String keyword),否则分页的总页数会出错。 - 类型匹配:
PageImpl的构造器中总记录数是long类型,所以尽量让Repository的count方法返回Mono<Long>,避免不必要的类型转换。 - 异步模型适配:这种方式完全符合Reactive的异步非阻塞模型,两个查询是并行执行的,不会阻塞线程,性能上没问题。
内容的提问来源于stack exchange,提问作者krishnakumarp
相关产品推荐
相关产品推荐

