掌握Tiles 框架 (一)---Tiles入門和Tiles 框架和體系結構
1. Tile 佈局
構建第一個 tile 佈局
如果站點能夠重用相同的佈局(使用 HTML 表格來實現)和影象,而不必重複相同的 HTML 程式碼,這樣不是很好嗎?
Tile 在為站點建立共同的外觀方面特別出色。話雖這樣說,許多開發人員並沒有認識到 Tiles 在建立用 JSP 實現的可重用元件方面同樣也很出色。
如果您發現自己在多個頁面上重複相同的 HTML 程式碼,就可考慮對那些頁面使用 tile 佈局。類似地,如果在不同頁面上的不同地方使用相同的 HTML 或 JSP 標籤,這種情形也很適合使用 tile 來建立小型可視元件。
作為 Tiles 框架的一個例子,下面將重構一個簡單的股票報價應用程式來利用 tile 佈局,如圖 3 所示。
示例應用程式
這個簡單的示例應用程式主要包含一個股票報價頁面,它具有一個接受單個引數(即股票程式碼)的表單(index.jsp
)。 另一個頁面顯示股票報價的值(quote.jsp
)。
研究一下下面這兩個程式碼清單。您將重構它們以使用各種各樣的 tile 佈局。
index.jsp
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><html><head><title>Stock Quote</title></head><body><table width="500" border="0" cellspacing="0" cellpadding="0"><tr><td></td></tr><tr bgcolor="#36566E"><td height="68" width="48%"><div align="left"><img src="images/hp_logo_rickhightower.gif"width="220" height="74"></div></td></tr><tr><td></td></tr></table><html:form action="Lookup"><table width="45%" border="0"><tr><td><bean:message key="app.symbol"/>:</td><td><html:text property="symbol"/></td></tr><tr><td colspan="2" align="center"><html:submit /></td></tr></table></html:form></body></html>
quote.jsp
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><html><head><title>Stock Quote</title></head><body><table width="500" border="0" cellspacing="0" cellpadding="0"><tr><td></td></tr><tr bgcolor="#36566E"><td height="68" width="48%"><div align="left"><img src="images/hp_logo_rickhightower.gif" width="220" height="74"></div></td></tr><tr><td></td></tr><tr><td></td></tr><tr><td></td></tr><tr><td><bean:message key="app.price"/>: <%= request.getAttribute("PRICE") %></td></tr><tr><td></td></tr></table></body></html>
欲學習如何使用 Tiles 框架,您首先必須編寫一個 tile 佈局,然後重構上述兩個例子頁面,以便它們不必重複如此多的 HTML 程式碼。
逐步建立 tile 佈局
為了建立一個 tile 佈局,您需要做以下事情:
- 找出兩個頁面的相似之處。
- 建立一個新的佈局頁面。
- 建立兩個新的內容頁面,它們僅包含 和 之間的不同之處。
EmployeeListing.jsp
DeptListing.jsp
- 將 tile 佈局插入頁面 ―― 也就是讓 和 在它們的頁面中插入 tile 佈局,並將內容作為引數傳遞,同時傳遞其他必要的引數(比如標題)。
EmployeeListing.jsp
DeptListing.jsp
由於找出兩個頁面之間的相似之處需要 HTML 佈局和 Web 站點適用性方面的技能,事實證明這項工作更像一門藝術,而不是像一門科學。由於某些原因,擁有紫色的頭髮和紋身是有所幫助的。如果您不這樣認為,可以問我的朋友 Boo。
本教程重點集中於 Struts,而不是 HTML 佈局和 Web 站點適用性方面的必要技能。 因此,您不會了解關於紋身和紫色頭髮方面的內容。事實上,例子中的 HTML 佈局是刻意簡單化的,以防分散我們對 Tiles 框架的注意力。
建立 tile 佈局
一旦找出了頁面之間的相似之處(這是困難的部分),您就能夠建立新的佈局頁面(這是容易的部分)。為了建立一個 tile 佈局,您必須做以下事情:
- 使用標籤庫指令將 tile 標籤庫匯入 JSP,同時匯入需要的其他任何標籤庫。
- 使用字串引數來顯示像頁面這樣使用 標籤的內容。
tiles:getAsString
- 使用 標籤將 tile 插入佈局的適當區域。
tiles:insert
- 使用
tiles:put
標籤向內部 tile 傳遞任何需要的引數 ―― 這個標籤是tiles:insert
標籤的子標籤。
將 tile 標籤庫匯入 JSP,同時匯入需要的其他任何標籤庫,如下所示(siteLayout.jsp
):
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %
注意:要使用 tile 標籤庫,不要忘了包括 web.xml
檔案中的標籤庫:
<taglib><taglib-uri>/WEB-INF/struts-tiles.tld</taglib-uri><taglib-location>/WEB-INF/struts-tiles.tld </taglib-location></taglib>
接下來使用字串引數顯示諸如頁面標題之類的內容。您不僅需要更改頁面的內容,而且還需要更改出現在瀏覽器中的標題。為此,需要傳入 tile 佈局將要使用的標題:
View Code<html><head><title><tiles:getAsString name="title" ignore="true"/></title></head>
注意該程式碼中使用了tiles:getAsString
標籤來顯示字串引數。您不僅能夠傳遞字串引數,而且能夠傳遞要插入這個頁面的其他頁面。這裡假設呼叫 JSP 頁面向這個 tile 佈局傳遞了一個標題;否則,標題將是空白。
注意: ignore
屬性:
ignore
屬性如果為 true,這意味著在缺失該屬性的情況下忽略它。否則,如果
ignore
屬性為 false,那麼在沒有傳遞該引數的情況下,Tiles 框架將丟擲異常,頁面將不會顯示出來(false 是預設值)。
要插入內容 JSP,可使用 tiles:insert
標籤,它插入該框架作為 tile 來引用的任何頁面或 Web 資源。這個標籤實際上在 tile 佈局中定義了一個區域。 記住,tile 佈局的目標是將 tile 佈置到該佈局中。下面是向該佈局插入一個 tile 的例子:
<tiles:insert attribute="content"/>
上面這個例子非常簡單。如果想要插入一個 tile,並向它傳遞當前頁面範圍內的項,那該怎麼辦呢?例如,使用 Tiles 框架給 header.jsp
傳遞一個標題引數(在 tile 範圍內)是可以做到的。
呼叫其他 tile(傳遞屬性)
在插入 tile 的任何時候,您都可以選擇性地給它傳遞引數。傳遞給 tile 的引數將被放入該 tile 的標題範圍(稱為“標題屬性”)。例如,除了讓標題顯示在瀏覽器的標題欄之外,可能還希望該標題出現在頁面的頁首區域。
header.jsp
檔案將完成這個任務。雖然標題變數在該 tile 佈局頁面範圍之內,但它不在該 tile 佈局所插入的 tile 的範圍之內。脆弱方法每個 tile 和 tile 佈局都獲取它自己的環境 ―― 也就是它自己的 tile 範圍。因而,您必須像下面這樣給頁首 tile 傳遞該 tile 變數:
<tiles:insert attribute="header" ignore="true"><tiles:put name="title" beanName="title" beanScope="tile"/></tiles:insert>
tiles:put
標籤將這個 tile 佈局範圍內的 tile 引數放進頁首 tile 的範圍。然後頁首 tile 就能夠像 tile 佈局所做的那樣,通過
tiles:getAsString
標籤來使用這個引數。引數名稱就是頁首的 tile 範圍內的屬性名稱。 bean 引數是當前範圍內(siteLayout.jsp
)的 bean 的名稱。 beanScope 是您在其中查詢這個屬性的範圍(可能的值是頁面、tile、請求、會話和應用程式)。 您可以從任何範圍向該 tile
傳遞 bean。
這個 tile 佈局的完整清單
接下來,您會看到 quote.jsp
和 index.jsp
將要使用的這個新佈局頁面(siteLayout.jsp
)的完整清單:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%><html><head><title><tiles:getAsString name="title" ignore="true"/></title></head><body><table width="500" border="0" cellspacing="0" cellpadding="0"><tr bgcolor="#36566E"><td height="68" width="48%"><div align="left"><img src="images/hp_logo_rickhightower.gif" width="220" height="74"></div></td></tr><tr><td height="68" width="2000"><tiles:insert attribute="header" ignore="true"><tiles:put name="title" beanName="title" beanScope="tile"/></tiles:insert></td></tr><tr><td><div align="center"><tiles:insert attribute="content"/></div></td></tr><tr><td><tiles:insert attribute="footer" ignore="true"/></td></tr></table></body></html>
請花點時間研究一下上面的程式碼。注意 tile 是如何插入不同區域的(頁首、頁尾、內容),以及如何利用 HTML 佈局來為 tile 定義區域,從而為應用程式定義完整的佈局。
使用 tile 佈局現在已經定義好了使用 tiles 的 tile 佈局,您需要使用該佈局。 index.jsp
和
quote.jsp
都將使用同一個佈局。雖然這對兩個頁面來說似乎是大量的工作,但是對於真實的 Web 應用程式,你可能會對 20 個或更多的頁面使用同一個佈局。 通過這種方式,您不必在 20 個位置重複 HTML 或包括 JSP 片斷。
注意:為什麼不就使用 jsp:include
呢?
在適當的位置包括 JSP 片斷是重用 HTML 的脆弱方法。設想一下包括相同的 5 個 JSP 片斷的 20 個頁面 ―― 您必須重複 100 次。
為了使用 tile,您需要執行以下步驟:
- 使用
taglib
指令匯入 tile 標籤庫。 - 使用
tiles:insert
標籤來將 tile 佈局插入當前頁面。 - 使用
tiles:put
來傳遞字串引數。 - 使用
tiles:put
來傳入引數 tile。
通過使用 tile 佈局,您能夠在一個位置中將站點佈局所需要的整個 HTML 外部化,然後只需將它插入每個頁面。觀察一下下面的例子,它顯示瞭如何把 tile 佈局插入
index.jsp
:
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%><tiles:insert page="/siteLayout.jsp" flush="true"><tiles:put name="title" type="string" value="Get Rick Hightower Stock Quote"/><tiles:put name="header" value="/header.jsp"/><tiles:put name="footer" value="/footer.jsp"/><tiles:put name="content" value="/indexContent.jsp"/></tiles:insert>
現在,當您想要在 quote.jsp
中做相同的事情時,只需更改內容和頁首。
您需要使用插入標籤來呼叫 tile 佈局(顯示函式)。(注意用來將 tile 佈局插入當前頁面的 tiles:insert
標籤):
<tiles:insert page="/siteLayout.jsp" flush="true">
page 屬性指定了上一節中定義的 tile 佈局。如果
flush
屬性被設定為 true,這個 tile(以及到目前為止的頁面)將在頁面的其餘部分之前(或在緩衝區滿而迫使執行重新整理時)寫到瀏覽器。
要更改 quote.jsp
和 header.jsp
之間的頁面 tile,可使用子標籤
tiles:put
:
<tiles:put name="title" type="string" value="Get Stock Quote"/>
注意 tiles:put
是如何向 tile 佈局傳遞字串引數的。
tiles:put
的
name
屬性標籤指定了引數名稱。tiles:put
的
type
屬性指定了引數的型別。最後,value
引數用於傳遞
title
屬性的值。這允許您在使用 tiles:insert
標籤來呼叫 tile 佈局(顯示函式)時,把簡單的字串作為引數來傳遞。這些引數將成為該 tile 佈局屬性;也就是被插入該 tile 佈局的 tile 範圍。
注意您是如何將三個 tile 作為頁首、頁尾和內容引數來傳遞的( header.jsp
、footer.jsp
和
indexContent.jsp
):
<tiles:put name="header" value="/header.jsp"/><tiles:put name="footer" value="/footer.jsp"/><tiles:put name="content" value="/indexContent.jsp"/>
header.jsp
頁面將被插入該 tile 佈局的頁首區域。
footer.jsp
頁面將被插入該 tile 佈局的頁尾區域。indexContent.jsp
頁面將被插入該 tile 佈局的內容區域。 如果想插入不同的內容和 tile,只需改變內容引數的值。
注意用於 index.jsp
的表單不再駐留在
index.jsp
中。該表單現在駐留在 indexContent.jsp
中,如下面所列出的:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><html:form action="Lookup"><table width="45%" border="0"><tr><td><bean:message key="app.symbol"/>:</td><td><html:text property="symbol"/></td></tr><tr><td colspan="2" align="center"><html:submit /></td></tr></table></html:form>
除了將 tile 指定為 JSP 頁面外,您還能夠在 tiles:put
標籤的正文內將文字作為 tile 來傳遞。quote.jsp
所做的正好就是這樣:
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%><%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%><tiles:insert page="/siteLayout.jsp" flush="true"><tiles:put name="title" type="string" value="Rick Hightower Stock Quote"/><tiles:put name="header" value="/header.jsp"/><tiles:put name="footer" value="/footer.jsp"/><tiles:put name="content" type="string"><bean:message key="app.price"/><%= request.getAttribute("PRICE") %></tiles:put></tiles:insert
注意 tiles:put
標籤的標籤體包含 quote.jsp
的內容。其他每項內容都是該佈局所定義的,都與上一個例子中使用的 tile 相同。這樣的優點是能夠減少系統中的 JSP 頁面的數目。 關於哪種方法工作得最好,很久以來一直存在爭議,我的結論是它取決於 put 標籤體中有多少程式碼。
您看到這裡存在的問題了嗎?存在這樣一條規則:不要重複您自己(Don't repeat yourself,DRY),而您已經違背了這點規則。您知道為什麼嗎?
2. Tile 定義
建立定義
遺憾的是,quote.jsp
和 index.jsp
都違背了 DRY 規則,它們都重複定義了頁首和頁尾引數。由於它們都使用相同的引數值,因此不必在兩個頁面上重複相同的引數是很理想的。
設想有這樣一個真實的應用程式,其中的 tile 佈局包括更多的區域(比如說 8 個)和使用該 tile 佈局的更多頁面。您會發現每次想使用某個 tile 佈局時都要重複每個引數是一件很痛苦的事情。既然大多數頁面都將使用相同的頁首和頁尾,那麼在單個位置而不是在每個頁面定義它們將會帶來好處。
回顧一下前面的顯示函式類比,tile 佈局在某些方面類似一個顯示函式。 您使用 tiles:insert
來呼叫 tile 佈局,並且使用
tiles:put
來傳入引數。引數是能夠插入 tile 佈局區域的其他 JSP 頁面或字串。
您現在需要定義對應於頁首和頁尾區域的預設引數