JSP
標(biāo)準(zhǔn)標(biāo)記庫(
JSP Standard Tag Library
,
JSTL
)是一個實(shí)現(xiàn)
Web
應(yīng)用程序中常見的通用功能的定制標(biāo)記庫集,這些功能包括迭代和條件判斷、數(shù)據(jù)管理格式化、
XML
操作以及數(shù)據(jù)庫訪問。在
developerWorks
上其新系列的第一篇文章中,軟件工程師
Mark Kolb
向您展示了如何使用
JSTL
標(biāo)記來避免在
JSP
頁面中使用腳本編制元素。您還將了解如何通過從表示層刪除源代碼來簡化軟件維護(hù)。最后,您將了解
JSTL
經(jīng)過簡化的表達(dá)式語言,它允許在不必使用功能齊全的編程語言的情況下對
JSTL
操作指定動態(tài)屬性值。
JavaServer Pages
(
JSP
)是用于
J2EE
平臺的標(biāo)準(zhǔn)表示層技術(shù)。
JSP
技術(shù)提供了用于執(zhí)行計(jì)算(這些計(jì)算用來動態(tài)地生成頁面內(nèi)容)的腳本編制元素和操作。腳本編制元素允許在
JSP
頁面中包括程序源代碼,在為響應(yīng)用戶請求而呈現(xiàn)頁面時可以執(zhí)行這些源代碼。操作將計(jì)算操作封裝到很象
HTML
或
XML
標(biāo)記的標(biāo)記中,
JSP
頁面的模板文本通常包含這些標(biāo)記。
JSP
規(guī)范只將幾種操作定義成了標(biāo)準(zhǔn),但從
JSP 1.1
開始,開發(fā)人員已經(jīng)能夠以定制標(biāo)記庫的方式創(chuàng)建其自己的操作了。
JSP
標(biāo)準(zhǔn)標(biāo)記庫(
JSTL
)是
JSP 1.2
定制標(biāo)記庫集,這些標(biāo)記庫實(shí)現(xiàn)大量服務(wù)器端
Java
應(yīng)用程序常用的基本功能。通過為典型表示層任務(wù)(如數(shù)據(jù)格式化和迭代或條件內(nèi)容)提供標(biāo)準(zhǔn)實(shí)現(xiàn),
JSTL
使
JSP
作者可以專注于特定于應(yīng)用程序的開發(fā)需求,而不是為這些通用操作
“
另起爐灶
”
。
當(dāng)然,您可以使用
JSP
腳本編制元素(
scriptlet
、表達(dá)式和聲明)來實(shí)現(xiàn)此類任務(wù)。例如,可以使用三個
scriptlet
實(shí)現(xiàn)條件內(nèi)容,清單
1
中著重顯示了這三個
scriptlet
。但是,因?yàn)槟_本編制元素依賴于在頁面中嵌入程序源代碼(通常是
Java
代碼),所以對于使用這些腳本編制元素的
JSP
頁面,其軟件維護(hù)任務(wù)的復(fù)雜度大大增加了。例如,清單
1
中的
scriptlet
示例嚴(yán)格地依賴于花括號的正確匹配。如果不經(jīng)意間引入了一個語法錯誤,則條件內(nèi)容中的嵌套其它
scriptlet
可能會造成嚴(yán)重破壞,并且在
JSP
容器編譯該頁面時,要使所產(chǎn)生的錯誤信息有意義可能會很困難。
清單
1.
通過
scriptlet
實(shí)現(xiàn)條件內(nèi)容
<% if (user.getRole() == "member")) { %>
<p>Welcome, member!</p>
<% } else { %>
<p>Welcome, guest!</p>
<% } %>
修正此類問題通常需要相當(dāng)豐富的編程經(jīng)驗(yàn)。盡管通常會由十分精通頁面布局和圖形設(shè)計(jì)的設(shè)計(jì)人員來開發(fā)和維護(hù)
JSP
,但是同一頁面中的腳本編制元素出現(xiàn)問題時,需要程序員的介入。這種狀況將單個文件中代碼的責(zé)任分擔(dān)給多人,因而使得開發(fā)、調(diào)試和增強(qiáng)此類
JSP
頁面成為很麻煩的任務(wù)。通過將常用功能包裝到定制標(biāo)記庫的標(biāo)準(zhǔn)集合中,
JSTL
使
JSP
作者可以減少對編制腳本元素的需求,甚至可以不需要它們,并避免了相關(guān)的維護(hù)成本。
JSTL 1.0
JSTL 1.0
發(fā)布于
2002
年
6
月,由四個定制標(biāo)記庫(
core
、
format
、
xml
和
sql
)和一對通用標(biāo)記庫驗(yàn)證器(
ScriptFreeTLV
和
PermittedTaglibsTLV
)組成。
core
標(biāo)記庫提供了定制操作,通過限制了作用域的變量管理數(shù)據(jù),以及執(zhí)行頁面內(nèi)容的迭代和條件操作。它還提供了用來生成和操作
URL
的標(biāo)記。顧名思義,
format
標(biāo)記庫定義了用來格式化數(shù)據(jù)(尤其是數(shù)字和日期)的操作。它還支持使用本地化資源束進(jìn)行
JSP
頁面的國際化。
xml
庫包含一些標(biāo)記,這些標(biāo)記用來操作通過
XML
表示的數(shù)據(jù),而
sql
庫定義了用來查詢關(guān)系數(shù)據(jù)庫的操作。
兩個
JSTL
標(biāo)記庫驗(yàn)證器允許開發(fā)人員在其
JSP
應(yīng)用程序中強(qiáng)制使用編碼標(biāo)準(zhǔn)。可以配置
ScriptFreeTLV
驗(yàn)證器以在
JSP
頁面中禁用各種類型的
JSP
腳本元素
— scriptlet
、表達(dá)式和聲明。類似地,
PermittedTaglibsTLV
驗(yàn)證器可以用來限制可能由應(yīng)用程序的
JSP
頁面訪問的定制標(biāo)記庫集(包括
JSTL
標(biāo)記庫)。
盡管
JSTL
最終將會成為
J2EE
平臺的必需組件,但目前只有少數(shù)應(yīng)用程序服務(wù)器包括它。
JSTL 1.0
的參考實(shí)現(xiàn)可作為
Apache
軟件基金會(
Apache Software Foundation
)的
Jakarta Taglibs
項(xiàng)目(請參閱參考資料)的一部分而獲得。可以將該參考實(shí)現(xiàn)中的定制標(biāo)記庫合并到任何支持
JSP 1.2
和
Servlet 2.3
規(guī)范的服務(wù)器,以添加對
JSTL
的支持。
表達(dá)式語言
在
JSP 1.2
中,可以使用靜態(tài)字符串或表達(dá)式(如果允許的話)指定
JSP
操作的屬性。例如,在清單
2
中,對
<jsp:setProperty>
操作的
name
和
property
屬性指定了靜態(tài)值,而用表達(dá)式指定了其
value
屬性。這個操作的效果是將請求參數(shù)的當(dāng)前值賦予命名的
bean
特性。以這種形式使用的表達(dá)式被稱為請求時屬性值(
request-time attribute value
),這是構(gòu)建到
JSP
規(guī)范中的用于動態(tài)指定屬性值的唯一機(jī)制。
清單
2.
合并請求時屬性值的
JSP
操作
<jsp:setProperty name="user" property="timezonePref"
value='<%= request.getParameter("timezone") %>'/>
因?yàn)檎埱髸r屬性值是用表達(dá)式指定的,所以它們往往有和其它腳本元素一樣的軟件維護(hù)問題。因此,
JSTL
定制標(biāo)記支持另一種用于指定動態(tài)屬性值的機(jī)制。可以用簡化的表達(dá)式語言(
EL
)而不使用完整的
JSP
表達(dá)式來指定
JSTL
操作的屬性值。
EL
提供了一些標(biāo)識符、存取器和運(yùn)算符,用來檢索和操作駐留在
JSP
容器中的數(shù)據(jù)。
EL
在某種程度上以
EcmaScript
(請參閱參考資料)和
XML
路徑語言(
XML Path Language
,
XPath
)為基礎(chǔ),因此頁面設(shè)計(jì)人員和程序員都應(yīng)該熟悉它的語法。
EL
擅長尋找對象及其特性,然后對它們執(zhí)行簡單操作;它不是編程語言,甚至不是腳本編制語言。但是,與
JSTL
標(biāo)記一起使用時,它就能使用簡單而又方便的符號來表示復(fù)雜的行為。
EL
表達(dá)式的格式是這樣的:用美元符號(
$
)定界,內(nèi)容包括在花括號(
{}
)中,如清單
3
所示。
清單
3.
說明
EL
表達(dá)式定界符的
JSTL
操作
<c:out value="${user.firstName}"/>
此外,您可以將多個表達(dá)式與靜態(tài)文本組合在一起以通過字符串并置來構(gòu)造動態(tài)屬性值,如清單
4
所示。單獨(dú)的表達(dá)式由標(biāo)識符、存取器、文字和運(yùn)算符組成。標(biāo)識符用來引用存儲在數(shù)據(jù)中心中的數(shù)據(jù)對象。
EL
有
11
個保留標(biāo)識符,對應(yīng)于
11
個
EL
隱式對象。假定所有其它標(biāo)識符都引用限制了作用域的變量。存取器用來檢索對象的特性或集合的元素。文字表示固定的值
—
數(shù)字、字符、字符串、布爾型或空值。運(yùn)算符允許對數(shù)據(jù)和文字進(jìn)行組合以及比較。
清單
4.
組合靜態(tài)文本和多個
EL
表達(dá)式以指定動態(tài)屬性值
<c:out value="Hello ${user.firstName} ${user.lastName}"/>
限制了作用域的變量
JSP API
通過
<jsp:useBean>
操作允許從
JSP
容器內(nèi)的四個不同作用域中存儲和檢索數(shù)據(jù)。
JSTL
通過提供用于指定和除去這些作用域中的對象的附加操作來擴(kuò)展這一能力。此外,
EL
提供將這些對象作為限制了作用域的變量進(jìn)行檢索的內(nèi)置支持。特別地,任何出現(xiàn)在
EL
表達(dá)式中但不對應(yīng)于任何
EL
隱式對象的標(biāo)識符,都被自動假定為引用存儲在四個
JSP
作用域的其中某個中的對象,這四個作用域是:
·
頁面作用域
·
請求作用域
·
會話作用域
·
應(yīng)用程序作用域
您可能還記得,只有在為特定請求處理頁面期間才能檢索存儲在該頁面作用域中的對象。如果對象是存儲在請求作用域中的,可以在處理所有參與處理某請求的頁面期間檢索這些對象(譬如在對某個請求的處理中遇到了一個或多個
<jsp:include>
或
<jsp:forward>
操作)。如果對象是存儲在會話作用域中的,則在與
Web
應(yīng)用程序的交互式會話期間,可以由用戶訪問的任何頁面檢索它(即,直到與該用戶交互相關(guān)聯(lián)的
HttpSession
對象無效為止)。可以由任何用戶從任何頁面訪問存儲在應(yīng)用程序作用域中的對象,直到卸載
Web
應(yīng)用程序本身為止(通常是由于關(guān)閉
JSP
容器所致)。
通過將字符串映射為期望作用域中的對象來將對象存儲到該作用域。然后,就可以通過提供相同字符串來從該作用域檢索該對象。在作用域的映射中查找字符串,并返回被映射的對象。在
Servlet API
中,將此類對象稱為相應(yīng)作用域的屬性。但是,在
EL
的上下文中,也將與屬性相關(guān)聯(lián)的字符串看作變量的名稱,該變量通過屬性映射的方式獲得特定的值。
在
EL
中,與隱式對象無關(guān)聯(lián)的標(biāo)識符被認(rèn)為是存儲在四個
JSP
作用域中的名稱對象。首先對頁面作用域檢查是否存在這樣的標(biāo)識符,其次對請求作用域、然后對會話作用域、最后對應(yīng)用程序作用域依次進(jìn)行這樣的檢查,然后測試該標(biāo)識符的名稱是否與存儲在該作用域中的某個對象的名稱匹配。第一個這樣的匹配作為
EL
標(biāo)識符的值被返回。通過這種方法,可以將
EL
標(biāo)識符看作引用限制了作用域的變量。
從更技術(shù)的方面來說,沒有映射到隱式對象的標(biāo)識符是用
PageContext
實(shí)例的
findAttribute()
方法求值的,該實(shí)例表示對頁面的處理,在該頁面上,當(dāng)前正在處理用于請求的表達(dá)式。標(biāo)識符的名稱作為參數(shù)傳遞給這個方法,然后該方法依次在四個作用域中搜索具有相同名稱的屬性。并將所找到的第一個匹配項(xiàng)作為
findAttribute()
方法的值返回。如果未在這四個作用域中找到這樣的屬性,則返回
null
。
最終,限制了作用域的變量是四個
JSP
作用域的屬性,這些屬性具有可以用作
EL
標(biāo)識符的名稱。只要對限制了作用域的變量賦予由字母數(shù)字組成的名稱,就可以通過
JSP
中提供的用于設(shè)置屬性的任何機(jī)制來創(chuàng)建它們。這包括內(nèi)置的
<jsp:useBean>
操作,以及由
Servlet API
中的幾個類定義的
setAttribute()
方法。此外,四個
JSTL
庫中定義的許多定制標(biāo)記本身就能夠設(shè)置作為限制了作用域的變量使用的屬性值。
隱式對象
表
1
中列出了
11
個
EL
隱式對象的標(biāo)識符。不要將這些對象與
JSP
隱式對象(一共只有九個)混淆,其中只有一個對象是它們所共有的。
表
1. EL
隱式對象
類別
標(biāo)識符
描述
JSP
pageContext
PageContext
實(shí)例對應(yīng)于當(dāng)前頁面的處理
作用域
pageScope
與頁面作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的
Map
類
requestScope
與請求作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的
Map
類
sessionScope
與會話作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的
Map
類
applicationScope
與應(yīng)用程序作用域?qū)傩缘拿Q和值相關(guān)聯(lián)的
Map
類
請求參數(shù)
param
按名稱存儲請求參數(shù)的主要值的
Map
類
paramValues
將請求參數(shù)的所有值作為
String
數(shù)組存儲的
Map
類
請求頭
header
按名稱存儲請求頭主要值的
Map
類
headerValues
將請求頭的所有值作為
String
數(shù)組存儲的
Map
類
Cookie
cookie
按名稱存儲請求附帶的
cookie
的
Map
類
初始化參數(shù)
initParam
按名稱存儲
Web
應(yīng)用程序上下文初始化參數(shù)的
Map
類
盡管
JSP
和
EL
隱式對象中只有一個公共對象(
pageContext
),但通過
EL
也可以訪問其它
JSP
隱式對象。原因是
pageContext
擁有訪問所有其它八個
JSP
隱式對象的特性。實(shí)際上,這是將它包括在
EL
隱式對象中的主要理由。
其余所有
EL
隱式對象都是映射,可以用來查找對應(yīng)于名稱的對象。前四個映射表示先前討論的各種屬性作用域。可以用它們來查找特定作用域中的標(biāo)識符,而不用依賴于
EL
在缺省情況下使用的順序查找過程。
接下來的四個映射用來獲取請求參數(shù)和請求頭的值。因?yàn)?/span>
HTTP
協(xié)議允許請求參數(shù)和請求頭具有多個值,所以它們各有一對映射。每對中的第一個映射返回請求參數(shù)或頭的主要值,通常是恰巧在實(shí)際請求中首先指定的那個值。每對中第二個映射允許檢索參數(shù)或頭的所有值。這些映射中的鍵是參數(shù)或頭的名稱,但這些值是
String
對象的數(shù)組,其中的每個元素都是單一參數(shù)值或頭值。
cookie
隱式對象提供了對由請求設(shè)置的
cookie
名稱的訪問。這個對象將所有與請求相關(guān)聯(lián)的
cookie
名稱映射到表示那些
cookie
特性的
Cookie
對象。
最后一個
EL
隱式對象
initParam
是一個映射,它儲存與
Web
應(yīng)用程序相關(guān)聯(lián)的所有上下文的初始化參數(shù)的名稱和值。初始化參數(shù)是通過
web.xml
部署描述符文件指定的,該文件位于應(yīng)用程序的
WEB-INF
目錄中。
存取器
因?yàn)?/span>
EL
標(biāo)識符是作為隱式對象或限制了作用域的變量(通過屬性來實(shí)現(xiàn))解析的,因此有必要將它們轉(zhuǎn)換成
Java
對象。
EL
可以自動包裝和解包其相應(yīng)的
Java
類中的基本類型(例如,可以在后臺將
int
強(qiáng)制轉(zhuǎn)換成
Integer
類,反之亦可),但大多數(shù)的標(biāo)識符將成為指向完整的
Java
對象的指針。
結(jié)果是,對這些對象的特性或(在對象是數(shù)組和集合的情況下)對其元素的訪問通常是令人滿意的。就為了實(shí)現(xiàn)這種用途,
EL
提供了兩種不同的存取器(點(diǎn)運(yùn)算符(
.
)和方括號運(yùn)算符(
[]
)),也支持通過
EL
操作特性和元素。
點(diǎn)運(yùn)算符通常用于訪問對象的特性。例如,在表達(dá)式
${user.firstName}
中,使用點(diǎn)運(yùn)算符來訪問
user
標(biāo)識符所引用對象的名為
firstName
的特性。
EL
使用
Java bean
約定訪問對象特性,因此必須定義這個特性的
getter
方法(通常是名為
getFirstName()
的方法),以便表達(dá)式正確求值。當(dāng)被訪問的特性本身是對象時,可以遞歸地應(yīng)用點(diǎn)運(yùn)算符。例如,如果我們虛構(gòu)的
user
對象有一個實(shí)現(xiàn)為
Java
對象的
address
特性,那么也可以用點(diǎn)運(yùn)算符來訪問這個對象的特性。例如,表達(dá)式
${user.address.city}
將會返回這個地址對象嵌套的
city
特性。
方括號運(yùn)算符用來檢索數(shù)組和集合的元素。在數(shù)組和有序集合(也即,實(shí)現(xiàn)了
Java.util.List
接口的集合)的情況下,把要檢索的元素的下標(biāo)放在方括號中。例如,表達(dá)式
${urls[3]}
返回
urls
標(biāo)識符所引用的數(shù)組或集合的第四個元素(和
Java
語言以及
JavaScript
中一樣,
EL
中的下標(biāo)是從零開始的)。
對于實(shí)現(xiàn)
Java.util.Map
接口的集合,方括號運(yùn)算符使用關(guān)聯(lián)的鍵查找存儲在映射中的值。在方括號中指定鍵,并將相應(yīng)的值作為表達(dá)式的值返回。例如,表達(dá)式
${commands["dir"]}
返回與
commands
標(biāo)識符所引用的
Map
中的
"dir"
鍵相關(guān)聯(lián)的值。
對于上述兩種情況,都可允許表達(dá)式出現(xiàn)在方括號中。對嵌套表達(dá)式求值的結(jié)果將被作為下標(biāo)或鍵,用來檢索集合或數(shù)組的適當(dāng)元素。和點(diǎn)運(yùn)算符一樣,方括號運(yùn)算符也可以遞歸應(yīng)用。這使得
EL
能夠從多維數(shù)組、嵌套集合或兩者的任意組合中檢索元素。此外,點(diǎn)運(yùn)算符和方括號運(yùn)算符還可以互操作。例如,如果數(shù)組的元素本身是對象,則可以使用方括號運(yùn)算符來檢索該數(shù)組的元素,并結(jié)合點(diǎn)運(yùn)算符來檢索該元素的一個特性(例如
${urls[3].protocol}
)。
假定
EL
充當(dāng)指定動態(tài)屬性值的簡化語言,
EL
存取器有一個有趣的功能(與
Java
語言的存取器不同),那就是它們在應(yīng)用于
null
時不拋出異常。如果應(yīng)用
EL
存取器的對象(例如,
${foo.bar}
和
${foo["bar"]}
中的
foo
標(biāo)識符)是
null
,那么應(yīng)用存取器的結(jié)果也是
null
。事實(shí)證明,在大多數(shù)情況下,這是一個相當(dāng)有用的行為,不久您就會了解這一點(diǎn)。
最后,點(diǎn)運(yùn)算符和方括號運(yùn)算符可能實(shí)現(xiàn)某種程度的互換。例如,也可以使用
${user["firstName"]}
來檢索
user
對象的
firstName
特性,正如可以用
${commands.dir}
獲取與
commands
映射中的
"dir"
鍵相關(guān)聯(lián)的值一樣。
運(yùn)算符
EL
還可以通過使用標(biāo)識符和存取器,遍歷包含應(yīng)用程序數(shù)據(jù)(通過限制了作用域的變量公開)或關(guān)于環(huán)境的信息(通過
EL
隱式對象)的對象層次結(jié)構(gòu)。但是,只是訪問這些數(shù)據(jù),通常不足以實(shí)現(xiàn)許多
JSP
應(yīng)用程序所需的表示邏輯。
最終,
EL
還包括了幾個用來操作和比較
EL
表達(dá)式所訪問數(shù)據(jù)的運(yùn)算符。表
2
中匯總了這些運(yùn)算符。
表
2. EL
運(yùn)算符
類別
運(yùn)算符
算術(shù)運(yùn)算符
+
、
-
、
*
、
/
(或
div
)和
%
(或
mod
)
關(guān)系運(yùn)算符
==
(或
eq
)、
!=
(或
ne
)、
<</code>
(或
lt
)、
>
(或
gt
)、
<=
(或
le
)和
>=
(或
ge
)
邏輯運(yùn)算符
&&
(或
and
)、
||
(或
or
)和
!
(或
not
)
驗(yàn)證運(yùn)算符
empty
算術(shù)運(yùn)算符支持?jǐn)?shù)值的加法、減法、乘法和除法。還提供了一個求余運(yùn)算符。注:除法和求余運(yùn)算符都有替代的、非符號的名稱(為的是與
XPath
保持一致)。清單
5
中顯示了一個演示算術(shù)運(yùn)算符用法的示例表達(dá)式。對幾個
EL
表達(dá)式應(yīng)用算術(shù)運(yùn)算符的結(jié)果是將該算術(shù)運(yùn)算符應(yīng)用于這些表達(dá)式返回的數(shù)值所得的結(jié)果。
清單
5.
利用算術(shù)運(yùn)算符的
EL
表達(dá)式
${item.price * (1 + taxRate[user.address.zipcode])}
關(guān)系運(yùn)算符允許比較數(shù)字或文本數(shù)據(jù)。比較的結(jié)果作為布爾值返回。邏輯運(yùn)算符允許合并布爾值,返回新的布爾值。因此,可以將
EL
邏輯運(yùn)算符應(yīng)用于嵌套的關(guān)系或邏輯運(yùn)算符的結(jié)果,如清單
6
所示。
清單
6.
利用關(guān)系和邏輯運(yùn)算符的
EL
表達(dá)式
${(x >= min) && (x <= max)}
最后一種
EL
運(yùn)算符是
empty
,它對于驗(yàn)證數(shù)據(jù)特別有用。
empty
運(yùn)算符采用單個表達(dá)式作為其變量(也即,
${empty input}
),并返回一個布爾值,該布爾值表示對表達(dá)式求值的結(jié)果是不是
“
空
”
值。求值結(jié)果為
null
的表達(dá)式被認(rèn)為是空,即無元素的集合或數(shù)組。如果參數(shù)是對長度為零的
String
求值所得的結(jié)果,則
empty
運(yùn)算符也將返回
true
。
表
3
顯示了
EL
運(yùn)算符的優(yōu)先級。正如清單
5
和
6
所示,可以用圓括號對表達(dá)式分組,高于普通的優(yōu)先級規(guī)則。
表
3. EL
運(yùn)算符優(yōu)先級(自頂?shù)降祝瑥淖蟮接遥?/span>
[], .
()
unary -、not、!、empty
*、/、div、%、mod
+、binary -
() <</code>、>、<=、>=、lt、gt、le、ge
==、!=、eq、ne
&&、and
||、or
文字
在
EL
表達(dá)式中,數(shù)字、字符串、布爾值和
null
都可以被指定為文字值。字符串可以用單引號或雙引號定界。布爾值被指定為
true
和
false
。
Taglib
偽指令
正如我們先前討論的,
JSTL 1.0
包括四個定制標(biāo)記庫。為了演示
JSTL
標(biāo)記和表達(dá)式語言的交互,我們將研究幾個來自
JSTL core
庫的標(biāo)記。和使用任何
JSP
定制標(biāo)記庫一樣,必須在您想要使用這個庫標(biāo)記的任何頁面中包括
taglib
偽指令。清單
7
顯示了用于這個特定庫的偽指令。
清單
7.
用于
JSTL core
庫
EL
版本的
taglib
偽指令
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
實(shí)際上,對應(yīng)于
JSTL core
庫的
taglib
偽指令有兩種,因?yàn)樵?/span>
JSTL 1.0
中,
EL
是可選的。所有四個
JSTL 1.0
定制標(biāo)記庫都有使用
JSP
表達(dá)式(而不是
EL
)指定動態(tài)屬性值的備用版本。因?yàn)檫@些備用庫依賴于
JSP
的更傳統(tǒng)的請求時屬性值,所以它們被稱為
RT
庫,而那些使用表達(dá)式語言的則被稱為
EL
庫。開發(fā)人員用不同的
taglib
偽指令來區(qū)分每個庫的這兩個版本。清單
8
顯示了使用
core
庫的
RT
版本的偽指令。但是,由于現(xiàn)在我們討論的重點(diǎn)是
EL
,所以首先需要這些偽指令。
清單
8.
用于
JSTL core
庫
RT
版本的
taglib
偽指令
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>
變量標(biāo)記
我們首先要考慮的
JSTL
定制標(biāo)記是
<c:set>
操作。正如已經(jīng)說明的,限制了作用域的變量在
JSTL
中起關(guān)鍵作用,
<c:set>
操作提供基于標(biāo)記的機(jī)制來創(chuàng)建和設(shè)置限制了作用域的變量。清單
9
中顯示了該操作的語法,其中
var
屬性指定了限制了作用域的變量的名稱,
scope
屬性表明了該變量駐留在哪個作用域中,
value
屬性指定了分配給該變量的值。如果指定變量已經(jīng)存在,則簡單地將所指明的值賦給它。如果不存在,則創(chuàng)建新的限制了作用域的變量,并用該值初始化這個變量。
清單
9. <c:set>
操作的語法
<c:set var="name" scope="scope" value="expression"/>
scope
屬性是可選的,其缺省值是
page
。
清單
10
中顯示了
<c:set>
的兩個示例。在第一個示例中,將會話作用域變量設(shè)置成
String
值。在第二個示例中,用表達(dá)式來設(shè)置數(shù)值:將頁面作用域內(nèi)名為
square
的變量賦值為名為
x
的請求參數(shù)的值的平方。
清單
10. <c:set>
操作示例
<c:set var="timezone" scope="session" value="CST"/>
<c:set var="square" value="${param['x'] * param['x']}"/>
您還可以將限制了作用域的變量的值指定為
<c:set>
操作的主體內(nèi)容,而不是使用屬性。使用這種方法,您可以重新編寫清單
10
中的第一個示例,如清單
11
所示。此外,正如我們馬上可以看到的,
<c:set>
標(biāo)記的主體內(nèi)容本身也可以使用定制標(biāo)記。
<c:set>
主體內(nèi)生成的所有內(nèi)容都將作為一個
String
值賦給指定變量。
清單
11.
通過主體內(nèi)容指定
<c:set>
操作的值
<c:set var="timezone" scope="session">CST</c:set>
JSTL core
庫包含第二個用于管理限制了作用域的變量的標(biāo)記
— <c:remove>
。顧名思義,
<c:remove>
操作是用來刪除限制了作用域的變量的,它獲取兩個屬性。
var
屬性指定待刪除變量的名稱,
scope
屬性是可選的,它表示待刪除變量來自哪個作用域,缺省為
page
,如清單
12
所示。
清單
12. <c:remove>
操作示例
<c:remove var="timezone" scope="session"/>
輸出
盡管
<c:set>
操作允許將表達(dá)式結(jié)果賦給限制了作用域的變量,但開發(fā)人員通常會希望只顯示表達(dá)式的值,而不存儲它。
JSTL <c:out>
定制標(biāo)記承擔(dān)這一任務(wù),其語法如清單
13
所示。該標(biāo)記對由其
value
屬性指定的表達(dá)式進(jìn)行求值,然后打印結(jié)果。如果指定了可選屬性
default
,那么,在對
value
屬性的表達(dá)式求值所得結(jié)果為
null
或空
String
的情況下,
<c:out>
將打印其值。
清單
13. <c:out>
操作的語法
<c:out value="expression" default="expression" escapeXml="boolean"/>
escapeXml
屬性也是可選的。它控制當(dāng)用
<c:out>
標(biāo)記輸出諸如
“<”
、
“>”
和
“&”
之類的字符(在
HTML
和
XML
中具有特殊意義)時是否應(yīng)該進(jìn)行轉(zhuǎn)義。如果將
escapeXml
設(shè)置為
true
,則會自動將這些字符轉(zhuǎn)換成相應(yīng)的
XML
實(shí)體(此處提到的字符分別轉(zhuǎn)換成
<
、
>
和
&
)。
例如,假定有一個名為
user
的會話作用域變量,它是一個類的實(shí)例,該類為用戶定義了兩個特性:
username
和
company
。每當(dāng)用戶訪問站點(diǎn)時,這個對象被自動分配給會話,但直到用戶實(shí)際登錄后,才會設(shè)置這兩個特性。假定是這種方案,請考慮清單
14
中的
JSP
片段。在用戶登錄之后,這個片段將顯示單詞
“Hello”
,其后是他/她的用戶名和一個驚嘆號。但是,在用戶登錄之前,由這個片段生成的內(nèi)容則是短語
“Hello Guest!”
。在這種情況下,因?yàn)?/span>
username
特性還有待初始化,所以
<c:out>
標(biāo)記將轉(zhuǎn)而打印出
default
屬性的值(即字符串
“Guest”
)。
清單
14.
帶缺省內(nèi)容的
<c:out>
操作示例
Hello
<c:out value="${user.username}" default=="Guest"/>!
接下來,考慮清單
15
,它使用了
<c:out>
標(biāo)記的
escapeXml
屬性。如果在這種情況下已經(jīng)將
company
特性設(shè)置成
Java String
值
"Flynn & Sons"
,那么,實(shí)際上該操作生成的內(nèi)容將是
Flynn & Sons
。如果這個操作是生成
HTML
或
XML
內(nèi)容的
JSP
頁面的一部分,那么,這個字符串中間的
“&”
符號最終可能被解釋為
HTML
或
XML
控制字符,從而妨礙了對該內(nèi)容的顯示或解析。但是,如果將
escapeXml
屬性值設(shè)置成
true
,則所生成的內(nèi)容將是
Flynn & Sons
。瀏覽器或解析器不會因在解釋時遇到這種內(nèi)容而出問題。假定
HTML
和
XML
是
JSP
應(yīng)用程序中最常見的內(nèi)容類型,所以
escapeXml
屬性的缺省值是
true
就不足為奇了。
清單
15.
禁用轉(zhuǎn)義的
<c:out>
操作示例
<c:out value="${user.company}" escapeXml="false"/>
用缺省值設(shè)置變量
除了簡化動態(tài)數(shù)據(jù)的顯示之外,當(dāng)通過
<c:set>
設(shè)置變量值時,
<c:out>
指定缺省值的能力也很有用。正如清單
11
所示,用來賦給限制了作用域的變量的值可以指定為
<c:set>
標(biāo)記的主體內(nèi)容,也可以通過其值屬性來指定。通過將
<c:out>
操作嵌套在
<c:set>
標(biāo)記的主體內(nèi)容中,變量賦值就可以利用其缺省值能力。
清單
16
中說明了這種方法。外部
<c:set>
標(biāo)記的行為非常簡單:它根據(jù)其主體內(nèi)容設(shè)置會話作用域
timezone
變量的值。但是,在這種情況下,主體內(nèi)容是通過
<c:out>
操作生成的。這個嵌套操作的值屬性是表達(dá)式
${cookie['tzPref'].value}
,它嘗試通過
cookie
隱式對象返回名為
tzPref
的
cookie
值。(
cookie
隱式對象將
cookie
名稱映射到相應(yīng)的
Cookie
實(shí)例,這意味著必須通過對象的
value
特性使用點(diǎn)運(yùn)算符來檢索儲存在
cookie
中的實(shí)際數(shù)據(jù)。)
清單
16.
合并
<c:set>
和
<c:out>
以提供缺省變量值
<c:set var="timezone" scope=="session">
<c:out value="${cookie['tzPref'].value}" default=="CST"/>
</c:set>
但是,請考慮以下情況,用戶是第一次嘗試使用這段代碼的
Web
應(yīng)用程序。結(jié)果是,請求中沒有提供名為
tzPref
的
cookie
。這意味著使用隱式對象的查找將返回
null
,在這種情況下整個表達(dá)式將返回
null
。因?yàn)閷?/span>
<c:out>
標(biāo)記的
value
屬性求值的結(jié)果是
null
,所以
<c:out>
標(biāo)記會轉(zhuǎn)而輸出對其
default
屬性求值的結(jié)果。在這里是字符串
CST
。因此,實(shí)際的結(jié)果是將
timezone
限制了作用域的變量設(shè)置成用戶的
tzPref cookie
中存儲的時區(qū),或者,如果沒有,則使用缺省時區(qū)
CST
。
EL
和
JSP 2.0
目前,表達(dá)式語言僅可用于指定
JSTL
定制標(biāo)記中的動態(tài)屬性值。但
JSTL 1.0
表達(dá)式語言的一個擴(kuò)展已經(jīng)被提出,會把它包括到
JSP 2.0
中去,眼下正在進(jìn)行最后評審。這個擴(kuò)展將允許開發(fā)人員通過自己的定制標(biāo)記來使用
EL
。頁面作者將可以在目前允許使用
JSP
表達(dá)式的任何地方使用
EL
表達(dá)式,譬如將動態(tài)值插入模板文本中:
<p>Your preferred time zone is ${timezone}</p>
。
這個
JSP 2.0
功能(就象
JSTL
本身一樣)將支持頁面作者進(jìn)一步減少對
JSP
編制腳本元素的依賴,從而改進(jìn)
JSP
應(yīng)用程序的可維護(hù)性。
結(jié)束語
EL
(與四個
JSTL
定制標(biāo)記庫提供的操作結(jié)合起來)允許頁面作者不使用腳本元素即可實(shí)現(xiàn)表示層邏輯。例如,對比本文開頭清單
1
中的
JSP
代碼和清單
17
中顯示的通過
JSTL
實(shí)現(xiàn)的同樣功能。(
JSTL core
庫中其余的標(biāo)記,包括
<c:choose>
及其子標(biāo)記,將在本系列的下一篇文章中討論。)盡管顯然執(zhí)行了條件邏輯,但是
JSTL
版本中沒有
Java
語言源代碼,并且標(biāo)記之間的關(guān)系(尤其是關(guān)于嵌套需求)對于任何精通
HTML
語法的人都應(yīng)該是熟悉的。
清單
17.
合并
<c:set>
和
<c:out>
以提供缺省變量值
<c:choose>
<c:when test="${user.role == 'member'}">
<p>Welcome, member!</p>
</c:when>
<c:otherwise>
<p>Welcome, guest!</p>
</c:otherwise>
</c:choose>
通過提供大多數(shù)
Web
應(yīng)用程序常用功能的標(biāo)準(zhǔn)實(shí)現(xiàn),
JSTL
有助于加速開發(fā)周期。與
EL
結(jié)合起來,
JSTL
可以不需要對表示層程序編寫代碼,這極大地簡化了
JSP
應(yīng)用程序的維護(hù)。
posted on 2006-09-06 16:49
周銳 閱讀(887)
評論(0) 編輯 收藏 所屬分類:
Jsp