在 Web 應用開發中,分頁處理是核心需求。主要有兩種架構模式:
本文採用方案二,結合 Hibernate 原生 setFirstResult()/setMaxResults() 實現高效分頁。
Query q = session.createQuery("from Cat as c");
q.setFirstResult(10000); // 跳過前 10000 條
q.setMaxResults(100); // 取 100 條
List list = q.list();
封裝總行數、頁大小、當前頁、總頁數、起始行等屬性,提供首頁、上頁、下頁、尾頁、跳轉等導航邏輯:
package com.jpcf.db.helper;
public class Pager {
private int totalRows, pageSize = 10, currentPage, totalPages, startRow;
public Pager(int totalRows) {
this.totalRows = totalRows;
this.totalPages = (totalRows + pageSize - 1) / pageSize;
this.currentPage = 1;
this.startRow = 0;
}
// 導航方法
public void first() { currentPage = 1; startRow = 0; }
public void previous() { if (currentPage > 1) { currentPage--; startRow = (currentPage - 1) * pageSize; } }
public void next() { if (currentPage < totalPages) { currentPage++; startRow = (currentPage - 1) * pageSize; } }
public void last() { currentPage = totalPages; startRow = (currentPage - 1) * pageSize; }
public void refresh(int page) { currentPage = Math.min(page, totalPages); startRow = (currentPage - 1) * pageSize; }
// Getter/Setter 省略...
}
從 HTTP 請求參數中提取分頁狀態,自動計算並返回填充好的 Pager 實例:
package com.jpcf.db.helper;
import javax.servlet.http.HttpServletRequest;
public class PagerHelper {
public static Pager getPager(HttpServletRequest request, int totalRows) {
Pager pager = new Pager(totalRows);
String currentPage = request.getParameter("currentPage");
if (currentPage != null) pager.refresh(Integer.parseInt(currentPage));
String method = request.getParameter("pageMethod");
if (method != null) {
switch (method) {
case "first": pager.first(); break;
case "previous": pager.previous(); break;
case "next": pager.next(); break;
case "last": pager.last(); break;
}
}
return pager;
}
}
package com.jpcf.db.dao;
import com.jpcf.db.helper.HibernateUtil;
import net.sf.hibernate.*;
import java.util.*;
public class VehiclePropertyDAO {
/** 分頁查詢 */
public Collection findWithPage(int pageSize, int startRow) throws HibernateException {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
Query q = session.createQuery("from VehicleProperty vp");
q.setFirstResult(startRow);
q.setMaxResults(pageSize);
List list = q.list();
tx.commit();
return list;
} catch (HibernateException e) {
if (tx != null) tx.rollback();
throw e;
} finally {
HibernateUtil.closeSession();
}
}
/** 統計總行數 */
public int getRows(String hql) throws HibernateException {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
try {
Integer count = (Integer) session.iterate(hql).next();
tx.commit();
return count.intValue();
} catch (HibernateException e) {
if (tx != null) tx.rollback();
throw e;
} finally {
HibernateUtil.closeSession();
}
}
}
public ActionForward queryWithPage(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
VehiclePropertyDAO dao = new VehiclePropertyDAO();
int totalRows;
try {
totalRows = dao.getRows("select count(*) from VehicleProperty");
} catch (Exception e) {
servlet.log(e.toString());
return mapping.findForward(Constants.FAILURE);
}
Pager pager = PagerHelper.getPager(request, totalRows);
Collection list;
try {
list = dao.findWithPage(pager.getPageSize(), pager.getStartRow());
} catch (Exception e) {
servlet.log(e.toString());
return mapping.findForward(Constants.FAILURE);
}
request.setAttribute("CLINFOS", list);
request.setAttribute("PAGER", pager);
return mapping.findForward(Constants.SUCCESS);
}
使用 Struts 標簽庫生成分頁鏈接,傳遞 pageMethod 與 currentPage 參數:
<html:link action="/bussiness/clInfo/queryWithPage.do" paramId="currentPage" paramName="PAGER" paramProperty="currentPage">
<html:param name="pageMethod" value="first"/>首頁
</html:link>
<html:link ...><html:param name="pageMethod" value="previous"/>上一頁</html:link>
<html:link ...><html:param name="pageMethod" value="next"/>下一頁</html:link>
<html:link ...><html:param name="pageMethod" value="last"/>尾頁</html:link>
count(*)。ScrollableResults 游標模式處理超大結果集。