利用Tiles簡化和增強Struts的 JSP開發(fā)
JSP(JavaServer Pages)技術(shù)通過includes支持應用程序?qū)ο蟮闹赜茫篿ncludes允許其他文件(包括其他JSP文件)在編譯時或者在應用程序運行時動態(tài)地被嵌入JSP文件。該特性非常有用,它可以將頁面的共用組件,諸如報頭、頁腳以及菜單提取出來,作為可重用組件被多個文件所用。
Includes功能很強大,并且可以節(jié)約時間,但是他們卻會帶來組件大量重復的潛在問題。 每個嵌入共用組件的JSP文件都復制include定義。如果被包含的文件的名稱改變了,那么每個使用Include引用這些文件的文件都需要被更新。
Tiles框架就是為了解決該局限性和增強Struts框架的功能而創(chuàng)建的。Tiles利用includes通過允許用戶定義模板(布局),然后指定模板內(nèi)容的裝入方式,而擴展了重用的概念。
借助JSP的include范例,每個JSP通過include指定其模板和明確地給出內(nèi)容的裝入方式。大多數(shù)JSP的模板是相同的:在相同的地方裝入相同的文件,只有加入獨特內(nèi)容(主體內(nèi)容)部分是不同的。借助Tiles,可以使用一個外部配置文件定義一個主模板JSP,后者指定每個用于裝填模板的include,然后定義哪個內(nèi)容需要加入該模板。比如,設(shè)想一下你有一個典型的網(wǎng)站模板:頁面頂端有一個報頭(標題),左側(cè)有一個菜單,中間部分為主體內(nèi)容,底部是頁腳。如果你僅僅使用JSP的includes來實現(xiàn)這種模板,每個具有這種模板的JSP不得不明確包含報頭、菜單、頁腳各部分以及頁面的主體內(nèi)容。該頁面中唯一獨特的部分就是主體內(nèi)容。然而,如果你使用Tiles來實現(xiàn)該模板,那么,你只需要創(chuàng)建一個包含報頭、菜單和頁腳的JSP文件,基于能夠傳遞給模板的用來指定哪個JSP文件包含主體內(nèi)容的屬性,就可以動態(tài)地包含主體內(nèi)容。根據(jù)你的愿望,該Tiles模板能夠被一次再一次地重復用于許多頁面,你的內(nèi)容JSPs必須包含的東西就是位于頁面中部的獨特的主體內(nèi)容。
將Tiles添加到你的應用程序中
現(xiàn)在你已經(jīng)知道了使用Tiles框架的好處,下面是將Tiles添加到你的Struts應用程序中所必要步驟:
- 將Tiles標記庫描述符(TLD,Tag Library Descriptor)文件添加到該應用程序。
- 創(chuàng)建模板JSPs。
- 更新現(xiàn)有的JSP以使用模板。
- 創(chuàng)建文件tiles-defs.xml。
- 更新struts-config.xml 文件中的傳遞定義(forward definitions),并且將Tiles插件添加到該文件中。
- 重新打包,并且運行更新后的該應用程序。
下面詳細講述該過程的每個步驟。
將Tiles 標記庫描述符文件添加到應用程序。更新你的Struts應用程序,以便使用Tiles的第一步是將Tiles標記庫描述符文件添加到該應用程序中。該步驟是必須的,只有這樣JSP才能使用Tiles標記庫。Tiles標記庫允許你在JSPs中使用Tiles模板。要將Tiles標記庫描述符文件添加到該應用程序中,需要從Struts發(fā)布庫目錄(例如,c:\java\jakarta-struts-1.1\lib)中將 struts-tiles.tld 文件拷貝到你的應用程序的/WEB-INF/tlds目錄中。下一步,在你的應用程序的Web部署描述符文件(web.xml)中添加一個標記庫描述符(TLD)項,并按如下所示注冊Tiles的標記庫描述符:
<taglib>
<taglib-uri>
/WEB-INF/tlds/struts-tiles.tld
</taglib-uri>
<taglib-location>
/WEB-INF/tlds/struts-tiles.tld
</taglib-location>
</taglib>
現(xiàn)在可以通過使用如下所示的代碼,從你的JSPs中引用TLD:
<%@ taglib
uri="/WEB-INF/tlds/struts-tiles.tld"
prefix="tiles" %>
創(chuàng)建模板JSPs。既然你已經(jīng)注冊了Tiles的標記庫描述符,那么現(xiàn)在就可以創(chuàng)建模板JSPs。代碼清單 1所示的模板描述了Tile的基本概念。該模板是在你應用程序已有的頁面結(jié)構(gòu)的基礎(chǔ)上創(chuàng)建的。
請注意,代碼清單 1中模板頁面的主體內(nèi)容采用黑體字。對于每個不同的頁面,該部分內(nèi)容是不相同的。然而,頁面的其他部分對這幾個頁面來說是相同的,這樣就可以將它們提取出來構(gòu)成一個通用的模板。
3個JSP文件--mainLayout.jsp、 header.jsp和 footer.jsp--構(gòu)成了該模板。mainLayout.jsp 文件如下所示:
<%@ taglib
uri="/WEB-INF/tlds/struts-tiles.tld"
prefix="tiles" %>
<html>
<head>
<title>
<tiles:getAsString name="title"/>
</title>
</head>
<body>
<tiles:insert attribute="header"/>
<tiles:insert attribute="body"/>
<tiles:insert attribute="footer"/>
</body>
</html>
該JSP文件定義了布局的模板,用于嵌入其他模板JSP以及主體內(nèi)容。主體內(nèi)容和其他模板JSP通過<tiles:insert>標記來嵌入。這些標記指定在Tiles配置文件中定義的屬性的名稱,這些屬性的值是在運行時應被插入到JSP中的JSPs的名字。請注意<tiles:getAsString>標記的用法。該標記的作用與<tiles:insert> 標記類似,但是與后者使用被包含的頁面的名稱作為指定的屬性值不同,它使用文本串來作為指定的屬性值。該方法適用于將小塊內(nèi)容動態(tài)地插入模板,但不保證自有包含文件也被插入。
下面是報頭和頁腳模板JSPs:
header.jsp
<font size="+1">
ABC, Inc. Human Resources Portal
</font><br>
<hr width="100%" noshade="true">
footer.jsp
<hr width="100%" noshade="true">
Copyright © ABC, Inc.
這種報頭和頁腳JSPs都非常的簡單,不包含太多的HTML。這些JSPs的內(nèi)容可以直接放入mainLayout.jsp文件中,內(nèi)容頁面仍然只需包含頁面的主體內(nèi)容。 然而,將頁面拆分成多個小塊可提高模板的使用靈活性。如果你需要一些頁面必須使用定制的報頭和頁腳而其他頁面使用標準報頭和頁腳,則可以將報頭和頁腳分離成離散的組件,以便使你能做到這一點。你只需在模板級別上定義報頭和頁腳屬性的值,對于需要定制的報頭或頁腳(或二者),可在頁面這一級上用新的值取代相應的值。
更新現(xiàn)有的JSPs以使用模板。在創(chuàng)建了模板JSPs之后,更新應用程序的原始JSPs,以便只包含其頁面的主體內(nèi)容。要達成此目的,從原始頁面中移除共用的模板部分。代碼清單 2顯示了更新后的只包含主體內(nèi)容的示例頁面。
代碼清單 2中的已更新的頁面不再包含內(nèi)容的報頭和頁腳部分。在運行時,模板JSPs用共用布局內(nèi)容填充已更新的頁面來創(chuàng)建完整的頁面。
創(chuàng)建文件tiles-defs.xml。有兩種聲明Tiles模板的方法:
- 通過在每個模板JSP中所包含的主JSP中的Tiles標記進行聲明;
- 通過在XML配置文件中對Tiles模板進行聲明。
下面所述的例子使用配置文件方式,因為這種方式更加靈活,并且更加容易維護。代碼清單 3顯示了聲明模板的tiles-defs.xml文件。該文件應該位于你的應用程序的/WEB-INF/ 文件夾中。
在該tiles-defs.xml 文件中有兩個Tiles的定義。該文件中的第一個定義聲明了名為main.layout的模板。通常,模板定義指定用于頁面的模板,也會指定屬性列表--這些屬性的值將會被用來完成模板的填充。 頁定義擴展模板定義,并且為在擴展模板中定義的屬性提供相應的值。
請注意,代碼清單 3中的第一個定義--main.layout--用put標記定義了4個屬性。這些屬性對于path屬性指定的模板JSP--mainLayout.jsp--可用。該模板JSP使用這些屬性來提供其內(nèi)容的位置。另外,與title屬性一樣,這些屬性能夠被用以支持文本串。mainLayout.jsp中使用了title屬性,因此它可以根據(jù)由頁面定義設(shè)置的值包含一個動態(tài)標題(title),從而擴展了模板的定義。
代碼清單 3的tiles-defs.xml 文件中的第二個定義聲明了一個被稱為search.page的頁面定義。該定義擴展了main.layout定義,并且為在模板定義中無值的屬性提供值。該定義可以重設(shè)模板定義中的任何屬性,但在本例中只有標題(title)和主體(body)屬性被重設(shè)。
更新struts-config.xml 文件中的傳遞定義,并且將Tiles插件添加到該文件中。在創(chuàng)建了Tiles配置文件之后,更新你的應用程序的struts-config.xml 文件以指向Tiles定義,而不是直接指向每個已經(jīng)轉(zhuǎn)換成使用Tiles的頁面的JSPs,并把Tiles 插件添加到struts-config.xml文件中。
如果沒有Tiles,正向作用定義就直接指向JSPs。有了Tiles,他們就指向Tiles配置文件中的頁面定義。比如說,在這之前應用程序的搜索行動(search action)直接指向search.jsp,如下所示:
<action
path="/search"
type="com.jamesholmes.minihr
.SearchAction"
name="searchForm"
scope="request"
validate="true"
input="/search.jsp"/>
然而,有了Tiles之后,該動作就指向搜索頁面的Tiles定義,如下所示:
<action
path="/search"
type="com.jamesholmes.minihr
.SearchAction"
name="searchForm"
scope="request"
validate="true"
input="search.page"/>
對于所有Struts配置文件中決定使用Tiles的傳遞和行動(forward and action)定義,如下例所示,用合適的Tiles頁面定義引用來代替相應的JSP引用。
為了將Tiles插件添加到應用程序,將以下代碼段添加到你的struts-config.xml文件中:
<!-- Tiles Configuration -->
<plug-in className=
"org.apache.struts.tiles.TilesPlugin">
<set-property property=
"definitions-config"
value="/WEB-INF/tiles-defs.xml"/>
</plug-in>
該段代碼使得應用程序在啟動時載入Tiles插件。請注意,Tiles配置文件由set-property標記來指定。通過提供一個以逗號分隔的文件列表,可以用該標記來指定多個配置文件。
代碼清單 4顯示了整個Struts配置文件。粗體顯示部分是被修改或者被添加的部分。重新打包,并且運行更新后的該應用程序。因為在該過程中,并沒有Java代碼被修改,所以不必要重新編譯應用程序。然而,因為添加了一些文件和對一些做了修改,所以在應用程序運行之前,需要重新打包和重新部署。一旦使你的更新之后的應用程序能夠運行,那么所有的功能都會和以前一樣發(fā)揮其作用,但是現(xiàn)在你可以毫不費力地添加新的頁面和對應用程序做出全局性的改變。
結(jié)論
通過提供了一個功能強大的促進頁面組件重用的模板創(chuàng)建系統(tǒng),Tiles框架極大地提高了核心Struts框架的價值。通過將Tiles框架用于你的JSP應用程序,可以節(jié)約大量的時間,并且大大提高你的Struts應用程序的開發(fā)效率。
James Holmes (james@)是一名獨立的Struts項目方面的Java咨詢專家和撰稿人。他是《Struts:完整的參考手冊》的作者,還是《Java的藝術(shù)》一書的合著者之一(兩本書都由McGraw-Hill/Osborne出版)