分頁是Web列表頁標配。將「總記錄數→總頁數、當前頁→數據起止行號」的計算邏輯封裝為復用工具類,消除Controller/JSP中的重復算術代碼。本文提供PageUpDown類完整實現與使用指南。
whw.function.PageUpDown)package whw.function;
public class PageUpDown {
private int currentPage; // 當前頁
private int totalPages; // 總頁數
private int totalRows; // 總行數
private int pageSize = 5; // 每頁行數,默認5
private int startRow; // 當前頁起始行號(1-based)
private int endRow; // 當前頁結束行號
/** 設置總行數,自動計算總頁數 */
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
if (totalRows > 0 && pageSize > 0) {
int pages = totalRows / pageSize;
if (totalRows % pageSize > 0) pages++;
totalPages = pages;
}
}
/** 設置每頁行數 */
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalPages() { return totalPages; }
/** 首頁 */
public void firstPage() {
currentPage = 1;
calcRowRange();
}
/** 尾頁 */
public void lastPage() {
currentPage = totalPages;
calcRowRange();
}
/** 上一頁 */
public void previousPage(int currentPage) {
this.currentPage = (currentPage <= 1) ? 1 : currentPage - 1;
calcRowRange();
}
/** 下一頁 */
public void nextPage(int currentPage) {
this.currentPage = (currentPage >= totalPages) ? totalPages : currentPage + 1;
calcRowRange();
}
/** 跳轉指定頁 */
public void gotoPage(int page) {
if (page < 1) page = 1;
if (page > totalPages) page = totalPages;
this.currentPage = page;
calcRowRange();
}
/** 核心:根據當前頁計算數據範圍 */
private void calcRowRange() {
startRow = (currentPage - 1) * pageSize + 1;
endRow = currentPage * pageSize;
if (endRow > totalRows) endRow = totalRows;
}
public int getStartRow() { return startRow; }
public int getEndRow() { return endRow; }
public int getCurrentPage() { return currentPage; }
}
int total = userDao.countAll();PageUpDown pager = new PageUpDown();pager.setTotalRows(total);pager.setPageSize(10); // 可選,默認5request.setAttribute("totalPages", pager.getTotalPages());int pageNo = Integer.parseInt(request.getParameter("pageNo"));pager.gotoPage(pageNo);List<User> list = userDao.findByPage(pager.getStartRow(), pager.getEndRow());| 數據庫 | 分頁寫法 | 參數映射 |
|---|---|---|
| MySQL | LIMIT ?, ? | startRow-1, pageSize |
| Oracle 12c+ | OFFSET ? ROWS FETCH NEXT ? ROWS ONLY | startRow-1, pageSize |
| SQL Server 2012+ | OFFSET ? ROWS FETCH NEXT ? ROWS ONLY | startRow-1, pageSize |
| PostgreSQL | LIMIT ? OFFSET ? | pageSize, startRow-1 |
| 通用(游標) | JDBC 2.0 ResultSet.TYPE_SCROLL_INSENSITIVE | rs.absolute(startRow) 循環pageSize次 |
PageResult<T>封裝List<T> data, long total, int pageNo, int pageSize,Controller直接返回JSON。total, pageSize, current屬性,發射change事件。LIMIT 1000000, 10極慢 → 改用WHERE id > lastId ORDER BY id LIMIT 10(游標分頁/Keyset Pagination)。count(*)結果,定時/事件驅動刷新。Pageable pageable = PageRequest.of(pageNo-1, pageSize); Page<User> page = repo.findAll(pageable);IPage<User> page = new Page<>(pageNo, pageSize); mapper.selectPage(page, null);query.setFirstResult(startRow-1).setMaxResults(pageSize);「一個工具類統一分頁算術」是早期JSP/Servlet時代的智慧結晶。現代框架雖內置更強大的分頁抽象,但startRow/endRow計算邏輯、邊界防呆、總頁數推導的核心思想始終相通。