传统分页功能的实现
之前一直认为分页是很繁琐的事情,随着时间的积累,这一次再次接触到分页功能,思路清晰了许多,其实分页无非就是根据页面的显示信息获取分页的几个值,大体上这些值也可以分类的:
比如:页面传递的值或者默认的值;通过查询数据库的内容来获取的值;通过推导公式计算出来的值。
(其实推导都是很简单的,只不过一提公式脑袋就大了,这是典型的不动脑的习惯,我本人属于此类,呵呵,所以大家还是多动脑,动脑,脑袋越动越灵活。)
下面我们分析关于分页所需要哪些内容:其实基本上所有网页的分页都是大同小异的,或许我们有时候会有很多分页工具封装好了这些分页内容,比如mybatis的pageHelper类,直接封装好了分页信息,我们直接拿来用即可。
但是明白了分页的最基本的原理,这些分页工具会起到画龙点睛的作用。下面我们开看看具体的分页信息:
1、创建一个pageBean类:封装分页所需要的几个字段,这个类是为了代码复用,因为分页这个功能很多模块可能都会涉及到,到时候我们直接调用即可。
首先我们看一个页面:
这是一个分页的典型的图片,基本很多分页都是基于此来开发的,下面看下有多少分页字段:
首先分页是对什么进行分页:页面要显示数据列表,而这些数据列表需要分页显示。所以我们要获取这些数据列表,然后加上分页的信息,将数据列表实现分段。
即字段:
recordList 每个页面显示的记录的列表。(这里涉及到每页都是从多少条记录开始显示的)
总记录数是多少:recordCount
我们看到页次:当前页/总共的页数 即 currentPage / pageCount
每页显示的条数:pageSize
另外我们看到我们想看哪一页就点击哪一页,总共要显示多少个页码,是都显示还是只显示一部分页码(这里又有一种方案),想跳转到哪一页就跳转到哪一页。
根据上面的分析所得:分页的信息就是这些,接下来就是如何获取这些信息对应的数据的值,然后将此pageBean封装好这些信息然后反馈到页面,页面获取到这些信息进行显示。
这里我们分三类:
(1)页面传递的或者默认可以设置的字段:每页显示条数:pageSize (可以默认自己设置多少值) ;当前页currentPage (通常默认为第一页)
(2)需要查询数据库获取的字段的值:
显示列表的总记录数recordCount:SELECT COUNT(*) FROM table WHERE 条件
加上分页后获取当前页面显示的记录的条数recordList:即每页页面显示的数据列表:
getSession().createQuery(//
"FROM Reply r WHERE r.topic= ? ORDER BY r.postTime ")
.setParameter(0,topic)
.setFirstResult((pageNum-1)*10)
注意这里有隐含的信息:比如我们设置每页显示10条记录,总共33条记录,第一页显示0--10记录数,第二页显示10--20,第三页显示30---40;即么每页显示10条。
所以这里设置每页的开始记录就是:(pageNum-1)*10
.setMaxResults(pageSize)
.list();
(3)获取到上面这些字段后,我们分析下如何通过公式计算剩下的字段:
总共多少页:pageCount,
页码开始的索引页beginPageIndex,页面结束的索引:endPageIndex(为什么要设置这两个字段呢,因为我们要进行列表的显示)
//计算剩余的三个值,根据公式进行计算
pageCount=(recordCount+pageSize-1)/pageSize;
/*计算开始页索引和结束页索引:这里我们定义总共显示10个页码。分几种情况
* 第一:当总共页数pageCount不足10页的时候,则显示全部页码
* 第二:当总共页数超过10页时,则显示当前页的前4页和当前页的后5页。
* 但是这里又有两种情况:如果总共有11页,当前页是3,则3-4=-1,这是不可以的,
* 即当前面的页面少于4个时,这个时候显示前十页。
* 同理:当后面的页面不足5个时,显示后10页。
*/
if (pageCount<=10) {
beginPageIndex=1;
endPageIndex=pageCount;
}else{
beginPageIndex=currentPage-4;
endPageIndex=currentPage+5;
if (beginPageIndex-4<1) {
beginPageIndex=1;
endPageIndex=10;
}
if (endPageIndex>pageCount) {
beginPageIndex=currentPage-10+1;
endPageIndex=pageCount;
}
}
}
最后一步就是将封装好内容的pageBean传递到页面:页面获取响应的值
2、修改jsp页面信息
这里主要是注意struts2标签内部使用OGNL表达式,在HTML标签里面或者标签体使用EL表达式。
OGNL用%{} EL表达式用${}获取。
3、具体代码如下:
package cn.itcast.oa.domain; import java.util.List; public class PageBean { //主要是对分页的几个字段属性进行封装,这些字段都可以根据jsp页面来进行推断出来 //这些可以页码获取 private int currentPage;//当前页码 private int pageSize;//每页显示多少条记录 //这些可以数据库获取 private List recordList;//本页的数据列表 private int recordCount;//总记录数 //这些可以根据上面的计算得到 private int pageCount;//总共多少页 private int beginPageIndex;//页码的开始索引 private int endPageIndex;//页码的结束索引 public PageBean(int currentPage, int pageSize, List recordList, int recordCount) { super(); this.currentPage = currentPage; this.pageSize = pageSize; this.recordList = recordList; this.recordCount = recordCount; //计算剩余的三个值,根据公式进行计算 pageCount=(recordCount+pageSize-1)/pageSize; /*计算开始页索引和结束页索引:这里我们定义总共显示10个页码。分几种情况 * 第一:当总共页数pageCount不足10页的时候,则显示全部页码 * 第二:当总共页数超过10页时,则显示当前页的前4页和当前页的后5页。 * 但是这里又有两种情况:如果总共有11页,当前页是3,则3-4=-1,这是不可以的, * 即当前面的页面少于4个时,这个时候显示前十页。 * 同理:当后面的页面不足5个时,显示后10页。 */ if (pageCount<=10) { beginPageIndex=1; endPageIndex=pageCount; }else{ beginPageIndex=currentPage-4; endPageIndex=currentPage+5; if (beginPageIndex-4<1) { beginPageIndex=1; endPageIndex=10; } if (endPageIndex>pageCount) { beginPageIndex=currentPage-10+1; endPageIndex=pageCount; } } } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public List getRecordList() { return recordList; } public void setRecordList(List recordList) { this.recordList = recordList; } public int getRecordCount() { return recordCount; } public void setRecordCount(int recordCount) { this.recordCount = recordCount; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getBeginPageIndex() { return beginPageIndex; } public void setBeginPageIndex(int beginPageIndex) { this.beginPageIndex = beginPageIndex; } public int getEndPageIndex() { return endPageIndex; } public void setEndPageIndex(int endPageIndex) { this.endPageIndex = endPageIndex; } }
//因为页面是要获取的是关于分页的pageBean这个类,页面获取里面的值,所以这里要想办法查询出pageBean这里面的字段的值 @Override public PageBean getPageBeanByTopic(int pageNum, int pageSize, Topic topic) { List list=getSession().createQuery(// "FROM Reply r WHERE r.topic= ? ORDER BY r.postTime ") .setParameter(0,topic) .setFirstResult((pageNum-1)*10) .setMaxResults(pageSize) .list(); Long count=(Long) getSession().createQuery( "SELECT COUNT(*) FROM Reply r WHERE r.topic= ? ") .setParameter(0,topic) .uniqueResult(); return new PageBean(pageNum, pageSize, list, count.intValue()); }
步骤应该是这样:先分析了类的字段,然后从数据库中查询中部分字段,然后将部分字段带入公式计算剩下的字段。
这里使用了根据部分字段来写构造方法,然后service在调用这个构造方法,计算公式。
看下jsp页面的代码:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>查看主题:${topic.title}</title> <%@ include file="/WEB-INF/jsp/public/commons.jspf" %> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/style/blue/forum.css" /> <script language="javascript" src="${pageContext.request.contextPath}/script/fckeditor/fckeditor.js" charset="utf-8"></script> <script type="text/javascript"> $(function(){ var fck = new FCKeditor("content"); fck.Width = "90%"; fck.ToolbarSet = "bbs"; fck.BasePath = "${pageContext.request.contextPath}/script/fckeditor/"; fck.ReplaceTextarea(); }); </script> </head> <body> <!-- 标题显示 --> <div id="Title_bar"> <div id="Title_bar_Head"> <div id="Title_Head"></div> <div id="Title"><!--页面标题--> <img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/> 查看主题 </div> <div id="Title_End"></div> </div> </div> <!--内容显示--> <div id="MainArea"> <div id="PageHead"></div> <center> <div class="ItemBlock_Title1" style="width: 98%"> <font class="MenuPoint"> > </font> <s:a action="forum_list">论坛</s:a> <font class="MenuPoint"> > </font> <s:a action="forum_show?id=%{#topic.forum.id}">${topic.forum.name}</s:a> <font class="MenuPoint"> >> </font> 帖子阅读 <span style="margin-left:30px;"> <s:a action="topic_addUI?forumId=%{#topic.forum.id}"> <img align="absmiddle" src="${pageContext.request.contextPath}/style/blue/images/button/publishNewTopic.png"/> </s:a> </span> </div> <div class="ForumPageTableBorder dataContainer" datakey="replyList"> <!--显示主题标题等--> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr valign="bottom"> <td width="3" class="ForumPageTableTitleLeft"> </td> <td class="ForumPageTableTitle"><b>本帖主题:${topic.title}</b></td> <td class="ForumPageTableTitle" align="right" style="padding-right:12px;"> <s:a cssClass="detail" action="reply_addUI?topicId=%{#topic.id}"> <img border="0" src="${pageContext.request.contextPath}/style/images/reply.gif" /> 回复 </s:a> <a href="moveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />移动到其他版块</a> <a href="#" onClick="return confirm('要把本主题设为精华吗?')"><img border="0" src="${pageContext.request.contextPath}/style/images/topicType_1.gif" />精华</a> <a href="#" onClick="return confirm('要把本主题设为置顶吗?')"><img border="0" src="${pageContext.request.contextPath}/style/images/topicType_2.gif" />置顶</a> <a href="#" onClick="return confirm('要把本主题设为普通吗?')"><img border="0" src="${pageContext.request.contextPath}/style/images/topicType_0.gif" />普通</a> </td> <td width="3" class="ForumPageTableTitleRight"> </td> </tr> <tr height="1" class="ForumPageTableTitleLine"><td colspan="4"></td></tr> </table> <!-- ~~~~~~~~~~~~~~~ 显示主帖(主帖只在第1页显示) ~~~~~~~~~~~~~~~ --> <s:if test="currentPage==1"> <div class="ListArea"> <table border="0" cellpadding="0" cellspacing="1" width="100%"> <tr> <td rowspan="3" width="130" class="PhotoArea" align="center" valign="top"> <!--作者头像--> <div class="AuthorPhoto"> <img border="0" width="110" height="110" src="${pageContext.request.contextPath}/style/images/defaultAvatar.gif" onerror="this.onerror=null; this.src='${pageContext.request.contextPath}/style/images/defaultAvatar.gif';" /> </div> <!--作者名称--> <div class="AuthorName">${topic.author.name}</div> </td> <td align="center"> <ul class="TopicFunc"> <!--操作列表--> <li class="TopicFuncLi"> <a class="detail" href="${pageContext.request.contextPath}/BBS_Topic/saveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />编辑</a> <a class="detail" href="#" onClick="return confirm('确定要删除本帖吗?')"><img border="0" src="${pageContext.request.contextPath}/style/images/delete.gif" />删除</a> </li> <!-- 文章的标题 --> <li class="TopicSubject"> ${topic.title} </li> </ul> </td> </tr> <tr><!-- 文章内容 --> <td valign="top" align="center"> <div class="Content">${topic.content}</div> </td> </tr> <tr><!--显示楼层等信息--> <td class="Footer" height="28" align="center" valign="bottom"> <ul style="margin: 0px; width: 98%;"> <li style="float: left; line-height:18px;"><font color=#C30000>[楼主]</font> ${topic.postTime} </li> <li style="float: right;"><a href="javascript:scroll(0,0)"> <img border="0" src="${pageContext.request.contextPath}/style/images/top.gif" /></a> </li> </ul> </td> </tr> </table> </div> </s:if> <!-- ~~~~~~~~~~~~~~~ 显示主帖结束 ~~~~~~~~~~~~~~~ --> <!-- ~~~~~~~~~~~~~~~ 显示回复列表 ~~~~~~~~~~~~~~~ --> <s:iterator value="recordList" status="status"> <div class="ListArea template"> <table border="0" cellpadding="0" cellspacing="1" width="100%"> <tr> <td rowspan="3" width="130" class="PhotoArea" align="center" valign="top"> <!--作者头像--> <div class="AuthorPhoto"> <img border="0" width="110" height="110" src="${pageContext.request.contextPath}/style/images/defaultAvatar.gif" onerror="this.onerror=null; this.src='${pageContext.request.contextPath}/style/images/defaultAvatar.gif';" /> </div> <!--作者名称--> <div class="AuthorName">${author.name}</div> </td> <td align="center"> <ul class="TopicFunc"> <!--操作列表--> <li class="TopicFuncLi"> <a class="detail" href="${pageContext.request.contextPath}/BBS_Topic/saveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />编辑</a> <a class="detail" href="#" onClick="return confirm('确定要删除本帖吗?')"><img border="0" src="${pageContext.request.contextPath}/style/images/delete.gif" />删除</a> </li> <!-- 文章表情与标题 --> <li class="TopicSubject"> ${title} </li> </ul> </td> </tr> <tr><!-- 文章内容 --> <td valign="top" align="center"> <div class="Content">${content}</div> </td> </tr> <tr><!--显示楼层等信息--> <td class="Footer" height="28" align="center" valign="bottom"> <ul style="margin: 0px; width: 98%;"> <li style="float: left; line-height:18px;"><font color=#C30000>[${(currentPage-1)*pageSize + status.count}楼]</font> ${postTime} </li> <li style="float: right;"><a href="javascript:scroll(0,0)"> <img border="0" src="${pageContext.request.contextPath}/style/images/top.gif" /></a> </li> </ul> </td> </tr> </table> </div> </s:iterator> <!-- ~~~~~~~~~~~~~~~ 显示回复列表结束 ~~~~~~~~~~~~~~~ --> </div> <!--分页信息--> <div id=PageSelectorBar> <div id=PageSelectorMemo> 页次:${currentPage}/ ${pageCount} 页 每页显示:${pageSize}条 总记录数:${recordCount}条 </div> <div id=PageSelectorSelectorArea> <a href="javascript:gotoPage(1)" title="首页" style="cursor: hand;"> <img src="${pageContext.request.contextPath}/style/blue/images/pageSelector/firstPage.png"/> </a> <!-- 注意EL表达式是用在外面,OGNL表达式是用在struts标签的内部,标签内 --> <s:iterator begin="%{beginPageIndex}" end="%{endPageIndex}" var="num" > <!-- var属性的对象的值存在了map中,所以用#获取--> <s:if test="#num==currentPage"> <span class="PageSelectorNum PageSelectorSelected">${num}</span> </s:if> <!-- 非当前页 --> <s:else> <span class="PageSelectorNum" style="cursor: hand;" onClick="gotoPage(${num});">${num}</span> </s:else> </s:iterator> <a href="javascript:gotoPage(${pageCount})" title="尾页" style="cursor: hand;"> <img src="${pageContext.request.contextPath}/style/blue/images/pageSelector/lastPage.png"/> </a> 转到: <select onchange="gotoPage(this.value)" id="_pn" > <s:iterator begin="1" end="%{pageCount}" var="num"> <option value="${num}">${num}</option> </s:iterator> </select> <script type="text/javascript"> $("#_pn").val("${currentPage}"); </script> </div> </div> <!-- 这里有问题,页面跳转不过来 --> <script type="text/javascript"> function gotoPage(pageNum){ window.location.href="topic_show.action?id=${id}&pageNum="+pageNum; } </script> <div class="ForumPageTableBorder" style="margin-top: 25px;"> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr valign="bottom"> <td width="3" class="ForumPageTableTitleLeft"> </td> <td class="ForumPageTableTitle"><b>快速回复</b></td> <td width="3" class="ForumPageTableTitleRight"> </td> </tr> <tr height="1" class="ForumPageTableTitleLine"> <td colspan="3"></td> </tr> </table> </div> </center> <!--快速回复--> <div class="QuictReply"> <form action=""> <div style="padding-left: 3px;"> <table border="0" cellspacing="1" width="98%" cellpadding="5" class="TableStyle"> <tr height="30" class="Tint"> <td width="50px" class="Deep"><b>标题</b></td> <td class="no_color_bg"> <input type="text" name="title" class="InputStyle" value="回复:昨天发现在表单里删除的图片" style="width:90%"/> </td> </tr> <tr class="Tint" height="200"> <td valign="top" rowspan="2" class="Deep"><b>内容</b></td> <td valign="top" class="no_color_bg"> <textarea name="content" style="width: 95%; height: 300px"></textarea> </td> </tr> <tr height="30" class="Tint"> <td class="no_color_bg" colspan="2" align="center"> <input type="image" src="${pageContext.request.contextPath}/style/blue/images/button/submit.PNG" style="margin-right:15px;"/> </td> </tr> </table> </div> </form> </div> </div> <div class="Description"> 说明:<br /> 1,主帖只在第一页显示。<br /> 2,只有是管理员才可以进行“移动”、“编辑”、“删除”、“精华”、“置顶”的操作。<br /> 3,删除主帖,就会删除所有的跟帖(回复)。<br /> </div> </body> </html>