在spring boot rest接口中返回分页数据,最标准的做法是结合使用spring data jpa的pageable参数与page或pageimpl对象。通过让控制器方法接收pageable实例,框架会自动解析前端传来的页码、大小等参数并执行查询,最终返回包含当前页数据列表及总页数、总记录数等元数据的page对象,直接序列化为json即可。

如何配置Controller以接收分页请求参数
要实现自动分页,只需在@RestController的方法签名中添加Pageable类型的参数,并配合Sort处理排序。Spring MVC会自动将URL中的page(默认0)、size(默认20)和sort参数绑定到该对象中。开发者无需手动编写SQL的分页逻辑,底层JPA实现会根据Pageable生成对应的limit和offset语句。

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ArticleController {
private final ArticleService articleService;
public ArticleController(ArticleService articleService) {
this.articleService = articleService;
}
@GetMapping("/articles")
public Page<article> getArticles(Pageable pageable) {
// 调用Service层,传入Pageable
return articleService.findAll(pageable);
}
}</article>
上述代码中,getArticles方法直接返回Page。当请求/articles?page=0&size=5时,Spring会创建Pageable对象,传递给Service,Service再传递给Repository。Repository执行查询后返回Page对象,Spring HTTP Message Converter将其转换为JSON响应。
如何自定义分页响应的数据结构
虽然Page对象提供了丰富的元数据,但有时业务需要更简洁或特定的JSON结构,例如将内容包裹在统一的data字段中,或者重命名字段。此时可以使用PageImpl手动构建分页对象,或者使用DTO映射。推荐使用PageImpl包装查询结果,以便灵活控制返回的JSON格式,同时保持分页元数据的完整性。

import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.List;
public class CustomPageResponse {
private List<article> content;
private int page;
private int size;
private long totalElements;
private int totalPages;
// Getters and Setters
}
// In Service or Controller:
List<article> content = articleRepo.findByStatus("PUBLISHED");
long total = articleRepo.countByStatus("PUBLISHED");
Page<article> page = new PageImpl(content, pageable, total);</article></article></article>
通过new PageImpl(content, pageable, total),开发者可以精确控制分页数据。即使查询不是通过JPA的findAll(Pageable)进行的,也可以手动计算总数并封装。这样返回的JSON结构依然符合RESTful分页的标准约定,前端可以轻松解析出content数组和分页导航信息。
基于Page对象中totalElements的具体问题
在使用Page对象时,一个常见的问题是totalElements的计算开销。对于大数据量,每次分页都执行count查询可能影响性能。可以通过配置JPA的SimplePageRequest或使用Slice来避免不必要的总数统计。如果不需要总页数,只关心是否有下一页,应改用Slice接口,它只返回当前切片数据和是否有下一片的信息,而不执行COUNT查询。











