有什么方法可以在 spring webflux 和 spring data reactive 中实现分页
Is there any way to implement pagination in spring webflux and spring data reactive
我正在尝试理解 spring 5 的反应部分。我创建了简单的休息端点,用于使用 spring web-flux
和 spring 数据反应来查找所有实体(mongo) 但不知道如何实现分页。
这是我在 Kotlin 中的简单示例:
@GetMapping("/posts/")
fun getAllPosts() = postRepository.findAll()
这是否意味着反应式端点不需要分页?是否有某种方法可以使用此堆栈从服务器端实现分页?
Spring 数据中的响应式支持不提供 Page
return 类型的方法。尽管如此,Pageable
参数在将 limit
和 offset
传递给驱动程序的方法签名中得到支持,因此传递给存储本身,returning a Flux<T>
发出请求的范围。
Flux<Person> findByFirstname(String firstname, Pageable pageable);
有关更多信息,请查看当前 Reference Documentation for 2.0.RC2 and the Spring Data Examples。
Flux 提供 skip
和 take
方法来获得分页支持,你也可以使用 filter
和sort
过滤和排序结果。 下面的过滤和排序不是一个很好的例子,但是使用 skip
和 Pageable
作为第二个参数是没什么不同。
以下代码对我有用。
@GetMapping("")
public Flux<Post> all(
//@RequestParam(value = "q", required = false) String q,
@RequestParam(value = "page", defaultValue = "0") long page,
@RequestParam(value = "size", defaultValue = "10") long size) {
return this.postRepository.findAll()
//.filter(p -> Optional.ofNullable(q).map(key -> p.getTitle().contains(key) || p.getContent().contains(key)).orElse(true))//(replace this with query parameters)
.sort(comparing(Post::getCreatedDate).reversed())
.skip(page * size).take(size);
}
更新:底层驱动程序应该负责以reactivestreams方式处理结果。
正如您在 Christoph 的回答中看到的那样,如果使用 findByXXX
方法,Spring Data Mongo Reactive 提供了一个变体来接受 pageable
参数,但是findAll
(reactive version) 不包含这样的变体,如果你真的需要,你必须在后面的操作中做skip
]分页 功能。当切换到 Flux
而不是 List 时,将 Flux 中的数据想象成河流中的活水或管道中的油,或者 twitter.com.
中的推文
我尝试比较使用 Pageale
的查询,而不是在以下情况下。
this.postRepository.findByTitleContains("title")
.skip(0)
.limitRequest(10)
.sort((o1, o2) -> o1.getTitle().compareTo(o2.getTitle()))
this.postRepository.findByTitleContains("title", PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "title")))
为 logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
启用日志记录时发现它们为查询打印相同的日志。
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
//other logging...
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
请记住,所有这些操作都应委托给底层 R2dbc 驱动程序,该驱动程序实现了反应流规范并在数据库端执行,而不是在应用程序端的内存中执行.
我上面提供的早期示例代码可能不是 filter
和 sort
操作的好示例(MongoDB 本身提供了很好的 regularexpression
操作)。但是反应式变体中的分页与反应式流规范中的概念不太匹配。在采用 Spring 反应式堆栈时,大多数时候,我们只是将工作转移到新的 API 集合中。在我看来,实时更新和弹性响应场景可以更好地匹配Reactive,例如。将它与 SSE、Websocket、RSocket、application/stream+json
(在新的 Spring 文档中缺失)协议等一起使用
效率不高,但在我寻找其他解决方案时对我有用
服务
public Page<Level> getPage(int page, int size, Sort.Direction direction, String properties) {
var pageRequest = PageRequest.of(page, size, direction, properties);
var count = levelRepository.count().block();
var levels = levelRepository.findAllLevelsPaged(pageRequest).collectList().block();
return new PageImpl<>(Objects.requireNonNull(levels), pageRequest, Objects.requireNonNull(count));
}
回购
@Repository
public interface LevelRepository extends ReactiveMongoRepository<Level, String> {
@Query("{ id: { $exists: true }}")
Flux<Level> findAllLevelsPaged(final Pageable page);
}
参考 example
我正在尝试理解 spring 5 的反应部分。我创建了简单的休息端点,用于使用 spring web-flux
和 spring 数据反应来查找所有实体(mongo) 但不知道如何实现分页。
这是我在 Kotlin 中的简单示例:
@GetMapping("/posts/")
fun getAllPosts() = postRepository.findAll()
这是否意味着反应式端点不需要分页?是否有某种方法可以使用此堆栈从服务器端实现分页?
Spring 数据中的响应式支持不提供 Page
return 类型的方法。尽管如此,Pageable
参数在将 limit
和 offset
传递给驱动程序的方法签名中得到支持,因此传递给存储本身,returning a Flux<T>
发出请求的范围。
Flux<Person> findByFirstname(String firstname, Pageable pageable);
有关更多信息,请查看当前 Reference Documentation for 2.0.RC2 and the Spring Data Examples。
Flux 提供 skip
和 take
方法来获得分页支持,你也可以使用 下面的过滤和排序不是一个很好的例子,但是使用 filter
和sort
过滤和排序结果。skip
和 Pageable
作为第二个参数是没什么不同。
以下代码对我有用。
@GetMapping("")
public Flux<Post> all(
//@RequestParam(value = "q", required = false) String q,
@RequestParam(value = "page", defaultValue = "0") long page,
@RequestParam(value = "size", defaultValue = "10") long size) {
return this.postRepository.findAll()
//.filter(p -> Optional.ofNullable(q).map(key -> p.getTitle().contains(key) || p.getContent().contains(key)).orElse(true))//(replace this with query parameters)
.sort(comparing(Post::getCreatedDate).reversed())
.skip(page * size).take(size);
}
更新:底层驱动程序应该负责以reactivestreams方式处理结果。
正如您在 Christoph 的回答中看到的那样,如果使用 findByXXX
方法,Spring Data Mongo Reactive 提供了一个变体来接受 pageable
参数,但是findAll
(reactive version) 不包含这样的变体,如果你真的需要,你必须在后面的操作中做skip
]分页 功能。当切换到 Flux
而不是 List 时,将 Flux 中的数据想象成河流中的活水或管道中的油,或者 twitter.com.
我尝试比较使用 Pageale
的查询,而不是在以下情况下。
this.postRepository.findByTitleContains("title")
.skip(0)
.limitRequest(10)
.sort((o1, o2) -> o1.getTitle().compareTo(o2.getTitle()))
this.postRepository.findByTitleContains("title", PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "title")))
为 logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
启用日志记录时发现它们为查询打印相同的日志。
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
//other logging...
find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post
请记住,所有这些操作都应委托给底层 R2dbc 驱动程序,该驱动程序实现了反应流规范并在数据库端执行,而不是在应用程序端的内存中执行.
我上面提供的早期示例代码可能不是 filter
和 sort
操作的好示例(MongoDB 本身提供了很好的 regularexpression
操作)。但是反应式变体中的分页与反应式流规范中的概念不太匹配。在采用 Spring 反应式堆栈时,大多数时候,我们只是将工作转移到新的 API 集合中。在我看来,实时更新和弹性响应场景可以更好地匹配Reactive,例如。将它与 SSE、Websocket、RSocket、application/stream+json
(在新的 Spring 文档中缺失)协议等一起使用
效率不高,但在我寻找其他解决方案时对我有用
服务
public Page<Level> getPage(int page, int size, Sort.Direction direction, String properties) {
var pageRequest = PageRequest.of(page, size, direction, properties);
var count = levelRepository.count().block();
var levels = levelRepository.findAllLevelsPaged(pageRequest).collectList().block();
return new PageImpl<>(Objects.requireNonNull(levels), pageRequest, Objects.requireNonNull(count));
}
回购
@Repository
public interface LevelRepository extends ReactiveMongoRepository<Level, String> {
@Query("{ id: { $exists: true }}")
Flux<Level> findAllLevelsPaged(final Pageable page);
}
参考 example