一、后端Java分页实现
1. 使用MyBatis + XML(带分页插件)
依赖包:MyBatis + PageHelper
<!-- pom.xml --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.6</version> </dependency>
代码实现:
// Controller @GetMapping("/users") public PageInfo<User> getUsers(@RequestParam int pageNum, @RequestParam int pageSize) { return userService.getUsers(pageNum, pageSize); } // Service public PageInfo<User> getUsers(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.selectAll(); return new PageInfo<>(users); } // Mapper XML(无需手写分页SQL,插件自动处理) <select id="selectAll" resultType="User"> SELECT * FROM users </select>
2. 纯JDBC手写分页(无框架)
核心逻辑:
public class PaginationService { public PageResult<User> getUsers(int pageNum, int pageSize) throws SQLException { int offset = (pageNum - 1) * pageSize; String sql = "SELECT * FROM users LIMIT ? OFFSET ?"; String countSql = "SELECT COUNT(*) FROM users"; try (Connection conn = DriverManager.getConnection(DB_URL); PreparedStatement ps = conn.prepareStatement(sql); PreparedStatement countPs = conn.prepareStatement(countSql)) { // 查询数据 ps.setInt(1, pageSize); ps.setInt(2, offset); ResultSet rs = ps.executeQuery(); List<User> users = new ArrayList<>(); while (rs.next()) { // 解析User对象... } // 查询总数 ResultSet countRs = countPs.executeQuery(); int total = countRs.next() ? countRs.getInt(1) : 0; return new PageResult<>(users, total); } } }
二、前端Vue分页实现
1. 使用Element UI分页组件
安装依赖:
npm install element-ui
组件代码:
<template> <div> <el-table :data="tableData"> <!-- 表格列定义 --> </el-table> <el-pagination @current-change="handlePageChange" @size-change="handleSizeChange" :current-page="currentPage" :page-sizes="[10, 20, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next" :total="total"> </el-pagination> </div> </template> <script> export default { data() { return { tableData: [], currentPage: 1, pageSize: 10, total: 0 }; }, methods: { async fetchData() { const res = await axios.get('/api/users', { params: { pageNum: this.currentPage, pageSize: this.pageSize } }); this.tableData = res.data.list; this.total = res.data.total; }, handlePageChange(page) { this.currentPage = page; this.fetchData(); }, handleSizeChange(size) { this.pageSize = size; this.fetchData(); } }, mounted() { this.fetchData(); } }; </script>
2. 手动实现分页控件
自定义分页组件:
<template> <div class="pagination"> <button @click="prevPage" :disabled="currentPage === 1">上一页</button> <span v-for="page in pages" :key="page" @click="goToPage(page)" :class="{ active: page === currentPage }"> {{ page }} </span> <button @click="nextPage" :disabled="currentPage === totalPages">下一页</button> </div> </template> <script> export default { props: ['currentPage', 'pageSize', 'total'], computed: { totalPages() { return Math.ceil(this.total / this.pageSize); }, pages() { const range = []; for (let i = 1; i <= this.totalPages; i++) { range.push(i); } return range; } }, methods: { goToPage(page) { this.$emit('page-change', page); }, prevPage() { if (this.currentPage > 1) this.goToPage(this.currentPage - 1); }, nextPage() { if (this.currentPage < this.totalPages) this.goToPage(this.currentPage + 1); } } }; </script>
三、数据库分页SQL示例
MySQL:
SELECT * FROM table LIMIT #{pageSize} OFFSET #{offset};
Oracle:
SELECT * FROM ( SELECT t.*, ROWNUM rn FROM ( SELECT * FROM table ORDER BY id ) t WHERE ROWNUM <= #{end} ) WHERE rn >= #{start}
四、完整流程说明
前后端交互协议:
请求参数:
pageNum
(当前页)、pageSize
(每页条数)响应格式:
{ list: [], total: 100 }
关键公式:
offset = (pageNum - 1) * pageSize; totalPages = ceil(total / pageSize);
五、总结
使用组件/包:快速开发,适合标准场景(推荐PageHelper + Element UI)。
手动实现:灵活定制,适合特殊需求或学习原理。
性能注意:大数据量时建议使用索引优化分页查询(如MySQL覆盖索引)。