若依(RuoYi)框架数据分页功能的前后端源码深度解析——以“学生信息”模块为例
·
一、 实例简介:为什么要进行数据分页?
在企业级应用开发中,当数据库中存储了海量数据(例如 10000 个用户信息)时,如果我们一次性将所有数据从后端读取并展示到前端,会面临巨大的性能灾难。如果不分页,系统会导致前端浏览器内存溢出、网络带宽被大量占用、后端数据库全表扫描性能极差。
1.在课堂上,我们分析了系统自带的“操作日志”页面的分页过程:
进入方式:系统管理 -> 日志管理 -> 操作日志

(图1:系统自带的操作日志页面展示)
2.为了加深对CSMD架构底层数据流转的理解,本文将不使用系统自带的日志模块,而是以我自定义开发的“系统工具 -> 学生信息”模块为例,深度剖析若依(RuoYi-Vue)框架是如何优雅地实现前后端数据分页的。

(图2:我自定义的“学生信息”页面,红框标记了左侧菜单与右下角的分页组件)
二、 源码分析:前端代码与网络请求机制
1. 前端页面组件 (index.vue)
①首先,我们找到学生信息页面的前端源码文件路径:

②打开该文件,可以看到页面底部使用了 <pagination> 组件。该组件绑定的 :total="total" 初始值为 0,且通过 @pagination="getList" 绑定了翻页事件。当用户在界面上点击“第几页”或切换“每页条数”时,会立即触发该函数:

(图3:前端 <pagination> 分页组件代码及属性绑定)
2. 函数调用链:参数获取与接口请求
③在页面上方,用户可以通过日期选择框和搜索按钮来触发查询:

(图4:前端搜索条件 - 生日选择框)

(图5:前端搜索条件 - 搜索触发按钮)
④数据的获取遵循调用链:getList -> listStudent -> request[axios]。 首先,在 api/system/student.js 中,通过引入 axios 封装的网络通信工具,定义了向后端发起 /system/student/list 请求的方法:

(图6:student.js 中定义的访问后端 URL 与 GET 请求方式)
⑤回到 index.vue 的 methods 中,当后端成功响应后,getList() 函数会将返回的 response.total 赋值给 this.total:

(图7:getList 方法的完整结构)

(图8:重点逻辑放大——只有当 total 被赋值后,页面才会通过 pagination 组件显示数据)
3. F12 开发者工具抓包验证
⑥按下 F12 打开开发者工具,切换到 Network(网络)面板,过滤 Fetch/XHR 交互请求。 首先查看 Headers(标头),可以看到前端发往后端的 URL 中携带了两个核心参数:pageNum=1(第几页)和 pageSize=10(每页条数):

(图9:开发者工具查看前端访问后端的请求参数信息)
⑦切换到 Preview(预览) 面板,可以看到后端返回了包含 total: 5 和 rows 数组的 JSON 数据。返回的数据条数精准匹配了请求的分页限制:
(图10:开发者工具查看前端接收到后端的回应信息)
三、 源码分析:后端代码与分页核心封装
前端发送了分页参数,后端是如何接收并处理的呢?
1. 控制器入口 (MyStudentController.java)
进入 MyStudentController.java,找到响应前端 HTTP 请求的 @GetMapping("/list") 方法。实现分页只需要两行核心代码:startPage();(开启分页)和 return getDataTable(list);(包装返回结果)。

(图11:后端学生信息 Controller 的分页实现逻辑)
2. 底层包装逻辑透视
这两个方法来自于若依的基类 BaseController.java:

(图12:BaseController.java 中的 startPage() 方法)
startPage() 实际上调用了工具类 PageUtils.java。在这里,系统动态获取了前端传来的 pageNum 和 pageSize 参数,并最终调用 MyBatis 插件的 PageHelper.startPage() 真正开启分页拦截:

(图13:PageUtils.java 中真正执行分页拦截的底层代码)
查询出数据后,BaseController 的 getDataTable() 方法会将数据放入 TableDataInfo 中,并通过 new PageInfo(list).getTotal() 自动计算表数据的总行数,最终返回给前端:

(图14:BaseController.java 中的 getDataTable() 数据包装逻辑)
四、 分页实现原理分析:MyBatis 与 SQL 日志剖析
我们在 Mapper 的 XML 文件中写的是普通的 SELECT 语句,并没有手动写 pageNum 和 pageSize,那它是如何截取数据的呢?这归功于 MyBatis 的 PageHelper 插件拦截机制。
观察 IDEA 控制台打印出的 Log 日志,我们会发现原本的一句 SQL,被 MyBatis 拦截并动态改写成了两句 SQL:

(图15:MyBatis 拦截后的控制台输出,包含 count 统计与 LIMIT 限制)
原理剖析:
-
查总数:第一句生成
SELECT count(0) FROM my_student,用于查询表的总行数(对应日志中的 Total: 5)。 -
查分页数据:第二句在原查询语句末尾自动拼接了
LIMIT ?,对查询数据做了物理行数限制。
五、总结:
通过对若依 CSMD 架构的前后链路分析,我们看到了一次完整的分页流转:前端传参 -> 控制器解析开启 PageHelper -> MyBatis 拦截改写 SQL -> 数据库执行 LIMIT 物理分页 -> 后端统一包装总条数 -> 前端渲染页码。这种设计极大地提升了系统的查询性能和稳定性。
更多推荐




所有评论(0)