传统分页功能的实现

之前一直认为分页是很繁琐的事情,随着时间的积累,这一次再次接触到分页功能,思路清晰了许多,其实分页无非就是根据页面的显示信息获取分页的几个值,大体上这些值也可以分类的:

比如:页面传递的值或者默认的值;通过查询数据库的内容来获取的值;通过推导公式计算出来的值。

(其实推导都是很简单的,只不过一提公式脑袋就大了,这是典型的不动脑的习惯,我本人属于此类,呵呵,所以大家还是多动脑,动脑,脑袋越动越灵活。)

下面我们分析关于分页所需要哪些内容:其实基本上所有网页的分页都是大同小异的,或许我们有时候会有很多分页工具封装好了这些分页内容,比如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 >
    <div >
        <div ></div>
        <div ><!--页面标题-->
            <img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/> 查看主题
        </div>
        <div ></div>
    </div>
</div>

<!--内容显示-->	
<div >
	<div ></div>
	<center>
		<div class="ItemBlock_Title1" style=" 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;  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;  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)"  >
				   <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="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=" 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>