分页实现方案
在现代Web应用中,用户列表展示与分页是一个常见的功能需求。前端与后端通过API协同工作,使用PageHelper等工具实现高效分页。
例如:
后端实现 (使用PageHelper)
public PageResult DishPage(DishPageQueryDTO dishPageQueryDTO) {
PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
Page<DishVO> page=dishMapper.DishQueryPage(dishPageQueryDTO);
PageResult pageResult=new PageResult();
pageResult.setTotal(page.getTotal());
pageResult.setRecords(page.getResult());
return pageResult;
}
PageHelper.startPage() - 分页的起点
PageHelper.startPage()
方法是整个分页过程的起点,它通过ThreadLocal机制在当前线程中设置分页参数:
PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
-
参数1:当前页码(从1开始计数)
-
参数2:每页显示的记录数
底层原理:
-
PageHelper会将这两个参数存入
Page
对象 -
通过
PageInterceptor
拦截器,这个对象会被后续的SQL查询拦截 -
拦截器会根据这些参数改写原始SQL,添加LIMIT/OFFSET等分页子句
执行Mapper查询
Page<DishVO> page = dishMapper.DishQueryPage(dishPageQueryDTO);
这行代码看似普通的Mapper调用,实则暗藏玄机:
-
自动拦截:PageHelper的拦截器会在SQL执行前介入
-
SQL改写:根据startPage设置的参数,拦截器会将原始SQL改写为分页查询
-
MySQL:添加
LIMIT offset, pageSize
-
Oracle:使用ROWNUM实现分页
-
-
执行查询:改写后的SQL会被执行,获取当前页的数据
-
总数查询:拦截器还会自动执行COUNT查询获取总记录数
Page对象解析
查询返回的Page<DishVO>
对象包含了丰富的分页信息:
-
getTotal():总记录数(不是总页数)
-
getResult():当前页的数据列表
-
getPages():总页数(通过total/pageSize计算)
-
getPageNum():当前页码
-
getPageSize():每页大小
构建自定义PageResult
PageResult pageResult = new PageResult(); pageResult.setTotal(page.getTotal()); pageResult.setRecords(page.getResult()); return pageResult;
这里将Page对象转换为自定义的PageResult
,通常是为了:
-
简化响应结构:只返回前端需要的字段
-
统一格式:保持API响应的一致性
-
数据脱敏:有机会对敏感字段进行处理
完整工作流程
客户端请求带分页参数的API(如
/dishes?page=2&pageSize=10
)控制器接收参数并构造DTO对象
Service层调用
PageHelper.startPage()
启动分页执行Mapper查询,PageHelper自动拦截并改写SQL
获取分页结果并包装为自定义响应对象
返回给前端统一格式的分页数据