Struts的MVC结构就是围绕ActionForm、Action、JSP、ActionForward以及各种business beans来设计的。Bean处理后的结果提交给JSP显示时,很可能由于数据行数比较多,需要分页显示。进行分页显示需要知道几个相关参数:需要显示的结果集(一般是数组)、总计分页的页面数量、当前显示的页面编号、该页面显示内容在结果集中的起止id。此外还需要提供在各个分页面之间跳转的链接。
Ø 设计思路:
目的:用一个ActionForm、一个Action以及在struts-config.xml中ActionForward信息来实现所有的查询结果分页显示。使这部分代码具有相当的可重用性。
Ø 实现方法:
查询的结果集总是和特定的JSP页面对应的,并且在各个页面之间进行跳转时结果集相对固定,改变的是页面的编号和数据行的内容。引入一个PageScroller类作为辅助,让它与一个结果集关联,通过操作这个辅助类来实现翻页以及页面跳转的功能。这个类具有以下属性:
private int totalRowsAmount; // 要显示的数据总的行数
private boolean rowsAmountSet; // 是否设置过totalRowsAmount
private int pageSize = 10; // 每页行数,改进时这个参数可以作为配置信息写在config文件中,动态读取。用户可以自定义修改。
private int currentPage = 1; // 默认时的显示页码编号
private int nextPage;
private int previousPage;
private int totalPages; // 总页数
private boolean hasNext; // 是否有下一页
private boolean hasPrevious; // 是否有前一页
private int pageStartRow;
private int pageEndRow;
有了这个辅助类以后,当用户请求显示查询结果时,处理查询请求的Action把结果集和PageScroller发送给JSP页面,JSP页面根据PageScroller的相关信息决定显示结果集中的某个数据段。初始情况下处理查询请求的Action会把currentPage设为1,即显示第一个页面的内容,在PageScroller中设置当前显示页面的相关的代码如下:
public void setCurrentPage(int i) {
currentPage = i;
nextPage = currentPage + 1;
previousPage = currentPage - 1;
// 计算当前页开始行和结束行
if (currentPage * pageSize < this.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;
}
}
第一次反馈的查询结果总是显示第一页的内容,用户如果要查看更多的信息,就要翻页显示。此时不需要重新进行查询,因为查询结果集还保存在session中,PageScroller对象也保存在session中。只要把PageScroller的名称和希望查看的页面编号发送给处理翻页请求的Action,由该Action根据请求的页面编码改变PageScroller的状态,然后再将其发送回JSP页面即可。
因为应用程序中所有的页面分页显示都要通过上述方法实现,因此Action和ActionForm需要有一定的通用性。在设计时每个JSP页面的PageScroller实例名称与页面匹配,该名称作为HTMl或表单的参数发送给Action, 在Action中根据PageScroller的名称从session中获取这个对象,然后再根据页面编号对PageScroller的状态进行修改,最后根据PageScroller的名称决定返回到哪个JSP页面进行显示。
PageScrollerForm的相关代码如下:
public class PageScrollerForm extends ActionForm {
private String pagescrollername;
private String showPage;
public String getPagescrollername() {
return pagescrollername;
}
public void setPagescrollername(String pagesrollername) {
this.pagescrollername = pagesrollername;
}
public String getShowPage() {
return showPage;
}
public void setShowPage(String showPage) {
this.showPage = showPage;
}
}
PageScrollerAction的相关代码如下:
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws IOException,ServletException{
String pagescrollername = null;
int showPage = 1;
//有两种方式可以提交翻页的信息,一是通过表单“转到第X页”的方式,另一种是通过链接“上一页”、“下一页”的方式
if (form != null) {
PageScrollerForm psForm = (PageScrollerForm) form;
pagescrollername = psForm.getPagescrollername();
showPage = Integer.parseInt(psForm.getShowPage());
}else{
pagescrollername = request.getParameter("pagescrollername");
String spage = request.getParameter("showPage");
showPage = Integer.parseInt(spage);
}
HttpSession session = request.getSession();
PageScroller ps = (PageScroller)session.getAttribute(pagescrollername);
ps.setCurrentPage(showPage);
return mapping.findForward(pagescrollername);
}
Ø 实例:
在ETM下载系统中,用户提供轨道参数,检索结果需要分页显示。在SearchSubmitAction中处理检索的逻辑。其中execute()方法的部分代码如下所示:
//1清除原先保存在session中的查询结果
session.removeAttribute("etmdata");
session.removeAttribute("etmdataPage");
//2从Form中获取用户提供的轨道参数
EtmParamForm myform = (EtmParamForm)form;
String path = myform.getPath();
String row = myform.getRow();
String[] date = new String[3];
date[0] = myform.getYear();
date[1] = myform.getMonth();
date[2] = myform.getDay();
//3 连接到数据库进行检索
DbEtmSearch dbetmsearch = new DbEtmSearch();
EtmParameters[] result = dbetmsearch.getETMImages(path,row,date);
//4 将查询结果与一个PageScroller进行绑定,保存在session中
if(result != null){
PageScroller ps = new PageScroller(result.length);//设置一个分页控制器
//将新的查询结果保存在session中
session.setAttribute("etmdata",result);
session.setAttribute("etmdataPage",ps);
}
return mapping.findForward("next");
上述代码的最后一句mapping.findForward("next")根据struts配置文件中的设置将转到一个JSP页面显示这次查询的结果。此时PageScroller的状态是显示第一页的内容。
在JSP页面中,先从session当中取出查询结果以及与它关联的PageScroller
EtmParameters[] result = (EtmParameters[])session.getAttribute("etmdata");
PageScroller ps = (PageScroller)session.getAttribute("etmdataPage");
然后根据PageScroller的状态确定此次需要显示的内容,确定起止行号,用一个for循环显示这个页码中的内容。
if(result != null && ps != null){
//PageScroller起始计数从1开始,而数组是从0开始的,这里做一个调整。
int startRow = ps.getPageStartRow() - 1;
int endRow = ps.getPageEndRow() - 1;
for(int i=startRow;i<=endRow;i++){
…………
}
上面显示了查询结果的第一页内容,接下来需要显示给用户的是这次查询所得到的数据集的内容,包括总的页面数、当先显示的页面、以及转到其他页面的链接。首先要显示的是页面跳转的链接:
<html:form action="/PageScroll" method="POST">
<p><html:hidden property="pagescrollername" value="etmdataPage"/></p>
<p>共有 <font color=black ><%=ps.getTotalPages()%></font> 页 现在是第 <font color=black ><%=ps.getCurrentPage()%></font> 页 转到第
<html:select property="showPage" size="1">
<%
for(int i=1;i<=ps.getTotalPages();i++){
out.println("<option value=" + i + ">" + i + "</option>");
}
%>
</html:select>页
<html:submit value="转到"/>
</html:form>
这个form的目的就是将pagescrollername和showPage这两个参数发送给PageScrollAction,然后由PageScrollAction把PageScroll的currentPage设置为showPage,最后再把结果返回给JSP页面。这次返回给JSP页面的PageScroll状态就发生了改变,显示showPage页的数据。
另外,还要提供“上一页”、“下一页”的链接,这时就不是用Form来传递参数,而是用<html:link>来传递这两个参数。方法如下:
<%
if(ps.isHasPrevious()){
java.util.HashMap newparam = new java.util.HashMap();
newparam.put("pagescrollername",new String("etmdataPage"));
newparam.put("showPage",new Integer(ps.getCurrentPage() - 1));
pageContext.setAttribute("newparam", newparam);
%>
<html:link action="/PageScroll" name="newparam">上一页 </html:link>
<%
}
%>
用<html:link>传递多个参数,struts提供了一个HashMap的方法将参数的key/value值保存在HashMap中,然后使用name属性将这个HashMap中保存的参数读取出来,以HTML参数的方式发送给ScrollerPageAction执行。上面的<html:link>解析后成为:
<a href=”http://localhost:8008/etm-struts/PageScroll.do?pagescrollername=etmdataPage&showPage= 2” >上一页</a>
ScrollerPageAction就可以像读取普通的HTML参数那样用request.getParameter()方法来获取这两个参数。