天天看點

功能強大的 eXtreme Table 使用

eXtreme Table 說明 

eXtreme Table 是ExtremeCompontents(http://extremecomponents.org或http://sourceforge.net/projects/extremecomp/)中一個功能強大而又容易配置、擴充、自定義的Table控件,其功能包括分頁、排序、過濾、導出Excel、pdf和彙總等。 

擴充eXtreme Table:extremetable-ext.jar是我們自己編寫的eXtreme Table擴充包,裡面的類繼承了原eXtreme Table中的類,并根據我們自己的需要進行了修改和擴充。主要擴充内容包括:顯示分頁頁号、CSV導出表頭等。其樣子類似這樣: 

功能強大的 eXtreme Table 使用

基本配置: 

1)首先下載下傳發行包 http://sourceforge.net/projects/extremecomp; 

2)将包内的extremecomponents.jar 檔案拷貝到項目的 WEB-INF/lib 目錄中 

3)将 images 檔案夾拷貝到 webroot目錄中 

4)将 extremecomponents.css 拷貝到 webroot/css目錄中 

5)将eXtreme Table擴充包extremetable-ext.jar拷貝到項目的 WEB-INF/lib 目錄中 

6)eXtremeTable支援在properties檔案裡友善的統一配置豐富的全局屬性,可以在/source/org/extremecomponents/table/core目錄找到extremetable.properties檔案,可以把它複制到src/裡面并進行修改,也可以在src/裡建立一個extremetable.properties檔案,在裡面隻寫需要修改的屬性,其他屬性會自動去jar包中的extremetable.properties檔案擷取。 

還要在web.xml中加上: 

<context-param>	
	<param-name>extremecomponentsPreferencesLocation</param-name>
        <param-value>/extremetable.properties</param-value>	
</context-param>	
<filter>			
	<filter-name>eXtremeExport</filter-name>		
	<filter-class>org.extremecomponents.table.filter.ExportFilter</filter-class>		
</filter>			
<filter-mapping>			
	<filter-name>eXtremeExport</filter-name>		
	<url-pattern>/*</url-pattern>		
</filter-mapping>
           

本項目用到的一些extremetable.properties配置:

table.filterable=false	 不允許過濾 
table.sortable=false	 不允許排序 
table.imagePath=/images/table/*.gif	 圖檔路徑	
table.locale=ja_JP	 使用日語	

table.view.html=org.extremecomponents.table.view.UserCompactView	 使用extremetable-ext中的html視圖類 
export.view.csv=org.extremecomponents.table.view.UserCsvView	 使用extremetable-ext中的CSV視圖類 

row.highlightRow=true	 滑鼠經過時高亮顯示行	

column.format.date=yyyy-MM-dd HH:mm:ss	 當列設定為cell="date"時采用的顯示格式	
column.format.currency=###,###,###,###,#00.00	 當列設定為cell="currency"時采用的顯示格式	

table.pageDisplayed=7	 在頁号選擇中顯示7個頁号	 (如圖中1所示位置)	
table.rowsDisplayed=20	 表格每頁顯示20行
           

基本原理和流程: 

1、首先,從action中按指定的每頁n行擷取第一頁的資料,即擷取前n個資料。 

2、Action将資料發給JSP頁面,由eXtremeTable的<ec:table>标簽顯示出第一頁。 

3、JSP中的<ec:table>本質上是一個form,在選擇其他頁時,eXtremeTable将把上次傳入的參數加上要顯示的頁号等參數作為該form的參數,把該form送出給指定的action。 

4、Action将按照傳入的上次檢索條件和本次的頁号等參數重新擷取一遍要顯示的資料,然後再發給JSP中的<ec:table>。每次隻取得一頁顯示需要的結果集,不擷取多餘的資料,進而減輕了資料庫的負荷。 

使用Limit特性: 

  預設的情況下eXtremeTable取得所有的結果集然後處理Beans集合,這樣的好處是你可以随意進行排序、過濾和分頁操作。你隻需要組裝Beans集合并讓eXtremeTable知道如何引用它。這樣的操作對于小到中等資料量的結果集非常有效,但結果集很大時這将非常糟糕。為了提高性能,正如前面基本原理和流程所描述的,我們希望每次隻取得一頁顯示需要的結果集,不擷取多餘的資料,即資料庫端分頁的方案。為此我們使用eXtremeTable的Limit特性。 

  Limit這個名字來自MySQL的limit指令,Limit接口的目的就是如何對表的結果集進行limit處理。Limit實作知道當排序、過濾、分頁、導出時,使用者如何與表互相作用。有了這些資訊你将能夠使用可能是最有效的方式顯示正确的過濾、排序、分頁後的請求頁面。 

  使用Limit時,eXtremeTable會使用Limit對象向Action傳遞PageNo,PageSize,OrderBy等分頁資訊。而服務端将向EC傳回總記錄數和目前頁的内容。

基本用法:

下面以一個簡單的例子說明最基本的用法:

1) JSP中:

  一個簡單的eXtreme Table類似于這個樣子:

<ec:table items="operators" var="operator"	
		action="${pageContext.request.contextPath}/sample.do"
		retrieveRowsCallback="limit" sortRowsCallback="limit" filterRowsCallback="limit"
		filterable="false" sortable="false" showExports="true"
		autoIncludeParameters="${empty param.autoInc?true:false}">			
		<ec:exportCsv fileName="DepositHistory.csv" tooltip="CSV Download" />			
		<ec:row>			
			<ec:column property="csLastName" title="名前" />		
			<ec:column property="csId" title="CS_ID" />		
			<ec:column property="csGroupId" title="権限グループ" />		
			<ec:column property="updateDate" cell="date" title="更新日付" />		
		</ec:row>			
	</ec:table>
           

        該表格從集合operators中擷取每行的元素,指派給變量operator,用作每行處理的資料。

        下面說明各項屬性:

        <ec:table>标簽:

items="operators" 按page、request、session和application範圍的順序搜尋并周遊集合operators,從中疊代擷取資料 

var="operator" 把每次從集合operators中取出的單個元素指派給名為operator的bean,存放在page範圍中

action="${pageContext.request.contextPath}/sample.do"指定處理此表單的Action 

retrieveRowsCallback="limit" 指定檢索Callback使用LimitCallback。為了使用Limit特性,eXtremeTable需要使用limit特定的RetrieveRowsCallback

sortRowsCallback="limit" 指定排序Callback使用LimitCallback。為了使用Limit特性,eXtremeTable需要使用limit特定的SortRowsCallback

filterRowsCallback="limit" 指定過濾Callback使用LimitCallback。為了使用Limit特性,eXtremeTable需要使用limit特定的FilterRowsCallback

filterable="false" 設定可否過濾(因為extremetable.properties已經進行了設定,是以本例中此處其實不用設定此屬性)

sortable="false" 設定可否排序(因為extremetable.properties已經進行了設定,是以本例中此處其實不用設定此屬性)

showExports="true" 設定是否顯示導出功能 (預設為true,是以本例中其實可以不寫此項)

autoIncludeParameters="${empty param.autoInc?true:false}"設定是否包含參數,設定為true時,它會把你上次傳過來的參數自動生成為ec form的hidden input, 這好處是在查詢的時候,使每次翻頁的查詢參數都是相同的。 

注:其中,autoIncludeParameters之是以設定成${empty param.autoInc?true:false},是為了更靈活地控制是否包含上次傳過來的參數——當你不希望它包含上次傳過來的參數時,隻要在傳過來的參數中加上一條autoInc=false。比方說,你在ec form中提供了一列checkbox控件用來指定要删除的記錄,如果你隻是簡單地把autoIncludeParameters設定成了true,就會帶來一個問題:如果第一次删除了N18, 等二次删除N9的時候,因為N18被auto include進ec form作為參數了,是以會同時删除 N18和N9。而N18此時已經不存在了,于是就會導緻執行第二次删除的時候失敗。解決辦法就是進行删除操作的時候加多一個參數autoInc=false,并且在<ec:table>中設定autoIncludeParameters="${empty param.autoInc?true:false}",則删除時就不會把參數帶到下一次了。

        <ec:exportCsv>标簽:提供CSV導出功能,可以把表格中的資料導出

fileName 設定導出的目标檔案名

tooltip 設定滑鼠懸浮時顯示的提示文字

其他的導出标簽還有:

<ec:exportXls> xls導出功能 

<ec:exportPdf> pdf導出功能 

        其中的屬性與<ec:exportCsv>标簽相同。

        <ec:row>标簽:<ec:row>和</ec:row>括來的内容就是每行中顯示的内容

        <ec:column>标簽:設定行中的每個列,即單元格

property="updateDate" 從page範圍中取得名為operator的bean,并得到它對應的updateDate屬性值。如果你正使用 Beans集合請确認具有對應的getter方法;如果使用Maps集合則不需要任何别的動作, eXtremeTable能夠通過屬性名從Map中得到對應的值。 

cell="date" 使用date格式,即extremetable.properties中設定的column.format.date 

title="更新日付" 設定表頭,即列标題 

其他常用屬性:

alias alias(别名)屬性用來唯一地辨別這列。當同樣的屬性被多列使用時用來唯一地辨別一列。 

viewsAllowed viewsAllowed屬性指定類允許使用的視圖。視圖包括:html、pdf、xls、csv,以及任何定制的視圖。 如果你指定一個或幾個視圖,那麼列僅能使用這些指定的視圖。例如:你指定viewsAllowed="pdf",這意味着這列隻允許PDF導出,而不能進行其他格式的導出或html視圖。 

viewsDenied viewsDenied屬性指定類不允許使用的視圖。視圖包括:html、pdf、xls、csv,以及任何定制的視圖。 如果你指定一個或幾個視圖,那麼列僅這些指定的視圖不能被使用。例如:你指定viewsDenied="html",這意味着這列不允許使用html試圖,但能進行任何形式的導出。 

2) Action中:

  前面JSP中已經指明了使用Limit特性。下面在Action中也需要增加一些關于Limit的語句。

  首先需要建立一個Limit。

  本項目中已經把提供了現成Limit的擷取方法,位于cn.bestwiz.jhf.admin.common.page.ExtremeTablePage方法中。

  一般用這麼一條語句即可獲得所需的Limit對象:Limit limit = ExtremeTablePage.getLimit(request);

  本例中的相關Action語句如下:

SampleService sampleService = new SampleService();		
		//ExtremeTable分頁
		Limit limit = ExtremeTablePage.getLimit(request);  //擷取得所需的Limit對象
		Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed());  //向Service方法傳入要顯示的頁号limit.getPage()和每頁的行數limit.getCurrentRowsDisplayed(),以實作資料庫端分頁查詢
		//傳回ExtremeTable分頁結果
		request.setAttribute("operators", etpage.getResult());  //把要顯示的結果集etpage.getResult()傳給JSP,其中的operators就是JSP的<ec:table>标簽中items="operators"屬性定義的變量名
		request.setAttribute("totalRows", etpage.getTotalCount());  //把總記錄數(即總行數)etpage.getTotalCount()傳給JSP,其中totalRows是eXtremeTable内定的總行數的變量名,不可随意更改。
           

        其中,Page是本項目中自定義的一個類,是為了友善分頁處理,它把分頁所需的各項參數都封裝到了一個類裡,使得用起來更加友善。

3) Service中:

  從前面Action部分的

Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed());
           

        我們已經看到,對應的Service方法需要接受兩個傳入的參數:要顯示的頁号、每頁的行數。是以本例中對應的Service方法應該是類似這樣的:

public Page getOperatorList(int pageNo, int pageSize) throws ServiceException {		
		Page page = null;	
		……	
		try {	
			DbSessionFactory.beginTransaction(DbSessionFactory.INFO);
			……
			SampleDao sampleDao = new SampleDao();
			page = sampleDao.getOperatorList(pageNo, pageSize, null);
			……
			DbSessionFactory.commitTransaction(DbSessionFactory.INFO);
		} catch ……	
		……	
		return page;	
	}
           

        其中,pageNo是要顯示的頁号、pageSize是每頁的行數,在Service中隻要把傳入的這兩個參數忠實地傳給Dao方法就行了,不必也不應進行任何處理。

  總的來說,Service中的變化一共隻有三處:

1、傳回值為Page類型

2、傳入的參數多了int pageNo, int pageSize兩項

3、在調用Dao方法時,要把pageNo和pageSize兩個參數傳過去

  除此之外,不用做任何其他改變。

4) Dao中:

  從前面Service部分的

page = sampleDao.getOperatorList(pageNo, pageSize, null);
           

        我們已經看到,對應的Dao方法需要接受兩個傳入的參數:要顯示的頁号pageNo、每頁的行數pageSize。是以本例中對應的Dao方法應該是類似這樣的:

public class SampleDao extends BaseHibernateDao {  //因為要用到分頁查詢,是以必須繼承自BaseHibernateDao	
		public SampleDao(){
			this.setSession(DbSessionFactory.infoSession());  //設定要使用的資料庫	
		}		
		……		
		public Page getOperatorList(int pageNo, int pageSize, Object[] args){ //其中Object[] args是參數數組,用于往hql語句中傳參		
			……	
			String hql = "from JhfCsOperator";  //建構一個HQL語句	
			……	
			try {	
				……
				Page page = pagedQuery(hql, pageNo, pageSize, args);  //進行分頁查詢。
				……
			} catch ……	
			……	
			return page;	
		}		
		……		
	}
           

        其中pagedQuery方法是BaseHibernateDao中定義的方法,用于分頁查詢。該方法接受HQL語句、頁号、每頁大小以及傳入hql語句的參數數組這四個參數,執行相應的查詢,然後傳回Page對象。 至此,本例就完成了。

更複雜的應用:

1) 設定初始每頁行數:

  預設情況下,初始每頁行數就是extremetable.properties中的table.rowsDisplayed屬性值。

  如果想要自定義某個表的初始每頁行數(假設為10),需要如下操作: 

1、JSP中: 

在<ec:table>标簽中設定屬性 

rowsDisplayed="10" 

這樣在JSP中顯示時就将以10作為初始的每頁行數來顯示。 

2、Action中: 

因為運作時的流程是先到Action,然後再轉到JSP,是以當第一次進入Action時,并不能得到JSP中設定的任何參數,是以上一條中設定的rowsDisplayed無法影響到Action第一次的查詢動作。以本例來說,雖然在JSP中設定了rowsDisplayed="10",但是Action在第一次擷取結果集時仍将按照extremetable.properties中設定的預設20行來查詢,雖然在JSP頁面中能夠按照10行來顯示,但剩下的10條資料就成了備援資料了。而如果JSP中設定了rowsDisplayed="30",Action在第一次擷取結果集時仍将隻查詢20行,這樣顯示的時候就會出問題了。

是以必須在Action中設定初始每頁行數。 

為此,隻要把上面的 

Limit limit = ExtremeTablePage.getLimit(request);
           

改成

Limit limit = ExtremeTablePage.getLimit(request, 10);  //其中10就是初始每頁行數
           

即可。其他部分都不需要修改,Service和Dao也不需要修改。

另外,為了便于以後維護,建議僅在一個地方定義此參數,具體做法可以類似下面這樣(僅供參考):

Action中:

int pageSize = 10;  //以後要改的話隻須改這一個地方
Limit limit = ExtremeTablePage.getLimit(request, pageSize);
request.setAttribute("pageSize", pageSize);
           

JSP的<ec:table>标簽中:

rowsDisplayed="${pageSize}" 

2) 在同一頁面中使用多個eXtremeTable

  要在同一JSP頁面中互不幹擾地使用兩個或多個不同的eXtremeTable,必須進行一些特别的設定:

1、JSP中:

在每個<ec:table>标簽中設定屬性 tableId ,為每個表格設定一個ID,例如:

tableId="table1"

這個ID将在其他各項操作中唯一地辨別這個表。

2、Action中:

Action中需要把前面示例中的相關各句如下修改:

SampleService sampleService = new SampleService();
			//ExtremeTable分頁
			Limit limit = ExtremeTablePage.getLimit(request, "table1");  //指明對應的tableId
			Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed());  //這句不變
			//傳回ExtremeTable分頁結果
			request.setAttribute("operators", etpage.getResult());  //這句不變
			request.setAttribute("table1_totalRows", etpage.getTotalCount());  //把屬性名由原來的 totalRows 改成 tableId + "totalRows"
           

Service和Dao都不需要修改。

這樣,隻要給不同的表格設定不同的tableId,就可以互不幹擾地使用了。

注:ExtremeTablePage.getLimit方法還有一個形式:ExtremeTablePage.getLimit(HttpServletRequest request, String tableId, int defautPageSize) ,可以同時傳入這三個參數。

3) 把eXtremeTable嵌套在其他form中

  有時需要把eXtremeTable嵌入到其他form中,作為其他form的一部分來使用和送出。但是預設情況下eXtremeTable本身就是一個form(就是說<ec:table>标簽最終會生成<form>标簽),是以不能直接嵌套。如果你想在表體中包含一些定制的form元素, 或者想将eXtremeTable嵌入到另外的form中,那麼你就要使用表标簽的form屬性用來參照最近的form。

  例如,如果在<ec:table>标簽中設定了屬性 form="form1"

  那麼<ec:table>将不再生成<form></form>标簽,隻生成表中的其他内容,這樣隻要把eXtremeTable放在name="form1"的form中,eXtremeTable中的所有内容都将作為form1的一部分來顯示和送出。

  在Struts架構中,<html:form>标簽生成的form,其name值為其action定義的name。

  例如,如果struts-config.xml中定義了

<action path="/currencypair" name="currencyPairForm"		
			validate="false" scope="request"
			type="cn.bestwiz.jhf.admin.system.action.CurrencyPairAction">
           

        那麼JSP中 

<html:form action="currencypair.do"> 
           

最終生成的form的name就等于currencyPairForm。如果要把eXtremeTable嵌套到該form中,就要在<ec:table>中設定form = "currencyPairForm",并把整個<ec:table> </ec:table>塊放到<html:form action="currencypair.do"> </html:form>塊内。

本文排版稍有改動,便于查閱,原文位址:http://www.iteye.com/topic/832612#

功能強大的 eXtreme Table 使用 http://blog.csdn.net/hobbypei/article/details/6722488

附:

相關教程:https://code.google.com/p/extremetable/wiki/Tutorials

eXtremeComponents參考文檔 http://www.blogjava.net/lucky/articles/33380.html