【OA】——封装分页

  引言

  分页是我们系统中常用的一个功能,尤其是在列表展示页面。下面总结一下SSH中分页功能的封装。


  第一、封装分页实体PageBean

package cn.itcast.oa.domain;

import java.util.List;

/**
 * 分页功能中的一页的信息
 * 
 * @author tyg
 * 
 */
public class PageBean {

	// 指定的或是页面参数
	private int currentPage; // 当前页
	private int pageSize; // 每页显示多少条

	// 查询数据库
	private int recordCount; // 总记录数
	private List recordList; // 本页的数据列表

	// 计算
	private int pageCount; // 总页数
	private int beginPageIndex; // 页码列表的开始索引(包含)
	private int endPageIndex; // 页码列表的结束索引(包含)

	/**
	 * 只接受前4个必要的属性,会自动的计算出其他3个属生的值
	 * 
	 * @param currentPage
	 * @param pageSize
	 * @param recordCount
	 * @param recordList
	 */
	public PageBean(int currentPage, int pageSize, int recordCount, List recordList) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
		this.recordCount = recordCount;
		this.recordList = recordList;

		// 计算总页码
		pageCount = (recordCount + pageSize - 1) / pageSize;

		// 计算 beginPageIndex 和 endPageIndex
		// >> 总页数不多于10页,则全部显示
		if (pageCount <= 10) {
			beginPageIndex = 1;
			endPageIndex = pageCount;
		}
		// >> 总页数多于10页,则显示当前页附近的共10个页码
		else {
			// 当前页附近的共10个页码(前4个 + 当前页 + 后5个)
			beginPageIndex = currentPage - 4;
			endPageIndex = currentPage + 5;
			// 当前面的页码不足4个时,则显示前10个页码
			if (beginPageIndex < 1) {
				beginPageIndex = 1;
				endPageIndex = 10;
			}
			// 当后面的页码不足5个时,则显示后10个页码
			if (endPageIndex > pageCount) {
				endPageIndex = pageCount;
				beginPageIndex = pageCount - 10 + 1;
			}
		}
	}

	public List getRecordList() {
		return recordList;
	}

	public void setRecordList(List recordList) {
		this.recordList = recordList;
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getPageCount() {
		return pageCount;
	}

	public void setPageCount(int pageCount) {
		this.pageCount = pageCount;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getRecordCount() {
		return recordCount;
	}

	public void setRecordCount(int recordCount) {
		this.recordCount = recordCount;
	}

	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;
	}

}

 

  第二、封装工具类(用来拼接hql语句)

package cn.itcast.oa.until;

import java.util.ArrayList;
import java.util.List;

import cn.itcast.oa.base.dao.DaoSupport;
import cn.itcast.oa.domain.PageBean;

import com.opensymphony.xwork2.ActionContext;

/***
 * 用户拼接HQL语句
 * 
 * @author zhenghao
 * 
 */
public class QueryHelper {
	private String fromClause; // FROM子句
	private String whereClause = ""; // Where子句
	private String orderByClause = ""; // OrderBy子句

	private List<Object> parameters = new ArrayList<Object>();// 参数列表

	/***
	 * 生成From字句
	 */

	public QueryHelper(Class clazz, String alias) {
		fromClause = "FROM " + clazz.getSimpleName() + " " + alias;
	}

	/**
	 * 拼接Where子句
	 * 
	 * @param condition
	 * @param params
	 */
	public QueryHelper addCondition(String condition, Object... params) {

		// 拼接
		if (whereClause.length() == 0) {
			whereClause = " WHERE " + condition;
		} else {
			whereClause += " AND " + condition;
		}
		// 参数
		if (params != null) {
			for (Object p : params) {
				parameters.add(p);
			}
		}
		return this;
	}

	/**
	 * 如果第一个参数为true,则拼接Where子句
	 * 
	 * @param append
	 * @param condition
	 * @param params
	 */
	public QueryHelper addCondition(boolean append, String condition, Object... params) {
		if (append) {
			addCondition(condition, params);
		}
		return this;
	}

	/**
	 * 拼接OrderBy子句
	 * 
	 * @param propertyName
	 *            参与排序的属性名
	 * @param asc
	 *            true表示升序,false表示降序
	 */
	public QueryHelper addOrderProperty(String propertyName, boolean asc) {
		if (orderByClause.length() == 0) {
			orderByClause = " ORDER BY " + propertyName + (asc ? " ASC" : " DESC");
		} else {
			orderByClause += ", " + propertyName + (asc ? " ASC" : " DESC");
		}
		return this;
	}

	/**
	 * 如果第一个参数为true,则拼接OrderBy子句
	 * 
	 * @param append
	 * @param propertyName
	 * @param asc
	 */
	public QueryHelper addOrderProperty(boolean append, String propertyName, boolean asc) {
		if (append) {
			addOrderProperty(propertyName, asc);
		}
		return this;
	}

	/**
	 * 获取生成的用于查询数据列表的HQL语句
	 * 
	 * @return
	 */
	public String getListQueryHql() {
		return fromClause + whereClause + orderByClause;
	}

	/**
	 * 获取生成的用于查询总记录数的HQL语句
	 * 
	 * @return
	 */
	public String getCountQueryHql() {
		return "SELECT COUNT(*) " + fromClause + whereClause;
	}

	/**
	 * 获取HQL中的参数值列表
	 * 
	 * @return
	 */
	public List<Object> getParameters() {
		return parameters;
	}

	/**
	 * 查询分页信息,并放到值栈栈顶
	 * 
	 * @param service
	 * @param pageNum
	 * @param pageSize
	 */
	public void preparePageBean(DaoSupport<?> service, int pageNum, int pageSize) {
		PageBean pageBean = service.getPageBean(pageNum, pageSize, this);
		ActionContext.getContext().getValueStack().push(pageBean);
	}
}

 方法解读:

  有一个构造方法,参数为类名和别名,其中拼接了一个from字句,这是因为每一个查询的hql语句from字句是必须有的,所以from字句的拼接在构造方法里面就完成了。

  有两个拼接条件的方法addCondition,主要是完成where字句的拼接,并且每拼接一个查询约束条件,对应在参数列表中添加一个参数,参数列表中的参数位置和where中的?的位置匹配。

  有两个拼接排序条件的方法,主要是完成order by字句的拼接,参数为排序的字段 和 排序规则(ASC OR  DESC),之所以是两个,是因为其中一个多一个用来判断的boolean类型的参数。

 有一个获取生成的用于查询数据列表的HQL语句方法getListQueryHql()

 有一个获取生成的用于查询总记录数的HQL语句getCountQueryHql()

 有一个获取hql中参数列表的方法getParameters()

 还有一个将查询的结果放在值栈中的方法preparePageBean()

总结:有了这样一个工具类以后,我们在action中只需要写一句代码就可以完成,分页的调用。需要主要是,上面工具类中,有很多的方法都是直接返回“this”。


 第三步、封装service接口(在service中直接操作了数据库)父类

/**
	 * 公共的查询分页信息的方法(最终版)
	 * 
	 * @param pageNum
	 * @param pageSize
	 * @param queryHelper
	 *            HQL语句与参数列表
	 * @return
	 */
	PageBean getPageBean(int pageNum, int pageSize, QueryHelper queryHelper);

第四步:具体的service中的实现()

// 公共的查询分页信息的方法(最终版)
	public PageBean getPageBean(int pageNum, int pageSize, QueryHelper queryHelper) {
		System.out.println("-------> DaoSupportImpl.getPageBean( int pageNum, int pageSize, QueryHelper queryHelper )");

		// 参数列表
		List<Object> parameters = queryHelper.getParameters();

		// 查询本页的数据列表
		Query listQuery = getSession().createQuery(queryHelper.getListQueryHql()); // 创建查询对象
		if (parameters != null) { // 设置参数
			for (int i = 0; i < parameters.size(); i++) {
				listQuery.setParameter(i, parameters.get(i));
			}
		}
		listQuery.setFirstResult((pageNum - 1) * pageSize);
		listQuery.setMaxResults(pageSize);
		List list = listQuery.list(); // 执行查询

		// 查询总记录数量
		Query countQuery = getSession().createQuery(queryHelper.getCountQueryHql());
		if (parameters != null) { // 设置参数
			for (int i = 0; i < parameters.size(); i++) {
				countQuery.setParameter(i, parameters.get(i));
			}
		}
		Long count = (Long) countQuery.uniqueResult(); // 执行查询

		return new PageBean(pageNum, pageSize, count.intValue(), list);
	}

第五步、具体的action的实现(topic)

            // 分页信息最终版
		new QueryHelper(Reply.class, "r")//
				.addCondition("r.topic=?", topic)//
				.addOrderProperty("r.postTime", true)//
				.preparePageBean(replyService, pageNum, pageSize);
   

      带有过滤条件的分页中的action实现

    // 准备分页信息 ,最终版
		new QueryHelper(Topic.class, "t")//
				// 过滤条件
				.addCondition("t.forum=?", forum)//
				.addCondition((viewType == 1), "t.type=?", Topic.TYPE_BEST) // 1
																			// 表示只看精华帖
				// 排序条件
				.addOrderProperty((orderBy == 1), "t.lastUpdateTime", asc) // 1
																			// 表示只按最后更新时间排序
				.addOrderProperty((orderBy == 2), "t.postTime", asc) // 2
																		// 表示只按主题发表时间排序
				.addOrderProperty((orderBy == 3), "t.replyCount", asc) // 3
																		// 表示只按回复数量排序
				.addOrderProperty((orderBy == 0), "(CASE t.type WHEN 2 THEN 2 ELSE 0 END)", false)//
				.addOrderProperty((orderBy == 0), "t.lastUpdateTime", false) // 0
																				// 表示默认排序(所有置顶帖在前面,并按最后更新时间降序排列)
				.preparePageBean(topicService, pageNum, pageSize);


 第六步;封装jsp(单独抽离出来)pageView.jspf

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<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>
		
		<s:iterator begin="%{beginPageIndex}" end="%{endPageIndex}" var="num">
			<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 οnchange="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 = "forum_show.action?id=${id}&pageNum=" + pageNum;
		
		$(document.forms[0]).append("<input type='hidden' name='pageNum' value='" + pageNum +"'>");
		document.forms[0].submit();
	}
	
</script>

         第七步、在具体页面中使用,在需要使用分页的地方写入下面代码

                       <!--分页信息-->
			<%@ include file="/WEB-INF/jsp/public/pageView.jspf"%>
			<s:form action="topic_show?id=%{id}"></s:form>
  如果我们需要多个筛选条件的话,可以将form表单将需要的条件包含住即可


 第八步、效果


 

  小结

  通过这样封装以后,如果在其他的页面中用到分页的话,将会很快的完成,并且会大大降低出错的几率,这也是封装的一个很大的优势!以后有类似的功能,则可以信手拈来啦!!!



评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

g-Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值