07-06
26
Struts分页的多个实现 (后台分页)
作者:Java伴侣 日期:2007-06-26
Struts分页的一个实现
在Web应用程序里,分页总让我们开发人员感到很头疼,倒不是因为技术上有多么困难,只是本来和业务没有太多关系的这么一个问题,你却得花不少功夫来处理。要是稍不留神,时不时出点问题就更郁闷了。我现在做的一个项目也到了该处理分页的时候了,感觉以前处理得都不好,所以这次有所改变,基本目标是在现有(未分页)的代码基础上,尽量少做修改,并且同样的代码可以应用于不同模块的分页。以下就是我用的方法:
首先,考虑分页绝大多数发生在列表时,组合查询时也需要用到。在我的项目里,列表的Action一般名字为ListXXXActioin,例如客户列表是ListClientsAction等等。在未分页前,ListXXXAction里会把所有的对象取出,通过request.setAttribute()放在request里,然后将请求转向到列表的jsp(例如listClients.jsp)显示出来(你可能会说不要在Action里放业务逻辑,但现在这不是我们考虑的重点)。而分页后,我们只取用户请求页对应的那些对象。为了最大限度的达到代码重用,我做了以下工作:
1、新建一个Pager类,该类有beginPage、endPage、currentPage、pageSize和total等int类型的属性,分别代表开始页、结束页、当前页、每页记录数和总记录数,它主要是让jsp页面显示页导航使用的。请注意currentPage属性是从0开始的。
2、新建一个AbstractListActioin类,并让所有ListXXXAction都继承它。在这个类里覆盖execute()方法,可以在这里判断权限等等,并在判断权限通过后执行一个abstract的act()方法,这个act()由ListXXXAction来实现。
3、在AbstractListAction里增加getPage()方法,用来从request得到用户请求的页码(若未请求则认为是第0页):
protected int getPage(HttpServletRequest request) {
String p = request.getParameter("p");
if (p == null)
return 0;
else
try {
return Integer.parseInt(p);
} catch (NumberFormatException e) {
return 0;
}
}
String p = request.getParameter("p");
if (p == null)
return 0;
else
try {
return Integer.parseInt(p);
} catch (NumberFormatException e) {
return 0;
}
}
4、在AbstractListAction里增加makePager()方法,用来向request里增加一个Pager类的实例,供jsp页面显示页导航:
protected Pager makePager(HttpServletRequest request, int total) {
Pager pager=new Pager();
pager.setTotal(total);
pager.setPageSize(Config.getInstance().getPageSize());
pager.setBeginPage(0);
pager.setEndPage(((pager.getTotal()) - 1) / pager.getPageSize() + 1);
pager.setCurrentPage(getPage(request));
return pager;
}
Pager pager=new Pager();
pager.setTotal(total);
pager.setPageSize(Config.getInstance().getPageSize());
pager.setBeginPage(0);
pager.setEndPage(((pager.getTotal()) - 1) / pager.getPageSize() + 1);
pager.setCurrentPage(getPage(request));
return pager;
}
注意在我的项目里,每页记录数是写在配置文件里的,如果你没有配置文件,上面第4行setPageSize()的参数直接填数字即可,例如pager.setPageSize(10);
5、这样,所有的ListXXXAction都可以使用getPage()得到请求的页码,并且能够方便的通过makePager()构造需要放在request里的pager对象了。现在要在从数据库取数据的代码上再做一些修改,即只取所需要的那一部分数据。由于我的项目中使用了Hibernate,所以这个修改也不是很困难。未分页前,在我的ListClientsAction里是通过构造一个Query来得到全部Client的,现在,只要在构造这个Query后再加两句(setMaxResults和setFirstResult)即可:
Query query = ;//构造query的语句
int total = ;//得到总记录数
Pager pager = makePager(request, total);//调用父类中的方法构造一个Pager实例
query.setMaxResults(pager.getPageSize());//设置每页记录数
query.setFirstResult(pager.getCurrentPage() * pager.getPageSize()); //设置开始位置
request.setAttribute(Pager.class.getName(), pager);//把pager放在request里
request.setAttribute(Client.class.getName(), query.list());
int total = ;//得到总记录数
Pager pager = makePager(request, total);//调用父类中的方法构造一个Pager实例
query.setMaxResults(pager.getPageSize());//设置每页记录数
query.setFirstResult(pager.getCurrentPage() * pager.getPageSize()); //设置开始位置
request.setAttribute(Pager.class.getName(), pager);//把pager放在request里
request.setAttribute(Client.class.getName(), query.list());
目前存在一个问题,就是在上面代码的第二句中,应该是获得总记录数,但我暂时没有特别好的办法不得到全部对象而直接得到记录数,只能很恐怖的用“int total = query.list().size();”,汗……
6、最后,我写了一个页导航的jsp页面pager.jsp,供各个显示列表的jsp来include,代码如下:
<%Pager pager=(Pager)request.getAttribute(Pager.class.getName());%>
<table width="90%" border="0" align="center" cellpadding="2" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#EEEEEE" align="right">
<bean:message key="prompt.pager" arg0="<%=""+pager.getTotal()%>"/>
[
<%
String url=request.getRequestURL().toString();
for(int i=pager.getBeginPage();i<pager.getEndPage();i++){
if(i==pager.getCurrentPage()){
%>
<%=(i+1)%>
<%}else{
String qs=request.getQueryString()==null?"":request.getQueryString();
String op = "p="+pager.getCurrentPage();//Original page parameter expression
String np = "p="+i;//New expression
if(qs.indexOf(op)==-1)
qs=np+"&"+qs;
qs=qs.replaceAll(op,np);
%>
<a href="<%=url+"?"+qs%>"><%=(i+1)%></a>
<%}%>
<%if(i<pager.getEndPage()-1){%>
<%}%>
<%}%>
]
</td></tr>
</table>
<table width="90%" border="0" align="center" cellpadding="2" cellspacing="1" bgcolor="#CCCCCC">
<tr>
<td bgcolor="#EEEEEE" align="right">
<bean:message key="prompt.pager" arg0="<%=""+pager.getTotal()%>"/>
[
<%
String url=request.getRequestURL().toString();
for(int i=pager.getBeginPage();i<pager.getEndPage();i++){
if(i==pager.getCurrentPage()){
%>
<%=(i+1)%>
<%}else{
String qs=request.getQueryString()==null?"":request.getQueryString();
String op = "p="+pager.getCurrentPage();//Original page parameter expression
String np = "p="+i;//New expression
if(qs.indexOf(op)==-1)
qs=np+"&"+qs;
qs=qs.replaceAll(op,np);
%>
<a href="<%=url+"?"+qs%>"><%=(i+1)%></a>
<%}%>
<%if(i<pager.getEndPage()-1){%>
<%}%>
<%}%>
]
</td></tr>
</table>
我觉得有必要解释一下,在上面的代码中,关于每一页对应的url是这样处理。取request.getRequestURL().toString()和request.getQueryString(),其中前者是不需要变的,而后者中可能包含“q=2”这样的页码请求也可能不包含即缺省请求第0页,所以统一用replaceAll()方法将其去掉,然后将对应的页码请求串(如“q=3”)加在qs的前面。这样做的好处是,每个模块都可以使用这个页导航,并且不会丢失url中的其他参数(例如今后加入排序功能后,url中可能包含“dir=desc”这样的参数)。
在列表jsp(listClients.jsp)中,很简单的这样include它(之所以要放在<logic:notEmpty>里,是希望在没有记录可显示的时候就不显示页导航了):
<logic:notEmpty name="<%=Client.class.getName()%>">
<%@include file="/pager.jsp"%>
</logic:notEmpty>
<%@include file="/pager.jsp"%>
</logic:notEmpty>
经过上面几步的处理,我的客户列表已经可以实现分页了,效果见下图。如果在另外一个模块中也需要分页,比如部门列表时,只需要1、修改ListDeptsAction继承AbstractListAction,2、在ListDeptsAction里增加setMaxResults()和setFirstResults()方法,3、在listDepts.jsp中适当的位置include页导航,就可以了,改动是相当小的。
最后,如果希望组合查询的结果也能够分页,必须指定组合查询表单的method属性为“GET”,这样查询要求会被记录在url中,分页导航从而能够正常的工作(每次换页都将查询要求和请求的页码提交)。
在struts中分页的一种实现
在struts中分页的一种实现
我的项目中的分页功能
1, 思路
使用一个页面控制类,它记录页面信息,如上页,下页,当前页等。在查询的Action中,将这个控制类和查询条件一起传递给数据库访问bean,然后将这两个参数保存在用户session中。在分页控制Action中,利用接收到的分页参数调用数据库访问的bean.
2,实现
(1)分页控制类
/* @author nick
* Created on 2004-3-18
* file name:PageController.java
*
*
*/
package com.tower.util;
/**
* @author nick
* 2004-3-18
* 用来进行翻页控制
*
*/
public class PageController {
int totalRowsAmount; //总行数
boolean rowsAmountSet; //是否设置过totalRowsAmount
int pageSize=2; //每页行数
int currentPage=1; //当前页码
int nextPage;
int previousPage;
int totalPages; //总页数
boolean hasNext; //是否有下一页
boolean hasPrevious; //是否有前一页
String description;
int pageStartRow;
int pageEndRow;
public PageController(int totalRows){
setTotalRowsAmount(totalRows);
}
public PageController(){}
/**
* @param i
* 设定总行数
*/
public void setTotalRowsAmount(int i) {
if(!this.rowsAmountSet){
totalRowsAmount = i;
totalPages=totalRowsAmount/pageSize+1;
setCurrentPage(1);
this.rowsAmountSet=true;
}
}
/**
* @param i
*
* 当前页
*
*/
public void setCurrentPage(int i) {
currentPage = i;
nextPage=currentPage+1;
previousPage=currentPage-1;
//计算当前页开始行和结束行
if(currentPage*pageSize<totalRowsAmount){
pageEndRow=currentPage*pageSize;
pageStartRow=pageEndRow-pageSize+1;
}else{
pageEndRow=totalRowsAmount;
pageStartRow=pageSize*(totalPages-1)+1;
}
//是否存在前页和后页
if (nextPage>totalPages){
hasNext=false;
}else{
hasNext=true;
}
if(previousPage==0){
hasPrevious=false;
}else{
hasPrevious=true;
};
System.out.println(this.description());
}
/**
* @return
*/
public int getCurrentPage() {
return currentPage;
}
/**
* @return
*/
public boolean isHasNext() {
return hasNext;
}
/**
* @return
*/
public boolean isHasPrevious() {
return hasPrevious;
}
/**
* @return
*/
public int getNextPage() {
return nextPage;
}
/**
* @return
*/
public int getPageSize() {
return pageSize;
}
/**
* @return
*/
public int getPreviousPage() {
return previousPage;
}
/**
* @return
*/
public int getTotalPages() {
return totalPages;
}
/**
* @return
*/
public int getTotalRowsAmount() {
return totalRowsAmount;
}
/**
* @param b
*/
public void setHasNext(boolean b) {
hasNext = b;
}
/**
* @param b
*/
public void setHasPrevious(boolean b) {
hasPrevious = b;
}
/**
* @param i
*/
public void setNextPage(int i) {
nextPage = i;
}
/**
* @param i
*/
public void setPageSize(int i) {
pageSize = i;
}
/**
* @param i
*/
public void setPreviousPage(int i) {
previousPage = i;
}
/**
* @param i
*/
public void setTotalPages(int i) {
totalPages = i;
}
/**
* @return
*/
public int getPageEndRow() {
return pageEndRow;
}
/**
* @return
*/
public int getPageStartRow() {
return pageStartRow;
}
public String getDescription(){
String description="Total:"+this.getTotalRowsAmount()+
" items "+this.getTotalPages() +" pages";
// this.currentPage+" Previous "+this.hasPrevious +
// " Next:"+this.hasNext+
// " start row:"+this.pageStartRow+
// " end row:"+this.pageEndRow;
return description;
}
public String description(){
String description="Total:"+this.getTotalRowsAmount()+
" items "+this.getTotalPages() +" pages,Current page:"+
this.currentPage+" Previous "+this.hasPrevious +
" Next:"+this.hasNext+
" start row:"+this.pageStartRow+
" end row:"+this.pageEndRow;
return description;
}
public static void main(String args[]){
PageController pc=new PageController(3);
System.out.println(pc.getDescription());
// pc.setCurrentPage(2);
// System.out.println(pc.description());
// pc.setCurrentPage(3);
// System.out.println(pc.description());
}
}
(2)查询Action的代码片断
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
Base queryForm= (Base) form;
if(!queryForm.getName().equals("")){
PageController pc=new PageController();
EmployeeBase service=new EmployeeBase();
ArrayList result=(ArrayList)service.search(queryForm,pc);
HttpSession session=request.getSession();
session.setAttribute("queryForm",queryForm);
session.setAttribute("pageController",service.getPageController());
request.setAttribute("queryResult",result);
request.setAttribute("pageController",service.getPageController());
return mapping.findForward("haveResult");
}else{
return mapping.findForward("noResult");
}
}
(3),翻页Action的代码片断
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
//读取翻页参数
TurnPageForm turnPageForm=(TurnPageForm)form;
//从PageController中取出查询信息,并使用bean提供的调用接口处理结果
HttpSession session=request.getSession();
PageController pc=(PageController)session.getAttribute("pageController");
Base queryForm=(Base)session.getAttribute("queryForm");
pc.setCurrentPage(turnPageForm.getViewPage());
EmployeeBase service=new EmployeeBase();
ArrayList result=(ArrayList)service.search(queryForm,pc);
//根据参数将数据写入 request
request.removeAttribute("queryResult");
request.removeAttribute("pageController");
request.setAttribute("queryResult",result);
request.setAttribute("pageController",pc);
//forward 到显示页面
return mapping.findForward("haveResult");
}
(4)数据库访问bean中的片断
public Collection search(Base base, PageController pc)
throws SQLException {
ArrayList emps = new ArrayList();
ResultSet rs = getSearchResult(base);
rs.absolute(-1);
pc.setTotalRowsAmount(rs.getRow());
setPageController(pc);
if (rs.getRow() > 0) {
rs.absolute(pc.getPageStartRow());
do {
System.out.println("in loop" + rs.getRow());
Base b = new Base();
b.setName(rs.getString("Name"));
b.setIdCard(rs.getString("IDCard"));
System.out.println("From db:" + rs.getString("IDCard"));
emps.add(b);
if (!rs.next()) {
break;
}
} while (rs.getRow() < (pc.getPageEndRow() + 1));
}
return emps;
}
(5)在jsp中,翻页部分的代码片断
<bean:write name="pageController" property="description"/>
<logic:equal name="pageController" property="hasPrevious" value="true">
<a href="turnPage.do?viewPage=<bean:write name="pageController" property="previousPage"/>" class="a02">
Previous
</a>
</logic:equal>
<logic:equal name="pageController" property="hasNext" value="true">
<a href="turnPage.do?viewPage=<bean:write name="pageController" property="nextPage"/>" class="a02">
Next
</a>
</logic:equal>
这样一来,翻页的功能可以以你喜欢的方式表现给client
评论: 0 | 引用: 0 | 查看次数: 992
发表评论