论坛首页 Java企业应用论坛

扔掉T5复杂的Grid组件,打造自己灵活的支持分页排序组件。

浏览 4419 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-01-03  
Grid算是比较T5中较复杂的一个组件,我也有篇介绍Grid怎么使用的文章。http://www.iteye.com/topic/114754   但是如果我们平时需要些比较灵活的布局。 Grid组件用起来就比较别扭了。 

下面我介绍下使用Loop组件实现一个灵活但是又不缺乏分页,排序功能的Grid组件的实现。

首先我们全局看下页面上是要怎样写的。

        <table>
        	<tr>
        		<td><a t:type="OrderColumn" orderProperty="country" paging="paging">Country</a> </td>
        		<td><a t:type="OrderColumn" orderProperty="language" paging="paging">Language</a> </td>
        	</tr>
        	<tr t:type="Loop" source="items" value="item">
        		<td>${item.country}</td>
        		<td>${item.language}</td>
        	</tr>
        	<tr>
        		<td colspan="2"><div t:type="PageNavigation" paging="paging" useAll="false"></div></td>
        	</tr>
        </table>


是不是比较简单。 你可以单独输出Table的头部和body部分。 这里使用了2个组件一个OrderColumn,一个是PageNavigation。 这两个组件公用了一个paging对象, 这个paging对象其实提供了对分页,和当前排序字段的支持。 下面看看page class的内容。

package com.iteye.com.dengyin000.tapestry.quickstart.pages;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.tapestry.annotations.Persist;

import com.iteye.com.dengyin000.tapestry.quickstart.utils.Paging;

/**
 * Start page of application quickstart.
 */
public class Start
{
	@Persist("session")
	private Paging paging;
	
	private Locale item;
	
	public Locale getItem() {
		return item;
	}

	public Date getCurrentTime() 
	{ 
		return new Date(); 
	}
	
	public Locale[] getAvailableLocales(){
		return Locale.getAvailableLocales();
	}
	
	public void pageLoaded(){
		if (paging == null){
			paging = new Paging("country");
		}
	}
	
	public List<Locale> getItems(){
		Locale[] availableLocales = Locale.getAvailableLocales();
		List<Locale> list = Arrays.asList(availableLocales);
		paging.setItemCount(list.size());
		return list.subList(paging.getFirstResult(), paging.getFirstResult() + paging.getMaxResults());
	}

	public Paging getPaging() {
		return paging;
	}

	public void setPaging(Paging paging) {
		this.paging = paging;
	}

	public void setItem(Locale item) {
		this.item = item;
	}
}



这里我们把paging对象保存在了session里。 然后绑定到OrderColumn和PageNavigation组件中。 请注意getItems方法。 这个是获得你要显示的数据。 这里你要先得到所有的数据的总数然后调用setItemCount方法, 然后你要通过paging中的firstResult maxResult orderProperty order(desc,ase)去获取你要显示的数据。 下面看看paging对象。

package com.iteye.com.dengyin000.tapestry.quickstart.utils;

import java.io.Serializable;
import java.util.List;

public class Paging implements Serializable {

	private static final long serialVersionUID = 4260574632101852340L;

	public static int ROWS_PER_PAGE = 15;

	public static int ALL = -1;

	private int firstResult = 0;

	private int maxResults = ROWS_PER_PAGE;

	/**
	 * One or more property names separated by comma (,). They are later used in
	 * ORDER BY clause.
	 */
	private String orderProperties;

	private boolean orderDescending = false;

	private int pageNo = 0;

	private long itemCount = 0;

	private String alias = null;

	protected boolean recalculateFirst = false; // enabled by setPageNo or
												// setItemCount

	private transient List results;

	public Paging(String orderColumn) {
		setOrderProperties(orderColumn);
	}

	public Paging(String orderColumn, boolean orderDescending) {
		setOrderProperties(orderColumn);
		setOrderDescending(orderDescending);
	}

	public Paging(String orderColumn, int pageNo) {
		setOrderProperties(orderColumn);
		setPageNo(pageNo);
	}

	public Paging(int firstResult, int maxResults, String orderColumn,
			boolean orderDescending) {
		this(firstResult, maxResults, orderColumn, null, orderDescending);
	}

	public Paging(int firstResult, int maxResults, String orderColumn,
			String alias, boolean orderDescending) {
		setFirstResult(firstResult);
		setMaxResults(maxResults);
		setOrderProperties(orderColumn);
		setOrderDescending(orderDescending);
		setAlias(alias);
	}

	public boolean isAll() {
		return pageNo == ALL;
	}

	public int getFirstResult() {
		if (this.recalculateFirst == true) {
			if (pageNo != ALL) {
				if (pageNo < 0) {
					pageNo = 0;
				}
				firstResult = pageNo * maxResults;
				if (firstResult >= itemCount) {
					firstResult = pageNo = 0;
				}
			} else {
				firstResult = 0;
			}
			this.recalculateFirst = false;
		}
		return firstResult;
	}

	public void changeSortColumn(String sortColumn) {
		if (sortColumn != null && sortColumn.equals(getOrderProperties())) {
			setOrderDescending(isOrderDescending() == true ? false : true); // change
																			// order
																			// desc
		} else {
			setOrderDescending(false); // set ascending order
			setOrderProperties(sortColumn);
		}
	}

	public void setFirstResult(int firstResult) {
		this.firstResult = firstResult;
	}

	public int getMaxResults() {
		return maxResults;
	}

	public void setMaxResults(int maxResults) {
		this.maxResults = maxResults;
	}

	public String getOrderProperties() {
		return orderProperties;
	}

	public void setOrderProperties(String sortColumn) {
		this.orderProperties = sortColumn;
	}

	public boolean isOrderDescending() {
		return orderDescending;
	}

	public void setOrderDescending(boolean sortOrder) {
		this.orderDescending = sortOrder;
	}

	public long getItemCount() {
		return itemCount;
	}

	public void setItemCount(long itemCount) {
		this.itemCount = itemCount;
		this.recalculateFirst = true;
	}

	public int getPageNo() {
		return pageNo;
	}

	public void setPageNo(int pageNo) {
		this.pageNo = pageNo;
		this.recalculateFirst = true;
	}

	public String getAlias() {
		return alias;
	}

	public void setAlias(String alias) {
		this.alias = alias;
	}

	public void setResults(List results) {
		this.results = results;
	}

	public List getResults() {
		return results;
	}

	/**
	 * apply order properties to the query string.
	 * @param query
	 * @param pas
	 * @return
	 */
	public static String buildOrderBy(String query, Paging pas) {
	    //FIXME
		if (pas != null && pas.getOrderProperties() != null) {
			StringBuffer orderBy = new StringBuffer();
			/** Oracle 
			int groupindex = query.toLowerCase().indexOf(" group ");
            if(groupindex>0){
                int i = query.toLowerCase().indexOf(" by ",groupindex+1);
                if(i>groupindex && (i-groupindex)<12)return query;
            }
			**/
			int posOrder = query.toLowerCase().indexOf(" order ");
			if (posOrder > 0) {
				int posBy = query.toLowerCase().indexOf(" by ", posOrder - 1);
				if (posBy >= 0) {
					orderBy.append(query.substring(0, posOrder));
				} else
					orderBy.append(new String(query));
			} else {
				orderBy.append(new String(query));
			}
			
			orderBy.append(" order by ");
			String[] orderCols = pas.getOrderProperties().split(",");
			for (int i = 0; i < orderCols.length; i++) {
				if (i > 0) {
					orderBy.append(", ");
				}
				if (pas.getAlias() != null) {
					orderBy.append(pas.getAlias() + ".");
				}
				
				orderBy.append(orderCols[i]);
				
				if (pas.isOrderDescending()) {
					orderBy.append(" desc");
				}
			}
			return orderBy.toString();
		}
		return query;

	}

	/**
	 * 'from User' or 'select name from User' will be changed to 
	 * 'select count(*) from User'
	 * replace select fields with count(*)
	 * @param queryString
	 * @return
	 */
	public static String buildItemCount(String queryString) {
		int posOfFrom = queryString.toLowerCase().indexOf("from ");
		return "select count(*) " + queryString.substring(posOfFrom);
	}
}


ok, 下面贴下OrderColumn, PageNavigation的代码

OrderColumn.tml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<span xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
	<a t:type="ActionLink" t:id="changeOrderLink"  t:context="orderProperty">
		<t:body/><img src="${icon}" class="t-sort-icon" alt="${iconLabel}"/>
	</a>
</span>


OrderColumn.java
package com.iteye.com.dengyin000.tapestry.quickstart.components;

import org.apache.tapestry.Asset;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.annotations.Path;
import org.apache.tapestry.ioc.annotations.Inject;

import com.iteye.com.dengyin000.tapestry.quickstart.utils.Paging;

public class OrderColumn {

	@Parameter(required=true, defaultPrefix="literal")
	private String orderProperty;
	
	@Parameter(required=true)
	private Paging paging;

    @Inject
    @Path("sort-asc.png")
    private Asset _ascendingAsset;

    @Inject
    @Path("sort-desc.png")
    private Asset _descendingAsset;

    @Inject
    @Path("sortable.png")
    private Asset _sortableAsset;	

	public String getOrderProperty() {
		return orderProperty;
	}

	public void setOrderProperty(String orderProperty) {
		this.orderProperty = orderProperty;
	}

	public Paging getPaging() {
		return paging;
	}

	public void setPaging(Paging paging) {
		this.paging = paging;
	}
	
	public void onActionFromChangeOrderLink(String orderProperty){
		paging.changeSortColumn(orderProperty);
	}
	
	public Asset getIcon(){
        if (isActiveSortColumn()) {
        	return getPaging().isOrderDescending() ?  _descendingAsset : _ascendingAsset;
        }

        return _sortableAsset;
    }
	
	private boolean isActiveSortColumn() {
		return orderProperty.equals(getPaging().getOrderProperties());
	}

	public String getIconLabel(){
        String key = isActiveSortColumn() ? ( getPaging().isOrderDescending() ? "descending": "ascending")
                : "sortable";

        return key;
	}
}



PageNavigation.tml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<span t:type="If"  t:test="navigationDisplayed" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
	<table border="0">
	<tr>
	  <td>&nbsp;</td>
	  <td class="navigation">
	  	<span t:type="If" t:test="notUnderAllStatus">
	  		<a t:type="ActionLink" t:id="first" t:context="first" t:disabled="firstDisabled">|&lt;&lt;</a>
	  		&nbsp;
	  		<a t:type="ActionLink" t:id="previous" t:context="previous" t:disabled="previousDisabled">&lt;&lt;</a>
	  		&nbsp;
	  		Page ${currentPage} Of ${pageCount}
	  		<a t:type="ActionLink" t:id="next" t:context="next" t:disabled="nextDisabled">&gt;&gt;</a>
	  		&nbsp;
	  		<a t:type="ActionLink" t:id="last" t:context="last" t:disabled="lastDisabled">&gt;&gt;|</a>
	  		&nbsp;
	  		<span t:type="If" t:test="useAll">
	  			<a t:type="ActionLink" t:context="all" t:disabled="allDisabled">All</a>
	  			<t:parameter name="else">
	  				<a t:type="ActionLink" t:id="pageStatus" t:disabled="prop:notUnderAllStatus">View Paginated</a>
	  			</t:parameter>
	  		</span>
	  	</span>
	  </td>
	</tr>
	</table>
</span>


PageNavigation.java

package
com.iteye.com.dengyin000.tapestry.quickstart.components;

import org.apache.tapestry.annotations.OnEvent;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.annotations.Persist;

import com.iteye.com.dengyin000.tapestry.quickstart.utils.Paging;

public class PageNavigation {

	@Persist
	private boolean underAllStatus;
	@Parameter(required=true)
	private Paging paging;
	
	private Integer num;
	
	@Parameter
	private boolean useAll;

	public boolean isUseAll() {
		return useAll;
	}

	public void setUseAll(boolean useAll) {
		this.useAll = useAll;
	}

	public boolean isUnderAllStatus() {
		return underAllStatus;
	}
	
	public boolean getNotUnderAllStatus(){
		return !underAllStatus;
	}

	public void setUnderAllStatus(boolean underAllStatus) {
		this.underAllStatus = underAllStatus;
	}

	public Paging getPaging() {
		return paging;
	}

	public void setPaging(Paging paging) {
		this.paging = paging;
	}

	public Integer getNum() {
		return num;
	}

	public void setNum(Integer num) {
		this.num = num;
	}
	
	public void onActionFromFirst(Integer newPageNo){
		changePageNo(newPageNo);
	}
	public void onActionFromPrevious(Integer newPageNo){
		changePageNo(newPageNo);
	}
	public void onActionFromNext(Integer newPageNo){
		changePageNo(newPageNo);
	}
	public void onActionFromLast(Integer newPageNo){
		changePageNo(newPageNo);
	}	
	  public void changePageNo(Integer newPageNo) {

		    getPaging().setPageNo(newPageNo == null ? Paging.ALL : newPageNo.intValue());
//		    setPaging(getPaging()); // persist!
		    
		    if (newPageNo == null)
		    	setUnderAllStatus(true);
		  }

		  public Integer[] getAllPageNumbers() {
		    int size = getLast().intValue() + 1;
		    Integer[] allPages = new Integer[size];
		    for (int i = 0; i < size; i++) {
		      allPages[i] = new Integer(i);
		    }
		    return allPages;
		  }

		  public String getPageLabel() {
		    return "" + (getNum().intValue() + 1);
		  }

		  public Integer getFirst() {
		    return new Integer(0);
		  }

		  public Integer getPrevious() {
		    return new Integer(getPaging().getPageNo() - 1);
		  }

		  public Integer getNext() {
		    return new Integer(getPaging().getPageNo() + 1);
		  }

		  public Integer getLast() {
		    int last = (int)Math.ceil((double)getPaging().getItemCount() / getPaging().getMaxResults()) - 1;
		    return new Integer(last);
		  }

		  public Integer getAll() {
		    return null;
		  }

		  public boolean isFirstDisabled() {
		    return getPaging().getPageNo() == 0;
		  }

		  public boolean isPreviousDisabled() {
		    return isFirstDisabled() || getPaging().getPageNo() == Paging.ALL;
		  }

		  public boolean isSelectedPage() {
		    return getPaging().getPageNo() == getNum().intValue();
		  }

		  public boolean isNextDisabled() {
		    return isLastDisabled() || getPaging().getPageNo() == Paging.ALL;
		  }

		  public boolean isLastDisabled() {
		    return getPaging().getPageNo() == getLast().intValue();
		  }

		  public boolean isAllDisabled() {
		    return getPaging().getPageNo() == Paging.ALL || getLast().intValue() == 0;
		  }

		  public boolean isNavigationDisplayed() {
		    return getLast().intValue() > 0;
		  }
		  
		  @OnEvent(component="pageStatus")
		  public void enterPagingStatus(){
			  setUnderAllStatus(false);
			  
			  getPaging().setPageNo(0);
//			  setPaging(getPaging());
		  }
		  
		  public int getCurrentPage(){
			  return paging.getPageNo() + 1;
			  
		  }
		  
		  public int getPageCount(){
			  return getLast() + 1;
		  }
}



Ok,这个对于T4, T3也是一样的。 你只要把OrderColumn 和 PageNavigation 组件改成相应版本下面的组件就行了。 还有就是如果觉得PageNavigation看起来不是很好的话, 你也可以自己做各式各样的PageNavigation,他就只需要Paging这个类。

我把这个打包成了一个Maven项目。 如果你装了WTP的话。
运行mvn eclipse:eclipse -Dwtpversion=1.0 -DdownloadSources=true 然后再import项目到eclipse中就行了。

   发表时间:2008-01-09  
我跑了一下,好像下面的导航显示有问题,数字不对。而且点到最后一页会报错,溢出了吧。。。
0 请登录后投票
   发表时间:2008-05-31  
出错的地方在这儿:
引用
private int maxResults = ROWS_PER_PAGE;

然后dengyin的代码中没有对maxResults < ROWS_PER_PAGE(15)的情况进行判断处理。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics