displaytag按需分頁的包裝及實例

displaytag1.1之後支持按需進行分頁查詢,在其官方網站有如下描述:

Displaytag 1.1 offers two alternative ways for working with partial lists:

  • the first one uses the valuelist pattern, and requires that the object that you give to displaytag implements theorg.displaytag.pagination.PaginatedList interface. You can pass this object to displaytag as an usual list, and it will extract paging and sorting information from it. This way is more recommended if you have to build your backend layer and you can easily follow this pattern.
  • a second way, recommended if you only have to use partial list for few tables that show a performance problem using full lists, is passing all the needed parameters as separate tag attributes (recors to be shown, page number, total number of records...)
參考:http://www.displaytag.org/1.2/tut_externalSortAndPage.html

當存在大數據量的時候,一般使用第一種方法。本文的示例來自實際項目,主要解決兩個問題:

1) 按需取得數據,利用displaytag實現頁面分頁顯示。

2) 對displaytag要求的分頁參數進行設置及複雜性包裝,便於快速開發。


主要的步驟如下:


1、創建一個簡單類實現org.displaytag.pagination.PaginatedList接口,此類在項目中公用,對於所有的分頁需求界面,不需要另造輪子。

package com.whyonly.core.displaytag;

import java.util.List;

import org.displaytag.pagination.PaginatedList;
import org.displaytag.properties.SortOrderEnum;

public class SimplePaginatedList<T> implements PaginatedList {

	private List<T> list;
	private int pageNumber = 1;
	private int objectsPerPage = 20;
	private int fullListSize = 0;
	private String sortCriterion;
	private SortOrderEnum sortDirection;
	private String searchId;

	public List<T> getList() {
		return list;
	}

	public void setList(List<T> list) {
		this.list = list;
	}

	public int getPageNumber() {
		return pageNumber;
	}

	public void setPageNumber(int pageNumber) {
		this.pageNumber = pageNumber;
	}

	public int getObjectsPerPage() {
		return objectsPerPage;
	}

	public void setObjectsPerPage(int objectsPerPage) {
		this.objectsPerPage = objectsPerPage;
	}

	public int getFullListSize() {
		return fullListSize;
	}

	public void setFullListSize(int fullListSize) {
		this.fullListSize = fullListSize;
	}

	public String getSortCriterion() {
		return sortCriterion;
	}

	public void setSortCriterion(String sortCriterion) {
		this.sortCriterion = sortCriterion;
	}

	public SortOrderEnum getSortDirection() {
		return sortDirection;
	}

	public void setSortDirection(SortOrderEnum sortDirection) {
		this.sortDirection = sortDirection;
	}

	public String getSearchId() {
		return searchId;
	}

	public void setSearchId(String searchId) {
		this.searchId = searchId;
	}

}

2,創建一個分頁包裝器,根據displaytag分頁的要求包裝共同性,同時把不同的部分通過接口的方式讓子類去處理,此包裝器也在項目中共用。

package com.whyonly.core.displaytag;

import java.util.List;

import javax.servlet.http.HttpServletRequest;


public abstract class PaginatedWrapper<T> {

	
	private int pageSize = 20;

	public void paginated(HttpServletRequest request) {
		int page = 1;

		if (request.getParameter("pageSize") != null
				&& !"".equals(request.getParameter("pageSize"))) {
			pageSize = Integer.parseInt(request.getParameter("pageSize"));
		} 
		if (request.getParameter("page") != null
				&& !"".equals(request.getParameter("page"))) {
			page = Integer.parseInt(request.getParameter("page"));
		} else {
			page = 1;
		}

		int fromIndex = (page - 1) * pageSize;
		int toIndex = fromIndex + pageSize;

		int fullListSize = getFullListSize();
		List<T> pageDatas = getPageDatas(fromIndex, toIndex);

		SimplePaginatedList<T> paginatedList = new SimplePaginatedList<T>();
		paginatedList.setPageNumber(page);

		if (pageDatas != null && pageDatas.size() > 0 && fullListSize > 0) {
			paginatedList.setFullListSize(fullListSize);
			paginatedList.setObjectsPerPage(pageSize);
			paginatedList.setList(pageDatas);
		} else {
			paginatedList.setFullListSize(0);
			paginatedList.setList(null);
		}
		request.setAttribute("pagedatas", paginatedList);
	}
	

	public PaginatedWrapper<T> setPageSize(int pageSize) {
		this.pageSize = pageSize;
		return this;
	}



	protected abstract List<T> getPageDatas(int fromIndex, int toIndex);

	protected abstract int getFullListSize();

}

PaginatedWrapper是一個抽象類,有以下幾個特性:

1) 支持泛型<T>,可以根據模塊的要求傳入相應的bean對象。

2) paginated()方法內聚和包裝了displaytag的參數需求,並進行了一些共有的初始化。同時也提供了pagesize大小的設置,默認是20,注意setPageSize放回的this,此處使用了反回自身的方式,便於連續的屬性設置。

3) 抽象方法 protected abstract List<T> getPageDatas(int fromIndex, int toIndex) 和 protected abstract int getFullListSize() 對每個模塊,具有不同性,因此通過接口方法的方式留給具體的模塊去實現。實現一般放在Dao層,然後通過前臺Controller(Spring),或者Action(Struts),或者Jsp去調用。


3,使用1,2步驟創建好的兩個包裝類,應用到具體的項目。下面以SSH2爲例,也可以應用到其它的框架結構,因爲SSH的框架比較通用,以下只給出關鍵代碼,具體的實現應該是簡單的。

3.1, Action類


	@Actions( {                                                                                       
		@Action(value = "/queryIncidental", results = {                                                         
				@Result(location = "center/pos/incidental_query_result.jsp", name = "success"), 
				})  
		})                                                                                              
	})                                                                                                
	public String queryIncidental(){                                                         
			new PaginatedWrapper<Posbatch>(){
				@Override
				protected List<Posbatch> getPageDatas(int fromIndex, int toIndex) {
					return service.initQueryIncidentalByPage(mv,getCompid(), fromIndex, toIndex);
				}

				@Override
				protected int getFullListSize() {
					return service.findFullSizeByCustAndDate(mv,getCompid());
				}
				
			}.paginated(request);
			return SUCCESS;                                                                                 
	}

以上Action的關鍵點在於實現getPageDatas()方法和getFullListSize()方法,service是業務邏輯成對象,如果用了Spring,可以通過@Autowired自動注入。


3.2) Service類

	public List<Posbatch> initQueryIncidentalByPage(IncidentalMV mv, int compid, int fromIndex, int toIndex) {	
		String custcode = mv.getCustcode();
		KTimestamp start = Kalendar.StringToKTimestamp("yyyy-MM-dd", mv.getStartdate());
		KTimestamp end = Kalendar.StringToKTimestamp("yyyy-MM-dd", mv.getEnddate());
		return posbatchDao.findByCustAndDateForPage(fromIndex,toIndex,compid,custcode,start,Kalendar.getKTimestampAfterDays(end, 1));
	}

	public int findFullSizeByCustAndDate(IncidentalMV mv, int compid) {
		String custcode = mv.getCustcode();
		KTimestamp start = Kalendar.StringToKTimestamp("yyyy-MM-dd", mv.getStartdate());
		KTimestamp end = Kalendar.StringToKTimestamp("yyyy-MM-dd", mv.getEnddate());
		return posbatchDao.findFullSizeByCustAndDate(compid, custcode, start, Kalendar.getKTimestampAfterDays(end, 1));
	}

3.3)Dao類


	public List<Posbatch> findByCustAndDateForPage(int fromIndex,int toIndex,int compid,String custcode, KTimestamp start,
			KTimestamp end) {
		StringBuffer buff = new StringBuffer();
		buff.append("select p from Posbatch p left join fetch p.customer c left join fetch p.wicustomer w left join fetch p.createPerson cp " +
				"where p.compid = ? and p.ctime >= ? and p.ctime<? ");
		buff.append("  order by p.batchnum desc");
		return super.find(buff.toString(), fromIndex, toIndex, compid,start,end);
	}
	
	public int findFullSizeByCustAndDate(int compid,String custcode, KTimestamp start,
			KTimestamp end) {
		StringBuffer buff = new StringBuffer();
		buff.append("select count(*) from Posbatch p " +
				"where p.compid = ? and p.ctime >= ? and p.ctime<? ");
		buff.append(custcode!=null && !custcode.equals("") ? " and p.custcode = ?" : "");
		buff.append("  order by p.batchnum desc");
		return super.findFullSize(buff.toString(),compid,start,end);
	}

此Dao用了Hibernate 的 left join fetch 的方式,因此直接注入Posbatch的關聯對象,便於displaytag的顯示。

另外,此Dao繼承了自己的BaseHibernateDAO,findFullSize()以及find()方法的代碼如下:

	public List<T> find(String hql ,int fromIndex,int toIndex, Object... params){
		Query query = getSession().createQuery(hql);
		for(int i = 0 , len = params.length ; i < len ; i++){
			query.setParameter(i , params[i]);
		}
		query.setFirstResult(fromIndex);
		query.setMaxResults(toIndex - fromIndex);
		return query.list();
	}
	
	public int findFullSize(String hql,Object... params){
		Query query = getSession().createQuery(hql);
		for(int i = 0 , len = params.length ; i < len ; i++){
			query.setParameter(i , params[i]);
		}
		return ((Long)query.list().get(0)).intValue();
	}

3.4) 頁面顯示(JSP)


<display:table id="pagedatas" name="pagedatas" export="false" sort="external" class="dispaytag" 
				 requestURI="queryIncidental"  decorator="com.whyonly.center.pos.mv.PosbatchWrapper"
				>
				<display:column property="batchnum" paramId="batchnum" paramProperty="batchnum"  href="incidental" titleKey="centerowl.posinvoicing.searchtran2" />
				<display:column property="custname" titleKey="centerowl.posinvoicing.searchtran3" />
				<display:column property="ctime"	titleKey="centerowl.posinvoicing.searchtran4" />
				<display:column property="createPerson.name" titleKey="centerowl.posinvoicing.searchtran5" />	
		</display:table>

此處用了一個包裝器,用於顯示日期。如果不需要對數據進行特殊的處理,直接忽略他。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章