You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现Spring Scroll API滚动加载时,如何限制返回结果数量?

Spring Scroll API 实现滚动加载时限制返回结果数量

问题描述

我想要通过Spring的Scroll API实现前端滚动加载,每次请求加载新数据,但尝试了多种方式都无法限制返回的结果数量,始终返回全表数据:

  1. 使用PageRequest
// Service
fun getOrders(customerId: Long): List<OrderDto> {
    val customer = customerRepository.findById(customerId).getOrElse { return emptyList() }
    val orders: WindowIterator<Order> = WindowIterator.of<Order> { position ->
        orderRepsitory.findAllByCustomerOrderByCreated(
             customer, 
             position as KeysetScrollPosition?,
             PageRequest.of(0, 20)
        )
    }
        .startingAt(ScrollPosition.keyset())
    val ordersResult: MutableList<Orders> = ArrayList<Orders>()
    orders.forEachRemaining { ordersResult.add(it) }
    return ordersResult.map {
        OrderDto(...)
    }
}

// Order Respository
interface OrderRepository : JpaRepository<Order, Long> {
fun findAllByCustomerOrderByCreated(
    customer: Customer, 
    position: KeysetScrollPosition?,
    pageable: Pageable,
    ): Window<Order>
}
  1. 调整JPA查询为findFirst5
// Order Respository
interface OrderRepository : JpaRepository<Order, Long> {
fun findFirst5ByCustomerOrderByCreated(
    customer: Customer, 
    position: KeysetScrollPosition?,
    ): Window<Order>
}

// Service中的调用
orderRepsitory.findFirst5ByCustomerOrderByCreated(
    customer, 
    position as KeysetScrollPosition?
)
  1. 使用Limit参数
// Order Respository
interface OrderRepository : JpaRepository<Order, Long> {
fun findAllByCustomerOrderByCreated(
    customer: Customer, 
    limit: Limit,
    ): Window<Order>
}

// Service中的调用
orderRepsitory.findAllByCustomerOrderByCreated(
    customer, 
    position as KeysetScrollPosition?,
     Limit.of(20)
)

请问如何通过Spring Scroll API正确限制每次返回的结果数量?


解决方案

核心问题分析

你之前的代码始终返回全表数据,根源在于Service层使用了WindowIterator.forEachRemaining()——这个方法会迭代所有滚动窗口,把符合条件的全量数据全部加载出来,直接抵消了限制结果数量的配置。

正确实现步骤

  1. 规范Repository方法定义
    使用Spring Data的ScrollPosition和Limit构建查询,同时确保排序字段包含唯一标识(比如ID),避免滚动时出现数据重复或遗漏:
interface OrderRepository : JpaRepository<Order, Long> {
    // 排序字段需包含唯一键,保证滚动逻辑的一致性
    fun findAllByCustomerOrderByCreatedDescIdDesc(
        customer: Customer,
        scrollPosition: ScrollPosition,
        limit: Limit
    ): Window<Order>
}
  1. Service层单次请求仅获取一个窗口数据
    不要遍历所有窗口,而是根据前端传递的滚动位置(首次请求用ScrollPosition.keyset()),获取单次请求的批次数据,并返回下一次滚动需要的位置给前端:
fun getOrders(customerId: Long, scrollPosition: ScrollPosition = ScrollPosition.keyset()): Pair<List<OrderDto>, ScrollPosition> {
    val customer = customerRepository.findById(customerId).getOrElse { return emptyList() to scrollPosition }
    
    // 单次请求仅获取20条数据的窗口
    val window = orderRepository.findAllByCustomerOrderByCreatedDescIdDesc(
        customer,
        scrollPosition,
        Limit.of(20)
    )
    
    val dtos = window.content.map { OrderDto(...) }
    // 返回当前批次数据和下一次滚动的起始位置
    return dtos to window.scrollPosition
}
  1. 前端交互逻辑配合
  • 首次请求时,不传滚动位置(或传递初始的KeysetScrollPosition)
  • 每次请求成功后,保存返回的scrollPosition(可序列化后存在前端缓存)
  • 滚动到底部时,携带保存的scrollPosition发起下一次请求,获取下一批数据

关键注意事项

  • Window对象包含当前批次的content数据,以及scrollPosition(用于下一次滚动的起始标记)
  • 排序字段必须包含唯一键,否则当存在相同created时间的记录时,滚动会出现数据重复或遗漏
  • 仅在需要全量加载数据时使用WindowIterator的遍历方法,滚动加载场景下要避免全量遍历

内容的提问来源于stack exchange,提问作者four-eyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:22:06