分頁是 Web 應用最基礎的數據展示需求。本文提供一個基於「表現層-控制層-DAO層-數據庫」經典架構的完整分頁示例,涵蓋總頁數計算、分頁查詢、Servlet 控制器、JSP+EL/JSTL 渲染,代碼可直接運行並擴展。
CREATE TABLE books (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
number VARCHAR(50)
);
-- 插入測試數據 20+ 條
public class BookDao {
// 連接工具類略 (JDBCUtils: getConnection/close)
/** 計算總頁數 */
public int getTotalPages(int pageSize) {
String sql = "SELECT COUNT(*) FROM books";
try (Connection conn = JDBCUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
int total = rs.getInt(1);
return (total + pageSize - 1) / pageSize; // 向上取整
}
} catch (SQLException e) { throw new RuntimeException(e); }
return 0;
}
/** 分頁查詢 */
public List<Book> findByPage(int pageNo, int pageSize) {
String sql = "SELECT id, name, number FROM books ORDER BY id LIMIT ?, ?";
List<Book> list = new ArrayList<>();
try (Connection conn = JDBCUtils.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, (pageNo - 1) * pageSize); // offset
ps.setInt(2, pageSize);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
Book b = new Book();
b.setId(rs.getInt("id"));
b.setName(rs.getString("name"));
b.setNumber(rs.getString("number"));
list.add(b);
}
}
} catch (SQLException e) { throw new RuntimeException(e); }
return list;
}
}
public class Book {
private int id; private String name; private String number;
// Getter/Setter
}
@WebServlet("/listBooks")
public class ListBooksServlet extends HttpServlet {
private BookDao dao = new BookDao();
private static final int PAGE_SIZE = 5;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int pageNo = 1;
String param = req.getParameter("pageNo");
if (param != null) {
try { pageNo = Integer.parseInt(param); }
catch (NumberFormatException ignored) {}
}
// 邊界校驗
int totalPages = dao.getTotalPages(PAGE_SIZE);
if (pageNo < 1) pageNo = 1;
if (pageNo > totalPages) pageNo = totalPages;
List<Book> books = dao.findByPage(pageNo, PAGE_SIZE);
req.setAttribute("books", books);
req.setAttribute("pageNo", pageNo);
req.setAttribute("totalPages", totalPages);
req.getRequestDispatcher("/booklist.jsp").forward(req, resp);
}
}
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<html><head><title>圖書列表</title>
<style> table{border-collapse:collapse;width:60%;margin:20px auto;} th,td{border:1px solid #ccc;padding:8px;text-align:center;} .page{text-align:center;margin:20px;} .page a{margin:0 5px;padding:2px 8px;border:1px solid #ccc;text-decoration:none;} .page span{margin:0 5px;} </style>
</head><body>
<h2 style="text-align:center">圖書信息</h2>
<table>
<tr><th>書號</th><th>書名</th><th>庫存量</th></tr>
<c:forEach items="${books}" var="book">
<tr>
<td>${book.id}</td>
<td>${book.name}</td>
<td>${book.number}</td>
</tr>
</c:forEach>
</table>
<div class="page">
<c:if test="${pageNo > 1}">
<a href="listBooks?pageNo=1">首頁</a>
<a href="listBooks?pageNo=${pageNo-1}">上一頁</a>
</c:if>
<span>第 ${pageNo} 頁 / 共 ${totalPages} 頁</span>
<c:if test="${pageNo < totalPages}">
<a href="listBooks?pageNo=${pageNo+1}">下一頁</a>
<a href="listBooks?pageNo=${totalPages}">末頁</a>
</c:if>
<form action="listBooks" method="get" style="display:inline;margin-left:10px;">
跳轉 <input type="number" name="pageNo" value="${pageNo}" min="1" max="${totalPages}" size="3">
<input type="submit" value="Go">
</form>
</div>
</body></html>
| 層級 | 核心邏輯 |
|---|---|
| 數據庫 | MySQL LIMIT offset, pageSize;Oracle 用 ROWNUM 子查詢/分析函數;SQL Server 用 OFFSET FETCH |
| DAO | 總記錄數 → 總頁數;PreparedStatement 防注入;try-with-resources 保證資源關閉 |
| Servlet | 參數解析+邊界校驗;設置屬性轉發 JSP;無業務邏輯 |
| JSP | <c:forEach> 渲染列表;<c:if> 控制分頁鏈接顯隱;EL 表達式 ${...} 取值 |
Page<T> 對象 (records, total, pageNo, pageSize, totalPages),Service 返回 Page,Controller 僅傳遞。PageHelper 一行代碼實現物理分頁:PageHelper.startPage(pageNo, pageSize); List<Book> list = mapper.selectAll(); PageInfo<Book> page = new PageInfo<>(list);本示例展示了 Java Web 分頁的「最小完整閉環」。理解 總數統計 → 物理分頁 SQL → 參數校驗 → 屬性傳遞 → EL/JSTL 渲染 流程,即可靈活應對各類分頁需求。現代項目建議引入 PageHelper 或前後端分離架構,將分頁邏輯下沉到框架/組件層。