package com.example.web.pagination;
public class Page {
// 配置參數 (可從配置檔讀取)
private int pageSize = 10; // 每頁筆數
private int displayPageCount = 10; // 頁碼導航顯示頁數
// 業務參數
private int totalRecord; // 總筆數
private int currentPageNum = 1; // 當前頁碼
// 衍生屬性
private int totalPage; // 總頁數
private int startRow; // 當前頁起始行 (0-based)
private int startPageNum; // 導航起始頁碼
private int endPageNum; // 導航結束頁碼
private int prevPageNum; // 上一頁
private int nextPageNum; // 下一頁
private int firstPageNum = 1; // 首頁
private int lastPageNum; // 尾頁
public Page() {}
public Page(int totalRecord) {
this.totalRecord = totalRecord;
calculate();
}
/** 核心計算邏輯 */
public void calculate() {
// 總頁數
totalPage = (totalRecord + pageSize - 1) / pageSize;
if (totalPage == 0) totalPage = 1;
// 當前頁碼邊界修正
currentPageNum = Math.max(1, Math.min(currentPageNum, totalPage));
// 衍生頁碼
lastPageNum = totalPage;
prevPageNum = Math.max(1, currentPageNum - 1);
nextPageNum = Math.min(totalPage, currentPageNum + 1);
// 起始行 (用於 SQL LIMIT/OFFSET)
startRow = (currentPageNum - 1) * pageSize;
// 導航頁碼範圍計算 (置中當前頁)
int half = displayPageCount / 2;
startPageNum = Math.max(1, currentPageNum - half);
endPageNum = Math.min(totalPage, startPageNum + displayPageCount - 1);
// 若尾部不足,向前補齊
if (endPageNum - startPageNum + 1 < displayPageCount) {
startPageNum = Math.max(1, endPageNum - displayPageCount + 1);
}
}
// Getter/Setter 省略...
}
@Namespace("/")
@Action(value = "userList", results = {
@Result(name = "success", location = "/user/list.jsp")
})
public class UserListAction extends ActionSupport {
@Autowired private UserService userService;
// 接收分頁參數 (Struts 2 自動注入)
private Page page = new Page();
public String execute() {
// 1. 查詢總筆數
int total = userService.countUsers();
page.setTotalRecord(total);
// 2. 計算分頁參數
page.calculate();
// 3. 查詢當前頁資料
List<User> users = userService.findByPage(page.getStartRow(), page.getPageSize());
// 4. 放入 request 供 JSP 使用
ServletActionContext.getRequest().setAttribute("page", page);
ServletActionContext.getRequest().setAttribute("users", users);
return SUCCESS;
}
// 跳轉頁面專用 Action
@Action(value = "toPage", results = @Result(name = "success", type = "redirectAction",
params = {"actionName", "userList", "page.currentPageNum", "${page.currentPageNum}", "page.totalRecord", "${page.totalRecord}"}))
public String toPage() {
return SUCCESS;
}
// Getter/Setter
public Page getPage() { return page; }
public void setPage(Page page) { this.page = page; }
}
<%@ taglib prefix="s" uri="/struts-tags" %>
<div class="pagination">
<!-- 總筆數/總頁數 -->
<div class="page-info">
共 <s:property value="#request.page.totalRecord" /> 筆 /
<s:property value="#request.page.totalPage" /> 頁
</div>
<!-- 首頁 -->
<s:url id="firstUrl" action="toPage">
<s:param name="page.currentPageNum"><s:property value="#request.page.firstPageNum" /></s:param>
<s:param name="page.totalRecord"><s:property value="#request.page.totalRecord" /></s:param>
</s:url>
<s:a href="%{firstUrl}">首頁</s:a>
<!-- 上一頁 -->
<s:url id="prevUrl" action="toPage">
<s:param name="page.currentPageNum"><s:property value="#request.page.prevPageNum" /></s:param>
<s:param name="page.totalRecord"><s:property value="#request.page.totalRecord" /></s:param>
</s:url>
<s:a href="%{prevUrl}">上一頁</s:a>
<!-- 頁碼導航 -->
<s:bean name="org.apache.struts2.util.Counter" var="counter">
<s:param name="first">%{#request.page.startPageNum}</s:param>
<s:param name="last">%{#request.page.endPageNum}</s:param>
<s:iterator var="pageNum" value="%{#counter}">
<s:if test="%{#pageNum == #request.page.currentPageNum}">
<span class="current-page"><s:property /></span>
</s:if>
<s:else>
<s:url id="pageUrl" action="toPage">
<s:param name="page.currentPageNum"><s:property /></s:param>
<s:param name="page.totalRecord"><s:property value="#request.page.totalRecord" /></s:param>
</s:url>
<s:a href="%{pageUrl}"><s:property /></s:a>
</s:else>
</s:iterator>
</s:bean>
<!-- 下一頁 -->
<s:url id="nextUrl" action="toPage">
<s:param name="page.currentPageNum"><s:property value="#request.page.nextPageNum" /></s:param>
<s:param name="page.totalRecord"><s:property value="#request.page.totalRecord" /></s:param>
</s:url>
<s:a href="%{nextUrl}">下一頁</s:a>
<!-- 尾頁 -->
<s:url id="lastUrl" action="toPage">
<s:param name="page.currentPageNum"><s:property value="#request.page.lastPageNum" /></s:param>
<s:param name="page.totalRecord"><s:property value="#request.page.totalRecord" /></s:param>
</s:url>
<s:a href="%{lastUrl}">尾頁</s:a>
</div>
// Mapper
List<User> selectByPage(@Param("offset") int offset, @Param("limit") int limit);
int selectCount();
// XML
<select id="selectByPage" resultType="User">
SELECT * FROM t_user ORDER BY create_time DESC
LIMIT #{offset}, #{limit}
</select>
<select id="selectCount" resultType="int">
SELECT COUNT(1) FROM t_user
</select>
// Service
public List<User> findByPage(int offset, int limit) {
return userMapper.selectByPage(offset, limit);
}
public int countUsers() {
return userMapper.selectCount();
}
totalRecord、pageSize、displayPageCount → 計算出所有衍生屬性<s:url> + <s:param> 自動編碼參數,支援重定向<s:iterator> 渲染頁碼PageResult<T> 封裝類,含 List<T> data, long total, int pageNum, int pageSizeLIMITStruts 2 分頁核心在於 Page 模型封裝計算邏輯,Action 只需設定 totalRecord 呼叫 calculate(),JSP 透過標籤庫渲染導航。雖然 Struts 2 已非主流,但此分頁模型設計思想 (輸入最小化、衍生屬性全自動、前後端分離參數傳遞) 具備普適參考價值。