-
Servlet 2.3或更高版本
-
JDK 1.3.1或更高版本
最小的Jars要求:
-
commons-beanutils 1.6
-
commons-collections 3.0
-
commons-lang 2.0
-
commons-logging 1.0.4
-
standard 1.0.2
PDF導(dǎo)出需要的Jars:
-
minimum jars (above)
-
avalon-framework 4.0
-
batik 1.5-fop-0.20-5
-
fop 0.20.5
-
xalan 2.5.1
-
xercesImpl 2.6.1
-
xml-apis 2.0.2
XLS導(dǎo)出需要的Jars:
-
minimum jars (above)
-
poi-2.5.1.jar
從sourceforge 下載發(fā)行包。(http://sourceforge.net/projects/extremecomp/)
在壓縮文件里你能找到開始使用需要的所有東西:
將extremecomponents.jar文件拷貝到你的工程的/WEB-INF/lib目錄下。
處理TLD文件有兩種方式。 你可以把extremecomponents.tld文件放到WEB-INF目錄下的任何地方。 不過,為了便于管理,我喜歡把我的TLD文件都放到/WEB-INF/tld目錄下。你需要根據(jù)你的extremecomponents.tld 文件的位置來修改/WEB-INF/web.xml文件的標(biāo)簽映射。
<taglib>
<taglib-uri>/tld/extremecomponents</taglib-uri>
<taglib-location>/WEB-INF/tld/extremecomponents.tld</taglib-location>
</taglib>
隨后,你需要向下面一樣在你的JSP里把eXtremeTable包含進(jìn)來:
<%@ taglib uri="/tld/extremecomponents" prefix="ec" %>
如果你的servlet容器支持JSP 1.2 (或更高版本),它將能夠自動(dòng)發(fā)現(xiàn)TLD文件,那么你什么也不需要做。 當(dāng)extremecomponents.jar被容器加載的時(shí)候,在它的META-INF目錄下的extremecomponents.tld文件將被找到。 這時(shí),你需要向下面一樣在你的JSP里把eXtremeTable包含進(jìn)來:
<%@ taglib uri="http://www.extremecomponents.org" prefix="ec" %>
為了使用eXtremeTable樣式,從styles目錄拷貝extremecomponents.css到你存放.css腳本的地方。 當(dāng)然在JSP頁面里,你需要提供一個(gè)到CSS的鏈接。就像我將我的樣式表放在/styles目錄下。
<%@ taglib uri="/tld/c" prefix="c" %>
<link rel="stylesheet" type="text/css" href="<c:url value="/styles/extremecomponents.css"/>">
為了使導(dǎo)出功能有效,你需要設(shè)置導(dǎo)出過濾器。這是一個(gè)僅用于導(dǎo)出功能的可選配置。
如下所示在/WEB-INF/web.xml里配置過濾器:
<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>
過濾器還有一個(gè)可選的初始化參數(shù),用于決定什么時(shí)候生成報(bào)頭(headers)。我發(fā)現(xiàn)大多數(shù)的servlet容器 傾向于在調(diào)用過濾器的doFilter()方法后才設(shè)置響應(yīng)報(bào)頭(response headers)。然而,一些servlet容器只有在 調(diào)用過濾器的doFilter()方法前設(shè)置響應(yīng)報(bào)頭,過濾器才能正常工作。默認(rèn)的方法是調(diào)用過濾器的doFilter()方法后 設(shè)置響應(yīng)報(bào)頭,你可以通過使用responseHeadersSetBeforeDoFilter這個(gè)初始化參數(shù)調(diào)整它。
<filter>
<filter-name>eXtremeExport</filter-name>
<filter-class>org.extremecomponents.table.filter.ExportFilter</filter-class>
<init-param>
<param-name>responseHeadersSetBeforeDoFilter</param-name>
<param-value>true</param-value>
</init-param>
</filter>
如果你使用了Sitemesh,你將需要包含SitemeshPageFilter。SitemeshPageFilter擴(kuò)展了正常的 sitemesh的PageFilter,它使得正在進(jìn)行導(dǎo)出的JSP頁面不被修飾。
如下所示在/WEB-INF/web.xml里配置過濾器:
<filter>
<filter-name>Sitemesh</filter-name>
<filter-class>org.extremecomponents.table.filter.SitemeshPageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
使用發(fā)行包的test.jsp來測試安裝。將test.jsp拷貝到web應(yīng)用的最頂層, 默認(rèn)的圖片文件在 /images/table/子目錄下。為了測試,創(chuàng)建相應(yīng)的目錄并將拷貝所有需要的圖片。所有工作都完成后,你可以在瀏覽 器里運(yùn)行test.jsp了。
提示: 我不提倡在JSP里使用腳本(scriplets),但為了不用使用框架而能進(jìn)行快速測試,在test.jsp 使用腳本是唯一的辦法。
TableTag用來設(shè)定什么被顯示并且如何進(jìn)行顯示。默認(rèn)的eXtremeTable在servlet范圍(按照page,request, session,applicaton的順序)尋找具有名稱和items屬性設(shè)置相同的Beans集合(如前章所述它指Beans和Maps兩種集合)。 表將遍歷所有列,它使用var屬性將當(dāng)前行對應(yīng)的bean從集合傳到page范圍,因此你可以從page范圍中重新得到這些數(shù)據(jù) 進(jìn)行操作。tableId用來唯一標(biāo)識(shí)表,如果在JSP頁面里包含兩個(gè)或兩個(gè)以上的表時(shí)需要設(shè)置它。
President bean定義如下:
public class President implements Serializable {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Beans集合需要被組裝并傳到servlet范圍中。我喜歡使用Spring框架,因此示例將使用Spring框架的 控制器(Controller)。如果你正在使用Struts,它和Action的功能類似。如果你使用別的東西,比如直接使用 servlets,你只需要明白我所做的只是組裝Beans集合并傳到request范圍中。
public class Presidents extends AbstractController {
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response)
throws Exception {
List presidents = new ArrayList();
President president = new President();
president.setFirstName("George");
president.setLastName("Washington");
presidents.add(president);
president = new President();
president.setFirstName("John");
president.setLastName("Adams");
presidents.add(president);
request.setAttribute("presidents", presidents);
return new ModelAndView("/demo/presidents.jsp");
}
現(xiàn)在你可以構(gòu)造表了:
<%@ taglib uri="/tld/extremecomponents" prefix="ec" %>
<ec:table
items="presidents"
var="pres"
imagePath="${pageContext.request.contextPath}/images/*.gif"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:column property="firstName"/>
<ec:column property="lastName"/>
${pres.lastName}
</ec:column>
</ec:table>
從本示例中你應(yīng)該知道我們將名為presidents的Beans集合以presidents為名稱放到request中。 為了使表知道如何找到這個(gè)Beans集合,我們設(shè)置TableTag的items屬性為presidents。同時(shí)我們定義 了兩列:firstName和lastName。firstName列是最普通的用法:我們僅僅想讓這列從當(dāng)前bean中得到相應(yīng) firstName的值;lastName列示另外一種用法:明確取得值。
從一列中明確取得值非常有用,但是你需要理解表是如何構(gòu)造行的。為了構(gòu)造行,表需要對所有行進(jìn)行 rowsDisplayed屬性設(shè)定次數(shù)的迭代。每次迭代都從Beans里取得下一個(gè)bean并使用var屬性設(shè)定的名稱傳入page 范圍。也可以說每次迭代你都訪問的是集合中當(dāng)前行對應(yīng)的bean。
為了顯示圖片需要設(shè)置imagePath屬性:
<ec:table
items="presidents"
var="pres"
imagePath="${pageContext.request.contextPath}/images/*.gif"
>
...
</ec:table>
eXtremeTable將找到一個(gè)目錄下的所有圖片并使用特殊的語法來定義他們是那類圖片。 本示例中所有的圖片都直接保存在web上下文的images目錄下。*.gif使eXtremeTable知道所 有的圖片都是GIF格式的。在我們討論preferences后,你將發(fā)現(xiàn)你可以你可以通過在 extremecomponents.properties文件中設(shè)定這個(gè)屬性,而不用再整個(gè)應(yīng)用的每個(gè)eXtremeTable 中包含它。
3.3. 過濾、排序和動(dòng)作(Action)
eXtremeTable內(nèi)嵌了過濾和排序功能,你只需要決定是否需要使用他們。你要使用的屬性是 filterable和sortable,他們都是布爾值并且默認(rèn)值是true。默認(rèn)的所有特性都有效,你可以按照 需要來關(guān)掉一些特性。比如,如果你不想使用排序或過濾你可以把他們的屬性設(shè)為false。
<ec:table
items="presidents"
var="pres"
imagePath="${pageContext.request.contextPath}/images/*.gif"
action="${pageContext.request.contextPath}/presidents.run"
filterable="false"
sortable="false"
>
...
</ec:table>
如果你仍不確信,你可以來驗(yàn)證他們。首先,設(shè)置filterable和sortable為true,你將看到 eXtremeTable允許你輸入關(guān)鍵詞來過濾結(jié)果集,它也允許你通過在頁頭(header)上滾動(dòng)鼠標(biāo)來排序。 然后,設(shè)置filterable和sortable為fale,你將發(fā)現(xiàn)所有這些特性都不允許使用。
本示例需要指出的是使用action屬性,action被用來告訴eXtremeTable當(dāng)過濾或排序時(shí)如何回 到當(dāng)前的頁面。本例中我通過Spring框架的controller(在這里是presidents.run)來得到Beans集合。 你不需要擔(dān)心傳參問題,eXtremeTable將保存所有的參數(shù)并將它們和過濾器、排序、分頁一起傳遞給 Beans集合。更詳細(xì)的信息請參考ParameterTag。
默認(rèn)地eXtremeTable一頁將顯示15行。你可以通過設(shè)定rowsDisplayed屬性為你想顯示行數(shù)的數(shù) 值來改變它。rowsDisplayed也可以在extremecomponents.properties文件中設(shè)定。(參考Preferences)。
提示:如果你想在一頁中顯示所有行,只需要設(shè)置showPagination為false。
TableTag關(guān)聯(lián)了很多樣式屬性:
<ec:table
cellspacing="0"
cellpadding="0"
border="0"
width="80%"
style=""
styleClass=""
/>
所有這些都是可選的。
表新增了兩個(gè)屬性:state和stateAttr。state屬性參照State接口并能插接如何保存表的狀態(tài)的不同實(shí)現(xiàn)。
State借口如下:
public interface State {
public void saveParameters(TableModel model, Map parameters);
public Map getParameters(TableModel model);
}
state屬性使用預(yù)設(shè)的四種狀態(tài)(default、notifyToDefault、persist和notifyToPersist)之一, 你也可以插接自己的實(shí)現(xiàn)。default狀態(tài)不維持任何狀態(tài);persist狀態(tài)沒有任何參數(shù)傳入,將一直維持表的狀態(tài); notifyToDefault狀態(tài)將一直維持表的狀態(tài)直到你傳入?yún)?shù)告訴它回到default狀態(tài);notifyToPersist狀態(tài) 將一直維持當(dāng)前狀態(tài)直到你傳入?yún)?shù)告訴它維持persisted狀態(tài)。
stateAttr為指定參數(shù)提供了一條途徑,你也可以使用屬性文件在全局范圍內(nèi)指定它。 為了向后兼容,默認(rèn)參數(shù)一直為useSessionFilterSort。
如果你想state按照不同方式工作你只要實(shí)現(xiàn)State接口,然后使用TableTag的state屬性來指定實(shí)現(xiàn)類的 全路徑。
作為一條首要規(guī)則當(dāng)使用state屬性時(shí),需要指定tableId。這是因?yàn)閟tate使用tableId為名保存在session里。 如果tableId不唯一,eXtremeTable將覆蓋另一個(gè)同名的內(nèi)容。tableId默認(rèn)值為ec。
為了保持一致性,所有的顯示特性都命名為showXXXX。他們包括showPagination、showStatusBar、 showTooltips、和showExports。
title屬性將在表的上方顯示標(biāo)題,標(biāo)題的位置根據(jù)使用的視圖不同而不同。當(dāng)前默認(rèn)視圖中標(biāo)題位于表的上方 工具條的左邊。更詳細(xì)的信息請參考View。
你會(huì)發(fā)現(xiàn)還有一些屬性沒有被探討,因?yàn)樗麄儗⒃谄渌绿接憽utoIncludeParameters在ParameterTag里被探討; retrieveRowsCallback,sortRowsCallback和filterRowsCallback在Callbacks里被探討。
大多數(shù)標(biāo)簽包含一系列的固定屬性,這樣那些已經(jīng)實(shí)現(xiàn)的功能能夠被使用。然而,eXtremeTable具有一種更具彈性的架構(gòu), 你可以添加自己的標(biāo)簽屬性實(shí)現(xiàn)更多的定制工作。此外,eXtremeTable提供了非常清晰的鉤子(hooks)允許你得到那些定制的 標(biāo)簽屬性來做一些你需要的工作。
通過addExtendedAttributes()方法將擴(kuò)展屬性包含到eXtremeTable里:
public void addExtendedAttributes(Table table);
如果方法被覆蓋TableTag將調(diào)用它。你需要做的就是擴(kuò)展TableTag,覆蓋addExtendedAttributes()方法,然后添加自己 的屬性到表對象中。一個(gè)定制的TreeTag示例如下:
public class TreeTag extends TableTag {
private String parentAttribute;
private String identifier;
public void setParentAttribute(String parentAttribute) {
this.parentAttribute = parentAttribute;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public void addExtendedAttributes(Table table) {
table.addAttribute(TableConstants.PARENT_ATTRIBUTE, TagUtils.evaluateExpressionAsString("parentAttribute",
parentAttribute, this, pageContext));
table.addAttribute(TableConstants.IDENTIFIER, TagUtils.evaluateExpressionAsString("identifier",
identifier, this, pageContext));
table.setFilterRowsCallback("org.extremecomponents.tree.ProcessTreeRowsCallback");
table.setSortRowsCallback("org.extremecomponents.tree.ProcessTreeRowsCallback");
}
}
現(xiàn)在你添加了屬性值到table對象。
另外,你也可以定制自己的標(biāo)簽和自己的TLD文件。你不需要修改extremecomponents.tld文件。 你能象使用eXtremeTable里的標(biāo)簽一樣使用自己的標(biāo)簽,除了使用你自己標(biāo)簽的參照。假如你的標(biāo)簽參照為mycompany 并且標(biāo)簽為customTable,你可以像下面一樣使用他們:
<mycompany:customTable
items="presidents"
action="${pageContext.request.contextPath}/public/demo/presidents.jsp"
title="Presidents"
>
<ec:row>
<ec:column property="nickName"/>
</ec:row>
</mycompany:customTable>
ColumnTag用來定義表中的列。
示例President Bean:
public class President implements Serializable {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
下例生成firstName和lastName列:
<ec:table
items="presidents"
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
/>
<ec:row>
<ec:column property="firstName"/>
<ec:column property="lastName">
${pres.lastName}
</ec:column>
</ec:row>
</ec:table>
通過對TableTag的討論,已經(jīng)知道列可以通過動(dòng)態(tài)或精確的方式得到他們的值。 firstName列動(dòng)態(tài)地取得相應(yīng)的值,列找到當(dāng)前的bean并調(diào)用相應(yīng)的getFirstName()取得值。 lastName列明確地從當(dāng)前bean取得值,它要求你自己取得相應(yīng)的值。如下例:
<ec:table
items="presidents"
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="lastName">
${pageScope.pres.lastName}
</ec:column>
</ec:row>
</ec:table>
從page范圍中取得名為pres的bean并得到它對應(yīng)的lastName屬性值。如果你正使用 Beans集合請確認(rèn)具有對應(yīng)的getter方法;如果使用Maps集合則不需要任何別的動(dòng)作, eXtremeTable能夠通過屬性名從Map中得到對應(yīng)的值。
提供這種可選取值方法的主要原因是使你能夠?qū)ζ渌愋偷膆tml標(biāo)簽提供動(dòng)作支持,例如顯示 一幅圖片或者通過定義href使該列成為到其它頁的一個(gè)鏈接。
<ec:table
items="presidents"
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="lastName">
<a >${pageScope.pres.lastName}</a>
</ec:column>
</ec:row>
</ec:table>
切記bean中所有的屬性都是可訪問的,因此你甚至可以通過firstName屬性 來顯示下一頁。請注意firstName屬性是如何作為URL字符串傳輸?shù)摹?/p>
<ec:table
items="presidents"
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
/>
<ec:row>
<ec:column property="lastName">
<a >
${pageScope.presidents.lastName}
</a>
</ec:column>
</ec:row>
</ec:table>
我將不再在任何示例中強(qiáng)調(diào)pageScope。JSP標(biāo)簽總是最先在pageScope中尋找任何對像, 因此我們總是能安全地返回正確的bean。
每一列總是被實(shí)現(xiàn)Cell接口的對象修飾,你可以認(rèn)為Cell是一個(gè)為了html顯示或?qū)С龆祷馗袷交档膶ο蟆?發(fā)行包包含的Cell有DisplayCell、DateCell、 NumberCell和RowCountCell。 DisplayCell是僅僅顯示列值的默認(rèn)cell;DateCell使用parse屬性(可選)和format屬性來格式化對應(yīng)的屬性值; NumberCell使用format屬性來格式化對應(yīng)的屬性值;RowCountCell顯示當(dāng)前行。
提示:為了避免混亂并提高靈活性Cell接口已經(jīng)被修改。而且對于區(qū)別 如何處理html和導(dǎo)出顯示值也不是很清晰。以前列值作為html顯示,列的propertyValue作為導(dǎo)出使用。 另外列值和propertyValue已經(jīng)重寫,他們以前在view中是不能被訪問的。
cell現(xiàn)在是singleton并且不再線程安全,改變的原因是為了Cell接口能更簡單地被使用。 init()和destroy()方法作為singleton更靈活但是處于一種混亂的狀態(tài)。
Cell接口如下:
public interface Cell {
/**
* The display that will be used for the exports.
*/
public String getExportDisplay(TableModel model, Column column);
/**
* The html that will be displayed in the table.
*/
public String getHtmlDisplay(TableModel model, Column column);
}
現(xiàn)在得到導(dǎo)出和html顯示存在明顯的區(qū)別。更重要的,需要返回字符串。列值和屬性值不再 需要設(shè)置。
DisplayCell是擴(kuò)展AbstractCell的最簡單的Cell。AbstractCell定義 的虛擬方法getCellValue用來返回cell的值。雖然AbstractCell在一些情況下是有用的, 但更多情況下只需要直接實(shí)現(xiàn)Cell接口。
DisplayCell:
public class DisplayCell extends AbstractCell {
public String getExportDisplay(TableModel model, Column column) {
return column.getPropertyValueAsString();
}
protected String getCellValue(TableModel model, Column column) {
return column.getValueAsString();
}
}
AbstractCell:
public abstract class AbstractCell implements Cell {
public String getExportDisplay(TableModel model, Column column) {
return getCellValue(model, column);
}
public String getHtmlDisplay(TableModel model, Column column) {
HtmlBuilder html = new HtmlBuilder();
CellBuilder.tdStart(html, column);
CellBuilder.tdBody(html, getCellValue(model, column));
CellBuilder.tdEnd(html);
return html.toString();
}
/**
* A convenience method to get the display value.
*/
protected abstract String getCellValue(TableModel model, Column column);
}
現(xiàn)在你應(yīng)該知道Cell是多么簡單。只需通過實(shí)現(xiàn)Cell接口或擴(kuò)展AbstractCell來定制你自己的Cell, 并設(shè)置列標(biāo)簽的Cell屬性為類的全路徑。例如: 如果你定制了一個(gè)名為MyCell的Cell,那么你可以像下面一樣使用它:
<ec:column property="firstName" cell="com.mycompany.cell.MyCell"/>
如果你改變列的數(shù)據(jù),那么過濾或排序可能沒有意義。切記我的意思是如果你人為地改變數(shù)據(jù), 而不是使用樣式對它進(jìn)行包裝或作為<a href>包含。 如果你的定制cell顯示數(shù)據(jù)的樹狀視圖,或者是一幅圖片, 那么過濾和排序等一切邏輯操作都是沒有意義的。
列的filterCell屬性控制過濾器如何顯示,它和cell屬性非常相像并且也是實(shí)現(xiàn)Cell接口。 已經(jīng)定義了兩個(gè)過濾器cells:默認(rèn)的和droplist。默認(rèn)的是一個(gè)輸入框元素,除非你確信你需要使這列可以進(jìn)行過濾, 否則你不需要做任何事。
你可以像下面一樣使用droplist過濾器Cell:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="status" filterCell="droplist"/>
</ec:row>
</ec:table>
filterCell也允許你定義定制的過濾器,所有你必須做的就是實(shí)現(xiàn)Cell接口或者擴(kuò)展AbstractCell, 并設(shè)置列標(biāo)簽的Cell屬性為類的全路徑。例如,如果你定制了一個(gè)名為MyCell的Cell,那么你可以像下面一樣使用它:
<ec:column property="firstName" filterCell="com.mycompany.cell.MyFilterCell"/>
參閱Cell節(jié)了解如何創(chuàng)建你自己定制Cells的更多信息。
headerCell屬性控制headers如何顯示,它和cell屬性非常相像并且也是實(shí)現(xiàn)Cell接口。 默認(rèn)header cell作為文本顯示,包含排序邏輯。
headerCell也允許你定義定制的過濾器,所有你必須做的就是實(shí)現(xiàn)Cell接口或者擴(kuò)展AbstractCell, 并設(shè)置列標(biāo)簽的Cell屬性為類的全路徑。例如,如果你定制了一個(gè)名為MyCell的Cell,那么你可以像下面一樣使用它:
<ec:column property="firstName" headerCell="com.mycompany.cell.MyHeaderCell"/>
參閱Cell節(jié)了解如何創(chuàng)建你自己定制Cells的更多信息。
ColumnTag關(guān)聯(lián)了很多樣式屬性:
<ec:column
width=""
style=""
styleClass=""
headerStyle=""
headerClass=""
filterStyle=""
filterClass=""
/>
所有這些都是可選的。style屬性定義列內(nèi)聯(lián)的樣式;styleClass允許你定義一個(gè)列顯示的css類; headerClass屬性允許你改變header列的css類;filterClass屬性允許你改變filter列的css類。
解析和格式化屬性被用在日期和貨幣的顯示上。
和date交互的工作依賴于你的bean屬性是否是一個(gè)字符串或者是一個(gè)Date對象。 如果是一個(gè)字符串那么你就需要確定parse屬性,parse屬性是按照模板定義來解析一個(gè)字符串為 一個(gè)日期對象。如果bean中的屬性是日期型對象則不需要添加parse屬性。不論如何你都需要設(shè)置format屬性。 format屬性按你提供的模板對值進(jìn)行格式化。
本示例中使用MM/dd/yyyy模板格式化日期型值。因?yàn)閎ean中的born屬性值為字符串,所以我們需要 使用parse屬性來將它轉(zhuǎn)換成日期型數(shù)值。
<ec:column property="born" cell="date" parse="yyyy-MM-dd" format="MM/dd/yyyy"/>
對于貨幣只需要設(shè)置format屬性:
<ec:column property="payroll" cell="currency" format="###,###,##0.00"/>
很多時(shí)候在extremeTable中,你使用同樣的模版來解析和格式化日期和貨幣值。 所以便利的方法是在你自己的extremecomponents.properties文件中定義解析和格式化屬性。 參閱Preferences章了解更多信息。
你可能記得在TableTag中看見過filterable和sortable屬性,ColumnTag中也有相同的屬性。 列的filterable和sortable屬性將覆蓋表的filterable和sortable屬性設(shè)置。當(dāng)你需要除了對表中的一、兩列之外的 所有列進(jìn)行過濾和排序時(shí),十分便利。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="firstName" filterable="false"/>
<ec:column property="lastName" sortable="false"/>
</ec:row>
</ec:table>
列新增了兩個(gè)屬性:calc和calcTitle:
<ec:column property="data" calc="total" calcTitle="Total:" />
calc屬性實(shí)現(xiàn)具有唯一方法的Calc接口:
public interface Calc {
public Number getCalcResult(TableModel model, Column column);
}
它傳入model和column,并返回一個(gè)Number型的值。默認(rèn)的實(shí)現(xiàn)為總計(jì)和平均值。
為了使用定制的Calc,只需要使用ColumnTag的calc屬性來指定實(shí)現(xiàn)Calc接口的實(shí)現(xiàn)類的 全路徑。
Calc為singleton并且不是線程安全的,因此不要定義任何類變量。
viewsAllowed屬性制定類允許使用的視圖。視圖包括:html、pdf、xls、csv,以及任何定制的視圖。 如果你指定一個(gè)或幾個(gè)視圖,那么列僅能使用這些指定的視圖。例如:你指定viewsAllowed="pdf",這意味著 這列只允許PDF導(dǎo)出,而不能進(jìn)行其他格式的導(dǎo)出或html視圖。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="firstName"/>
<ec:column property="lastName" viewsAllowed="pdf"/>
</ec:row>
</ec:table>
viewsDenied屬性制定類不允許使用的視圖。視圖包括:html、pdf、xls、csv,以及任何定制的視圖。 如果你指定一個(gè)或幾個(gè)視圖,那么列僅這些指定的視圖不能被使用。例如:你指定viewsDenied="html",這意味著 這列不允許使用html試圖,但能進(jìn)行任何形式的導(dǎo)出。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
>
<ec:row>
<ec:column property="firstName"/>
<ec:column property="lastName" viewsDenied="html"/>
</ec:row>
</ec:table>
title屬性用來為header設(shè)定一個(gè)描述性的名稱。如果你不定義title那么列將使用屬性名。 如果你不想顯示任何title,你只需要設(shè)置title屬性值為一個(gè)空白(whitespace)。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
title="Presidents"
>
<ec:row>
<ec:column property="firstName"/> //title shows as First Name
<ec:column property="firstName" title="First Name"/> //title shows as First Name
<ec:column property="firstName" title=" "/> //no title shows up
</ec:row>
</ec:table>
大多數(shù)標(biāo)簽包含一系列的固定屬性,這樣那些已經(jīng)實(shí)現(xiàn)的功能能夠被使用。然而,eXtremeTable具有一種更具彈性的架構(gòu), 你可以添加自己的標(biāo)簽屬性實(shí)現(xiàn)更多的定制工作。此外,eXtremeTable提供了非常清晰的鉤子(hooks)允許你得到那些定制的 標(biāo)簽屬性來做一些你需要的工作。
通過addExtendedAttributes()方法將擴(kuò)展屬性包含到eXtremeTable里:
public void addExtendedAttributes(Column column);
如果方法被覆蓋ColumnTag將調(diào)用它。你需要做的就是擴(kuò)展ColumnTag,覆蓋addExtendedAttributes()方法,然后添加自己 的屬性到列對象中。一個(gè)定制的CustomTag示例如下:
public class MyCustomTag extends ColumnTag {
private String customAttributeOne;
public String getCustomAttributeOne() {
return customAttributeOne;
}
public void setCustomAttributeOne(String customAttributeOne) {
this.customAttributeOne = customAttributeOne;
}
public void addExtendedAttributes(Column column) {
column.addAttribute("customAttributeOne", customAttributeOne);
}
}
現(xiàn)在你添加了屬性值到Column對象,現(xiàn)在你可以像下例一樣來定制cell:
public class MyCustomCell implements Cell {
public String getHtmlDisplay(TableModel model, Column column) {
Object customAttributeOne = column.getAttribute("customAttributeOne")
String customAttributeOne = column.getAttributeAsString("customAttributeOne")
}
}
另外,你也可以定制自己的標(biāo)簽和自己的TLD文件。你不需要修改extremecomponents.tld文件。 你能象使用eXtremeTable里的標(biāo)簽一樣使用自己的標(biāo)簽,除了使用你自己標(biāo)簽的參照。假如你的標(biāo)簽參照為mycompany 并且標(biāo)簽為customColumn,你可以像下面一樣使用他們:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/public/demo/presidents.jsp"
title="Presidents"
>
<ec:row>
<mycompany:customColumn
property="hello"
cell="com.mycompany.cell.MyCustomCell"
customAttributeOne="Hello World"/>
</ec:row>
</ec:table>
eXtremeTable具有導(dǎo)出不同格式文件的功能,導(dǎo)出的數(shù)據(jù)為過濾和排序后的所有結(jié)果集, 分頁不會(huì)影響返回的結(jié)果集。換句話說,如果表數(shù)據(jù)分多頁顯示,那么所有頁的數(shù)據(jù)都將被導(dǎo)出。 導(dǎo)出的格式為Microsoft Excel (OpenOffice Calc)、PDF和CSV。
使用ExportXlsTag導(dǎo)出Microsoft Excel (OpenOffice Calc):
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
/>
<ec:exportXls
fileName="presidents.xls"
tooltip="Export Excel"/>
...
</ec:table>
使用ExportPdfTag導(dǎo)出PDF。所有要做的就是指定fileName屬性和一些樣式屬性:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
/>
<ec:exportPdf
fileName="presidents.pdf"
tooltip="Export PDF"
headerColor="blue"
headerBackgroundColor="red"
headerTitle="Presidents"/>
...
</ec:table>
使用ExportCsvTag導(dǎo)出CSV。當(dāng)使用CSV導(dǎo)出是默認(rèn)的分隔符為‘,’(comma)。你可以使用 delimiter屬性來指定為其他的符號(hào)。下面為指定‘|’(pipe)為CSV分隔符的示例:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
/>
<ec:exportCsv
fileName="presidents.txt"
tooltip="Export CSV"
delimiter="|"/>
...
</ec:table>
你可以通過指定view屬性來導(dǎo)出其他文件格式。eXtremeTable視圖實(shí)現(xiàn)View接口并是 可插接的。參閱View章了解更多信息。
大多數(shù)標(biāo)簽包含一系列的固定屬性,這樣那些已經(jīng)實(shí)現(xiàn)的功能能夠被使用。然而,eXtremeTable具有一種更具彈性的架構(gòu), 你可以添加自己的標(biāo)簽屬性實(shí)現(xiàn)更多的定制工作。此外,eXtremeTable提供了非常清晰的鉤子(hooks)允許你得到那些定制的 標(biāo)簽屬性來做一些你需要的工作。
通過addExtendedAttributes()方法將擴(kuò)展屬性包含到eXtremeTable里:
public void addExtendedAttributes(Export export);
如果方法被覆蓋ExportTag將調(diào)用它。你需要做的就是擴(kuò)展ExportTag,覆蓋addExtendedAttributes()方法,然后添加自己 的屬性到導(dǎo)出對象中。
一個(gè)定制的ExportCsvTag示例如下:
public class ExportCsvTag extends ExportTag {
private String delimiter;
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public void addExtendedAttributes(Export export) {
String view = export.getView();
if (StringUtils.isBlank(view)) {
export.setView(TableConstants.VIEW_CSV);
export.setImageName(TableConstants.VIEW_CSV);
}
export.addAttribute(CsvView.DELIMITER, getDelimiter());
}
}
現(xiàn)在你添加了屬性值到Export對象,下面是CsvView實(shí)現(xiàn)的一部分:
public class CsvView implements View {
public void body(TableModel model, Column column) {
Export export = model.getExportHandler().getCurrentExport();
}
}
另外,你也可以定制自己的標(biāo)簽和自己的TLD文件。你不需要修改extremecomponents.tld文件。 你能象使用eXtremeTable里的標(biāo)簽一樣使用自己的標(biāo)簽,除了使用你自己標(biāo)簽的參照。假如你的標(biāo)簽參照為mycompany 并且標(biāo)簽為customExport,你可以像下面一樣使用他們:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/public/demo/presidents.jsp"
title="Presidents"
>
<mycompany:customExport fileName="presidents.txt" delimiter="|"/>
...
</ec:table>
Callbacks被用于重新得到(retrieve)、過濾和排序行數(shù)據(jù)。eXtremeTable為每個(gè)callback提供了一個(gè)定制實(shí)現(xiàn)。 首先,載入所有的元數(shù)據(jù),元數(shù)據(jù)為所有eXtremeTable標(biāo)簽的所有屬性;接著在eXtremeTable的model中調(diào)用 execute方法。eXtremeTable使用execute方法決定如何通過調(diào)用每個(gè)callback的接口來重新得到、過濾和排序行數(shù)據(jù)。 這三個(gè)callback的接口是:RetrieveRowsCallback、FilterRowsCallback和SortRowsCallback。
callbacks為singleton并且不是線程安全的,因此不要定義任何類變量。
8.2. RetrieveRowsCallback
RetrieveRowsCallback的默認(rèn)實(shí)現(xiàn)在servlet范圍內(nèi)尋找具有名稱和TableTag 的items屬性設(shè)置相同的Beans集合。為了使用定制的callback,只要實(shí)現(xiàn)RetrieveRowsCallback接口, 然后使用retrieveRowsCallback屬性來指定實(shí)現(xiàn)類的全路徑:
<ec:table
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
retrieveRowsCallback="com.mycompany.callback.MyCustomCallback"
/>
RetrieveRowsCallback接口如下所示:
public interface RetrieveRowsCallback {
public Collection retrieveRows(TableModel model) throws Exception;
}
只有一個(gè)方法需要實(shí)現(xiàn),傳入TableModel并返回一個(gè)集合,集合為Beans或Maps集合。 通過得到TableModel,就擁有了TableTag的所有元數(shù)據(jù)并能訪問Context。能夠訪問Context非常重要, 這意味著你訪問web容器的任何東西。
FilterRowsCallback的默認(rèn)實(shí)現(xiàn)得到Beans集合,通過實(shí)現(xiàn)jakarta Predicate接口進(jìn)行過濾, 過濾值從eXtremeTable的filter輸入框中取得。為了使用定制的callback,只要實(shí)現(xiàn)FilterRowsCallback接口, 然后使用filterRowsCallback屬性來指定實(shí)現(xiàn)類的全路徑:
<ec:table
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
filterRowsCallback="com.mycompany.callback.MyCustomCallback"
/>
FilterRowsCallback接口如下所示:
public interface FilterRowsCallback {
public Collection filterRows(TableModel model, Collection rows) throws Exception;
}
只有一個(gè)方法需要實(shí)現(xiàn),傳入TableModel并返回一個(gè)集合。你只需像eXtremeTable對 每個(gè)callback的默認(rèn)實(shí)現(xiàn)一樣來定制自己的callback。
SortRowsCallback的默認(rèn)實(shí)現(xiàn)得到Beans集合,使用jakarta BeanComparator進(jìn)行排序, 排序值當(dāng)用戶點(diǎn)擊列頭時(shí)取得。為了使用定制的callback,只要實(shí)現(xiàn)SortRowsCallback接口, 然后使用sortRowsCallback屬性來指定實(shí)現(xiàn)類的全路徑:
<ec:table
var="pres"
action="${pageContext.request.contextPath}/presidents.run"
sortRowsCallback="com.mycompany.callback.MyCustomCallback"
/>
SortRowsCallback接口如下所示:
public interface SortRowsCallback {
public Collection sortRows(TableModel model, Collection rows) throws Exception;
}
只有一個(gè)方法需要實(shí)現(xiàn),傳入TableModel并返回一個(gè)集合。你只需像eXtremeTable對 每個(gè)callback的默認(rèn)實(shí)現(xiàn)一樣來定制自己的callback。
為了替代硬編碼eXtremeTable使用的默認(rèn)屬性值,我在屬性文件中配置所有用到的屬性。 如果你需要覆蓋任何默認(rèn)的設(shè)置,你可以創(chuàng)建自己的extremecomponents.properties文件 并設(shè)置你想改變的值。
為了設(shè)置屬性文件,你應(yīng)該如下例所示在/WEB-INF/web.xml文件中聲明一個(gè)context-param,并 指定你的屬性文件的路徑:
<context-param>
<param-name>extremecomponentsPreferencesLocation</param-name>
<param-value>/org/extremesite/resource/extremecomponents.properties</param-value>
</context-param>
你可以認(rèn)為屬性文件為你提供了一個(gè)對所有的eXtremeTables聲明全局設(shè)置的一個(gè)方法。 創(chuàng)建屬性文件的最大好處就是避免在標(biāo)簽中復(fù)制、粘貼相同的屬性。典型的extremecomponents.properties文件如下所示:
table.imagePath=/extremesite/images/*.gif
table.rowsDisplayed=12
column.parse.date=yyyy-MM-dd
column.format.date=MM/dd/yyyy
column.format.currency=$###,###,##0.00
在屬性文件定義的TableTag使用最多的兩個(gè)屬性是:imagePath和rowsDisplayed。如果你不在屬性文件中聲明 這些屬性,你需要在每個(gè)eXtremeTable中添加他們。典型的表如下所示:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
imagePath="${pageContext.request.contextPath}/images/*.gif"
rowsDisplayed="12"
title="Presidents"
>
...
</ec:table>
如果在屬性文件聲明imagePath和rowsDisplayed,則表如下所示:
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/presidents.run"
title="Presidents"
>
...
</ec:table>
正如你所見,屬性文件避免了重復(fù)編碼。
在屬性文件定義的ColumnTag使用最多的兩個(gè)屬性是:parse和format。如果你不在屬性文件中聲明 這些屬性,你需要在每個(gè)eXtremeTable中添加他們。典型的列使用日期cell如下所示:
<ec:column property="dateOfBirth" cell=”date” parse=”yyyy-MM-dd” format=”MM/dd/yyyy”/>
如果在屬性文件聲明parse和format,則列如下所示:
<ec:column property="dateOfBirth" cell=”date”/>
當(dāng)然你仍然可以定義parse和format屬性來覆蓋全局設(shè)置,但是大多數(shù)工程對于日期使用一致的parse 和format。需要注意屬性文件中parse.date和format.date的聲明語法。
下例為使用貨幣cell的典型列:
<ec:column property="salary" cell=”currency” format=”$###,###,##0.00”/>
如果在屬性文件聲明format,則列如下所示:
<ec:column property="salary" cell=”currency”/>
另外,你可以聲明一個(gè)定制的format并在列中通過使用列的basis來使用它,我把這想象為named屬性。因此如果你的 extremecomponents.properties文件如下所示:
table.format.myCustomDate=yy-MM-dd
那么列可以如下使用定制的format:
<ec:column property="dateOfBirth" cell="date" format=”myCustomDate”>
10.4. Advanced Techniques
使用named屬性是我定義其他不同屬性默認(rèn)值時(shí)經(jīng)常使用的方法。你可能對我 使用cell="date"來指定日期cell、使用cell="currency"來指定貨幣cell或使用view="xls."來指定xls導(dǎo)出感到疑惑。 如果我給你展示extremetable.properties文件的一些片斷,這些就將非常清晰了。 extremetable.properties是eXtremeTable聲明默認(rèn)設(shè)置的屬性文件,你可以通過使用 extremecomponents.properties文件來覆蓋它。
column.cell.date=org.extremecomponents.table.cell.DateCell
column.cell.currency=org.extremecomponents.table.cell.NumberCell
column.filterCell.droplist=org.extremecomponents.table.cell.FilterDroplistCell
table.view.xls=org.extremecomponents.table.view.XlsView
當(dāng)你在列上定義cell="date"時(shí),eXtremeTable尋找到column.cell. 屬性并將你定義的cell屬性值拼接上。 換句話說cell="date"關(guān)聯(lián)到column.cell.date=org.extremecomponents.table.cell.DateCell這條屬性。使用屬性文件 真正強(qiáng)大的地方在于你能夠在extremecomponents.properties文件中聲明一個(gè)定制的cell,并在ColumnTag中通過 名稱來使用它。
再使用一個(gè)實(shí)例來闡明這一點(diǎn),是否記得ColumnTag章Cell節(jié)中如何調(diào)用一個(gè)名為MyCell的定制cell:
<ec:column property="firstName" cell="com.mycompany.cell.MyCell"/>
cell使用的更好方式是在屬性文件中聲明并通過名稱使用它。首先,更新extremecomponents.properties文件:
table.imagePath=/extremesite/images/*.gif
table.rowsDisplayed=12
table.cellspacing=2
column.parse.date=yyyy-MM-dd
column.format.date=MM/dd/yyyy
column.format.currency=$###,###,##0.00
column.cell.myCell=com.mycompany.cell.MyCell
現(xiàn)在可以通過名稱調(diào)用MyCell:
<ec:column property="firstName" cell="myCell"/>
正如你所見的這能幫助保持代碼清潔,并且這些都在一個(gè)地方定義。如果你的定制cell聲明 需要改變你只需要修改屬性文件。
為了設(shè)置資源綁定,你應(yīng)該如下例所示在/WEB-INF/web.xml文件中聲明一個(gè)context-param,并 指定你的資源文件的路徑:
<context-param>
<param-name>extremecomponentsMessagesLocation</param-name>
<param-value>org/extremesite/resource/extremecomponentsResourceBundle</param-value>
</context-param>
本示例中資源文件為extremecomponentsResourceBundle,它可以為任何名或者使用已經(jīng)存在的資源文件。
如果你不指定locale,則它將根據(jù)你的servlet request來決定使用哪個(gè)資源文件。 在eXtremeTable中可以通過使用TableTag的locale屬性來設(shè)置它。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/public/demo/locale.jsp"
title="table.title.president"
locale="de_DE"
>
...
</ec:table>
在這里eXtremeTable將尋找德文資源文件。
eXtremeTable使用一些全局的keys來與用戶交互,包括:狀態(tài)欄的文本信息,Rows Displayed droplist和不同的tooltips。如果你足夠幸運(yùn),eXtremeTable已經(jīng)提供了相應(yīng)的語言支持 的話,那么你什么也不用擔(dān)心。否則的話,你需要申明下列keys:
statusbar.resultsFound={0} results found, displaying {1} to {2}
statusbar.noResultsFound=There were no results found.
toolbar.firstPageTooltip=First Page
toolbar.lastPageTooltip=Last Page
toolbar.prevPageTooltip=Previous Page
toolbar.nextPageTooltip=Next Page
toolbar.filterTooltip=Filter
toolbar.clearTooltip=Clear
toolbar.clearText=Clear
toolbar.firstPageText=First
toolbar.lastPageText=Last
toolbar.nextPageText=Next
toolbar.prevPageText=Prev
toolbar.filterText=Filter
column.headercell.sortTooltip=Sort By
column.calc.total=Total
column.calc.average=Average
現(xiàn)在僅支持英語和德語。如果你使用其他語言的話,并能提供相應(yīng)的翻譯的話我將不勝感激。你可以通過 extremecomponents@gmail.com發(fā)送給我。
譯者注:我已經(jīng)提供了中文和日文的資源文件。
TableTag屬性中能夠使用locale方式指定的是:imagePath和title。
在eXtremeTable中,imagePath屬性有一個(gè)特定的key:table.imagePath。你可以在你的資源文件中 設(shè)置這個(gè)key為特定語言的目錄結(jié)構(gòu)。例如:德文圖片可能放在de文件夾下,那么你可以在相應(yīng)的資源文件中 進(jìn)行如下設(shè)置:
table.imagePath=/extremesite/images/table/de/*.gif
title有一點(diǎn)不同,如果你指定的title屬性值包含dot (.)并且你定義了一個(gè)資源文件,那么 eXtremeTable將尋找匹配的key。例如,如果你像下例一樣在表中指定屬性title="table.title.president":
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/public/demo/locale.jsp"
title="table.title.president"
>
...
</ec:table>
那么eXtremeTable將在屬性文件中尋找匹配的key:
table.title.president=US Präsidenten
ColumnTag屬性中能夠使用locale方式指定的是:format和title。
在eXtremeTable中,format屬性有一個(gè)特定的key:table.fomat.type。參考屬性文件的討論 來了解更多的細(xì)節(jié),他們具有同樣的概念。日期和貨幣的format類型定義可能如下所示:
column.format.date=MM/dd/yyyy
column.format.currency=$###,###,##0.00
title有一點(diǎn)不同,如果你指定的title屬性值包含dot (.)并且你定義了一個(gè)資源文件,那么 eXtremeTable將尋找匹配的key。例如,如果你像下例一樣在列中指定屬性title="table.column.nickName":
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/public/demo/locale.jsp"
title="table.title.president"
>
<ec:row>
<ec:column property="nickName" title="table.column.nickName" />
</ec:row>
</ec:table>
那么eXtremeTable將在屬性文件中尋找匹配的key:
table.column.nickName=Spitzname
默認(rèn)的情況下eXtremeTable取得所有的結(jié)果集然后處理Beans集合,這樣的好處是 你可以隨意進(jìn)行排序、過濾和分頁操作。你只需要組裝Beans集合并讓eXtremeTable知道如何 引用它。這樣的操作對于小到中等數(shù)據(jù)量的結(jié)果集非常有效,當(dāng)結(jié)果集很大時(shí)這將非常糟糕。 這是一個(gè)判斷,但我更喜歡描述如何做出我的技術(shù)決定。如果您認(rèn)為在性能上有問題, 那么最好是使用一個(gè)profiler工具記錄并查看它。有許多開源和商業(yè)的profiler工具可以幫助 你做出最好的判斷。因此,假設(shè)我們發(fā)現(xiàn)了性能上存在問題,需要我們自己來處理分頁。
手動(dòng)處理分頁意味著你一次只想取得一頁顯示需要的結(jié)果集。同時(shí),你需要自己處理排序、過濾和分頁。 下面的討論是基于我假設(shè)你從數(shù)據(jù)庫中取得集合,當(dāng)然同樣的原理能應(yīng)用到任何地方。
這是一個(gè)重要的部分。為了得到較小的結(jié)果集,你可以創(chuàng)建一個(gè)普通的查詢語句,但是limit你得到的結(jié)果集。 在Sybase和SQLServer中你可以使用rowcount命令,在MySql中你可以使用limit命令。 我不知道其他數(shù)據(jù)庫怎么使用,但我確信每個(gè)數(shù)據(jù)庫都有相似的功能。 也就是說當(dāng)用戶瀏覽第一頁是得到第一頁需要的 結(jié)果集,當(dāng)用戶瀏覽下一頁時(shí),再得到下一頁需要的結(jié)果集。
使用Sybase的開發(fā)人員可能會(huì)說:rowcount命令總是從第一條開始,那么當(dāng)我到第二頁時(shí)我也必須 從第一條數(shù)據(jù)開始。 是的,你現(xiàn)在得到的是兩頁的結(jié)果集,而不需要得到所有的結(jié)果集。當(dāng)你到第三頁時(shí),你只需要得到三頁的結(jié)果集。。。。。。 其他數(shù)據(jù)庫比如MySQL,允許你精確地得到你想要的那段數(shù)據(jù),這樣你就可以只得到當(dāng)前頁面顯示需要的結(jié)果集。
為了知道用戶想如何排序和過濾,他們想瀏覽哪一頁,一頁需要顯示幾條結(jié)果,eXtremeTable有一個(gè)使用LimitFactory 創(chuàng)建的名為Limit的簡便接口:
首先你需要通過LimitFactory得到一個(gè)Limit實(shí)例:
Context context = new HttpServletRequestContext(request);
LimitFactory limitFactory = new TableLimitFactory(context, tableId);
Limit limit = new TableLimit(limitFactory);
Limit對象定義了limit結(jié)果集的所有方法。
TableLimitFactory具有另外一個(gè)構(gòu)造函數(shù),如果沒有指定tableId的話默認(rèn)的tableId將為ec。
Context context = new HttpServletRequestContext(request);
LimitFactory limitFactory = new TableLimitFactory(context);
Limit limit = new TableLimit(limitFactory);
當(dāng)你對Limit實(shí)例化時(shí),實(shí)例化對象包含兩個(gè)對象:FilterSet和Sort。
private FilterSet filterSet;
private Sort sort;
FilterSet包含一個(gè)過濾動(dòng)作(Action)和一個(gè)過濾器對象數(shù)組。 動(dòng)作為TableConstants.FILTER_ACTION或TableConstants.CLEAR_ACTION。 一個(gè)過濾器包含一個(gè)property和這個(gè)過濾器的值。
private final String action;
private final Filter[] filters;
Sort對象包含property和sortOrder。sortOrder為 TableConstants.SORT_ASC或TableConstants.SORT_DESC:
private Sort sort;
設(shè)置行屬性:
limit.setRowAttributes(totalRows, DEFAULT_ROWS_DISPLAYED);
下面是設(shè)置行屬性可能用到的信息:
private int rowStart;
private int rowEnd;
private int currentRowsDisplayed;
private int page;
private int totalRows;
每個(gè)變量都有一個(gè)getter方法,我將不深入講解屬性的細(xì)節(jié)。
在你完成所有的定制工作:排序、過濾.....定制的Controller(Spring)或者Action(Struts)或者其他類似的框架后, 另外你需要?jiǎng)?chuàng)建一個(gè)callback,eXtremeTable已經(jīng)提供了一個(gè)名為LimitCallback的實(shí)現(xiàn)。為了使用你只需要設(shè)置表 屬性:retrieveRowsCallback、filterRowsCallback和sortRowsCallback:
<ec:table
items="presidents"
retrieveRowsCallback="limit"
filterRowsCallback="limit"
sortRowsCallback="limit"
action="${pageContext.request.contextPath}/limit.run"
title="Presidents"
>
<ec:row>
<ec:column property="fullName" title="Name"/>
<ec:column property="nickName" />
<ec:column property="term" />
<ec:column property="born" cell="date"/>
<ec:column property="died" cell="date"/>
<ec:column property="career" />
</ec:row>
</ec:table>
使用callback需要做的唯一事情是傳輸集合到request,同時(shí)傳輸totalRows屬性。 totalRows表示總行數(shù),使用PaginationCallback.TOTAL_ROWS靜態(tài)變量將易于維護(hù)。 如果JSP頁面使用了兩個(gè)(以上)eXtremeTable的話你可以利用tableId分別傳輸totalRows。 例如如果tableId名為pres,你可以如下處理:
request.setAttribute("pres", presidents);
request.setAttribute("pres_totalRows", new Integer(""+totalRows));
譯者注:關(guān)于limit使用的更詳細(xì)信息,請參考《Limit指南》。
Chapter 13. AutoGenerateColumns
大多數(shù)情況下你按照你需要的列來設(shè)計(jì)數(shù)據(jù)庫表。但是,有時(shí)候需要運(yùn)行時(shí)動(dòng)態(tài)生成一些列。 為了實(shí)現(xiàn)這點(diǎn),eXtremeTable需要使用ColumnsTag并設(shè)置autoGenerateColumns屬性。
AutoGenerateColumns為singleton并且不是線程安全的,因此不要定義任何類變量。
ColumnsTag只有autoGenerateColumns這一個(gè)屬性。所有你必須做的就是實(shí)現(xiàn)AutoGenerateColumns接口, 并設(shè)置autoGenerateColumns屬性為類的全路徑。
<ec:table
items="presidents"
action="${pageContext.request.contextPath}/autoGenerateColumns.run"
title="Presidents"
>
<ec:columns autoGenerateColumns="org.extremesite.controller.AutoGenerateColumnsImpl"/>
</ec:table>
AutoGenerateColumns接口只有一個(gè)方法:
public void addColumns(TableModel model);
你需要做的就是添加列(columns)到model里。最簡單的示例如下:
public class AutoGenerateColumnsImpl implements AutoGenerateColumns {
public void addColumns(TableModel model) {
Iterator iterator = columnsToAdd().iterator();
while (iterator.hasNext()) {
Map columnToAdd = (Map) iterator.next();
Column column = new Column(model);
column.setProperty((String) columnToAdd.get(PROPERTY));
column.setCell((String) columnToAdd.get(CELL));
model.getColumnHandler().addAutoGenerateColumn(column);
}
}
}
示例中columnsToAdd()方法簡單返回一個(gè)包含生成列(columns)需要的所有信息的集合。 作為參考,下面是我在eXtremeComponents網(wǎng)站實(shí)例中使用的columnsToAdd()方法:
private List columnsToAdd() {
List columns = new ArrayList();
columns.add(columnToAdd("fullName", "display"));
columns.add(columnToAdd("nickName", "display"));
columns.add(columnToAdd("term", "display"));
columns.add(columnToAdd("born", "date"));
columns.add(columnToAdd("died", "date"));
columns.add(columnToAdd("career", "display"));
return columns;
}
private Map columnToAdd(String property, String cell) {
Map column = new HashMap();
column.put(Column.PROPERTY, property);
column.put(Column.CELL, cell);
return column;
}
另外,我想聲明的是只創(chuàng)建列一次。eXtremeTable為了高效,不會(huì)每行創(chuàng)建一列, 而是通過循環(huán)持續(xù)插入新列值到已經(jīng)存在的列。記住TableModel能夠訪問Context,因此 你可以在Controller(Spring)或Action(Struts)中定義樣式(look like)并通過request傳輸集合。 所以你得AutoGenerateColumns實(shí)現(xiàn)只需要構(gòu)建列(Columns)并添加到model.columns里。