Struts + Hibernate分页显示 v1.0
2007年8月5日更新:这篇写于2年前的拙文,没想到现在还有很多的访问量,感谢大家的支持,很多朋友来信询问HibernateDAO的代码,实际上HibernateDAO是Hibernate应用的一种很流行的模式,在网上很容易就查到,所以我就没有列到文章里,但为了方便大家,我提供一个链接供参考:
http://www.javaeye.com/article/122
这篇文章是hibernate 2.0的版本,对于现在3.0版本改动不多,只需改一下包名:org.hibernate
题外话:关于hibernate, spring, struts等等j2ee开发框架,个人建议如果有时间的话,大家可以研究一下jboss seam这个下一代JavaEE开发框架,非常的值得
另外我的blog已经全部迁至javaeye, http://jeffreyhsu.javaeye.com 这里不做更新
欢迎大家访问
这是我学习Struts半个月以来,在开发第一个留言簿的时候,参考了网上很多的方案,然后做的一套Web分页机制,使用Struts的MVC方式,利用Hibernate的分段查询的机制来实现,JSP页面干净不含Java代码,逻辑结构清晰,易于扩展。是一个比较好的完整的分页解决方案。
目前为第一个版本,以后会逐步完善,在这里希望能起到一个抛砖引玉的作用
大家有什么好的建议可以与我联系:
jeffreyxu@gmail.com
阅读门槛:
Java基础知识
Struts基础知识
对Hibernate有一定了解
一、 开发环境
SQLServer2000
二、 开发思路
分页的步骤:
按照Struts 的MVC处理方式,对于显示数据的请求要先提交至相应的Action(这里是DisplayAction)进行处理,查询数据库,根据数据总数初始化分页信息,然后从数据库取得第一页所要显示的数据(这里并没有全部一次查询所有数据,效率较高),然后转交至相应的显示页面显示。
三、 源码部分
1) Hibernate 部分:
HibernateUtil Hibernate实用类,负责Session的取得和关闭
/*
* @(#)HibernateUtil.java 2005-4-26
*
* Copyright (c) 2005, Jeffrey Hsu
*/
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure()
.buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException("Exception building SessionFactory: " +
ex.getMessage(), ex);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
//Open a new Session, if this Thread has none yet
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null) {
s.close();
}
}
}
Paras 查询参数
ParasList 查询参数集合
HQuery 封装了查询参数的查询信息类
HibernateDAO 根据传递进来的HQuery进行数据库的查询
有关以上三个类的具体细节,请参考我收藏的文章:Hibernate查询解决方案
2) Pager 包含了分页信息的类,包括页面总数,记录总数,当前第几页
/*
* @(#)Pager.java 2005-5-3
*
* Copyright (c) 2005, Jeffrey Hsu
*/
package com.jeffrey.messagelove;
/**
* Pager holds the page info.
*/
public class Pager {
private int totalRows = 0; // 记录总数
private int totalPages = 0; // 总页数
private int pageSize = 10; // 每页显示数据条数,默认为10条记录
private int currentPage = 1; // 当前页数
private boolean hasPrevious = false; // 是否有上一页
private boolean hasNext = false; // 是否有下一页
public Pager() {
}
/**
* Initialize Pager
* @param totalRows total record rows
* @param pageSize total record is hold by every page
*/
public void init(int totalRows, int pageSize) {
this.totalRows = totalRows;
this.pageSize = pageSize;
totalPages = ((totalRows + pageSize) - 1) / pageSize;
refresh(); // 刷新当前页面信息
}
/**
* @return Returns the currentPage.
*/
public int getCurrentPage() {
return currentPage;
}
/**
* @param currentPage current page
*/
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
refresh();
}
/**
* @return Returns the pageSize.
*/
public int getPageSize() {
return pageSize;
}
/**
* @param pageSize The pageSize to set.
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
refresh();
}
/**
* @return Returns the totalPages.
*/
public int getTotalPages() {
return totalPages;
}
/**
* @param totalPages The totalPages to set.
*/
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
refresh();
}
/**
* @return Returns the totalRows.
*/
public int getTotalRows() {
return totalRows;
}
/**
* @param totalRows The totalRows to set.
*/
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
refresh();
}
// 跳到第一页
public void first() {
currentPage = 1;
this.setHasPrevious(false);
refresh();
}
// 取得上一页(重新设定当前页面即可)
public void previous() {
currentPage--;
refresh();
}
// 取得下一页
public void next() {
System.out.println("next: totalPages: " + totalPages +
" currentPage : " + currentPage);
if (currentPage < totalPages) {
currentPage++;
}
refresh();
}
// 跳到最后一页
public void last() {
currentPage = totalPages;
this.setHasNext(false);
refresh();
}
public boolean isHasNext() {
return hasNext;
}
/**
* @param hasNext The hasNext to set.
*/
public void setHasNext(boolean hasNext) {
this.hasNext = hasNext;
}
public boolean isHasPrevious() {
return hasPrevious;
}
/**
* @param hasPrevious The hasPrevious to set.
*/
public void setHasPrevious(boolean hasPrevious) {
this.hasPrevious = hasPrevious;
}
// 刷新当前页面信息
public void refresh() {
if (totalPages <= 1) {
hasPrevious = false;
hasNext = false;
} else if (currentPage == 1) {
hasPrevious = false;
hasNext = true;
} else if (currentPage == totalPages) {
hasPrevious = true;
hasNext = false;
} else {
hasPrevious = true;
hasNext = true;
}
}
}
3) Action:
DisplayAllAction 显示数据页面控制器
package com.jeffrey.messagelove;
import com.jeffrey.messagelove.*;
import com.jeffrey.messagelove.Pager;
import com.jeffrey.messagelove.hibernate.*;
/*
* @(#)DisplayAction.java 2005-5-2
*
* Copyright (c) 2005, Jeffrey Xu
*/
import org.apache.struts.action.*;
import java.util.*;
import javax.servlet.http.*;
/**
* 显示页面控制器
*/
public class DisplayAllAction extends Action {
private HibernateDAO hibernateDAO = new HibernateDAO();
private Pager pager = new Pager();
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
HttpSession session = request.getSession();
List messageList = null;
HQuery hquery = new HQuery();
int totalRows = 0;
int startRow = 0;
try {
totalRows = hibernateDAO.getRows("select count(*) from Message");
// 初始化页面信息
pager.init(totalRows, Constants.RECORD_PER_PAGE);
} catch (Exception ex) {
ex.printStackTrace();
}
hquery.setQueryString("From Message order by m_sendDate desc");
String viewPage = (String) request.getParameter("viewPage");
String action = (String) request.getParameter("action");
// 跳转至相应页面
if (viewPage != null && !viewPage.equals("")) {
try {
pager.setCurrentPage(Integer.parseInt(viewPage));
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
if (action != null) {
// 根据传递进来的参数控制页面的前进后退
if (action.equalsIgnoreCase("previous")) {
pager.previous();
} else if (action.equalsIgnoreCase("next")) {
pager.next();
} else if (action.equalsIgnoreCase("first")) {
pager.first();
} else if (action.equalsIgnoreCase("last")) {
pager.last();
}
}
try {
hquery.setPageStartNo(pager.getCurrentPage());
messageList = hibernateDAO.find(hquery);
} catch (Exception ex) {
ex.printStackTrace();
}
request.setAttribute("list", messageList);
session.setAttribute("pager", pager);
return mapping.findForward("display");
}
}
4) JSP页面 分页导航代码:
<%-- 分页导航 --%>
<table border="0" width="780" class="pageInfo">
<tr>
<td width="250">
共 <bean:write name="pager" property="totalRows"/><span class="pageInfo">条记录 </span>
第 <bean:write name="pager" property="currentPage"/>/<bean:write name="pager" property="totalPages"/>页
</td>
<td align="right" width="60">
<html:link page="/Displayall.do?viewPage=&action=first">首页</html:link>
</td>
<td align="right" width="60">
<logic:equal name="pager" property="hasPrevious" value="true">
<html:link page="/Displayall.do?viewPage=&action=previous">上一页</html:link>
</logic:equal>
<logic:equal name="pager" property="hasPrevious" value="false">
<span class="invalidLink">上一页</span>
</logic:equal>
</td>
<td align="center" width="4">
|
</td>
<td align="left" width="60">
<logic:equal name="pager" property="hasNext" value="true" >
<html:link page="/Displayall.do?viewPage=&action=next">下一页</html:link>
</logic:equal>
<logic:equal name="pager" property="hasNext" value="false">
<span class="invalidLink">下一页</span>
</logic:equal>
</td>
<td width="60">
<html:link page="/Displayall.do?viewPage=&action=last">末页</html:link>
</td>
<td width="160" align="rigth">
<%-- 跳转相应页面,参见下文页面跳转部分 --%>
<html:form action="/ViewPage.do">
跳转到
<html:text property="targetPage" size="3" maxlength="3"/>
<html:submit value="GO"/>
</html:form>
</td>
<td>
</td>
</tr>
</table>
<%-- 分页导航结束 --%>
5) 页面跳转部分:
Form:
ViewPageForm
/*
* @(#)ViewPageForm.java 2005-5-9
*
* Copyright (c) 2005, Jeffrey Xu
*/
package com.jeffrey.messagelove;
import org.apache.struts.action.*;
public class ViewPageForm extends ActionForm {
// 欲跳转的目标页面
private String targetPage;
/**
* @return Returns the tagetPage.
*/
public String getTargetPage() {
return targetPage;
}
/**
* @param tagetPage The tagetPage to set.
*/
public void setTargetPage(String targetPage) {
this.targetPage = targetPage;
}
}
Action:
根据Form传递进来的目标页面信息跳转之相应的页面
如果输入的数字合法,则跳转至相应的页面,否则跳转至当前页面(在用户看来页面没有变化)
/*
* @(#)ViewPageAction.java 2005-5-9
*
* Copyright (c) 2005, Jeffrey Xu
*/
package com.jeffrey.messagelove;
import org.apache.struts.action.*;
import javax.servlet.http.*;
public class ViewPageAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String targetPage = ((ViewPageForm) form).getTargetPage();
HttpSession session = request.getSession();
Pager pager = (Pager) session.getAttribute("pager");
try {
// 判断是否超出页面范围
if ((Integer.parseInt(targetPage) > pager.getTotalPages()) ||
(Integer.parseInt(targetPage) < 1)) {
targetPage = String.valueOf(pager.getCurrentPage());
}
// 如果输入的不是数字,也就是抛出NumberFormatException异常,
} catch (NumberFormatException e) {
e.printStackTrace();
targetPage = String.valueOf(pager.getCurrentPage());
}
request.removeAttribute(mapping.getAttribute());
return (new ActionForward("/Displayall.do?viewPage=" + targetPage));
}
}
四、 相关配置
<form-beans>
<form-bean name="ViewPageForm" type="com.jeffrey.messagelove.ViewPageForm"/>
</form-beans>
<global-forwards>
<!-- Default forward to "Welcome" action -->
<!-- Demonstrates using index.jsp to forward -->
<forward
name="displayall"
path="/Displayall.do?viewPage=1"/>
</global-forwards>
<!-- =========================================== Action Mapping Definitions -->
<action-mappings>
<!-- Default "Welcome" action -->
<!-- Forwards to Welcome.jsp -->
<action
path="/Displayall"
type="com.jeffrey.messagelove.DisplayAllAction"
scope="request"
validate="false"
>
</action>
<action
path="/ViewPage"
type="com.jeffrey.messagelove.ViewPageAction"
name="ViewPageForm"
scope="request"
validate="false"
>
<forward name="viewPage" path="/displayall.do?viewPage="/>
</action>
</action-mappings>
五、 结束:
代码已经全部结束,但是总觉得JSP页面的代码太多,期待有更好的解决办法,比如封装成自定义JSP标签Tag,复用度更高。
还有就是页面跳转部分我想做成下拉列表的方式,根据总页数来动态生成下拉列表,这样更方便一些,并且可以避免用户的错误输入,但我不知该如何根据总页数来动态生成下拉列表,希望哪位朋友能够给出一个解决办法。
水平有限,难免有不妥的地方,如果您有好的意见或建议请回复或与我联系,在下感激不尽!