JSTL 入門: 運算式語言

來源:互聯網
上載者:User
js

JSP 標準標記庫(JSP Standard Tag Library,JSTL)是一個實現 Web 應用程式中常見的通用功能的定製標記庫集,這些功能包括迭代和條件判斷、資料管理格式化、XML 操作以及資料庫訪問。在 developerWorks 上其新系列的第一篇文章中,軟體工程師 Mark Kolb 向您展示了如何使用 JSTL 標記來避免在 JSP 頁面中使用指令碼編製元素。您還將瞭解如何通過從展示層刪除原始碼來簡化軟體維護。最後,您將瞭解 JSTL 經過簡化的運算式語言,它允許在不必使用功能齊全的程式設計語言的情況下對 JSTL 操作指定動態屬性值。
JavaServer Pages(JSP)是用於 J2EE 平台的標準展示層技術。JSP 技術提供了用於執行計算(這些計算用來動態地產生頁面內容)的指令碼編製元素和操作。指令碼編製元素允許在 JSP 頁面中包括程式原始碼,在為響應使用者請求而呈現頁面時可以執行這些原始碼。操作將計算操作封裝到很象 HTML 或 XML 標記的標記中,JSP 頁面的模板文本通常包含這些標記。JSP 規範只將幾種操作定義成了標準,但從 JSP 1.1 開始,開發人員已經能夠以定製標記庫的方式建立其自己的操作了。

JSP 標準標記庫(JSTL)是 JSP 1.2 定製標記庫集,這些標記庫實現大量伺服器端 Java 應用程式常用的準系統。通過為典型展示層任務(如資料格式化和迭代或條件內容)提供標準實現,JSTL 使 JSP 作者可以專註於特定於應用程式的開發需求,而不是為這些通用操作“另起爐灶”。

當然,您可以使用 JSP 指令碼編製元素(scriptlet、運算式和聲明)來實現此類任務。例如,可以使用三個 scriptlet 實現條件內容,清單 1 中著重顯示了這三個 scriptlet。但是,因為指令碼編製元素依賴於在頁面中嵌入程式原始碼(通常是 Java 代碼),所以對於使用這些指令碼編製元素的 JSP 頁面,其軟體維護任務的複雜度大大增加了。例如,清單 1 中的 scriptlet 樣本嚴格地依賴於花括弧的正確匹配。如果不經意間引入了一個語法錯誤,則條件內容中的嵌套其它 scriptlet 可能會造成嚴重破壞,並且在 JSP 容器編譯該頁面時,要使所產生的錯誤資訊有意義可能會很困難。


清單 1. 通過 scriptlet 實現條件內容
<% if (user.getRole() == "member")) { %>
    <p>Welcome, member!</p>
<% } else { %>
    <p>Welcome, guest!</p>
<% } %>
 


修正此類問題通常需要相當豐富的編程經驗。儘管通常會由十分精通頁面配置和圖形設計的設計人員來開發和維護 JSP,但是同一頁面中的指令碼編製元素出現問題時,需要程式員的介入。這種狀況將單個檔案中代碼的責任分擔給多人,因而使得開發、調試和增強此類 JSP 頁面成為很麻煩的任務。通過將常用功能封裝到定製標記庫的標準集合中,JSTL 使 JSP 作者可以減少對編製指令碼元素的需求,甚至可以不需要它們,並避免了相關的維護成本。


 回頁首
 

JSTL 1.0

JSTL 1.0 發佈於 2002 年 6 月,由四個定製標記庫( core 、 format 、 xml 和 sql )和一對通用標記庫驗證器( ScriptFreeTLV 和 PermittedTaglibsTLV )組成。 core 標記庫提供了定製操作,通過限制了範圍的變數管理資料,以及執行頁面內容的迭代和條件操作。它還提供了用來產生和操作 URL 的標記。顧名思義, format 標記庫定義了用來格式化資料(尤其是數字和日期)的操作。它還支援使用本地化資源束進行 JSP 頁面的國際化。 xml 庫包含一些標記,這些標記用來操作通過 XML 表示的資料,而 sql 庫定義了用來查詢關聯式資料庫的操作。

兩個 JSTL 標記庫驗證器允許開發人員在其 JSP 應用程式中強制使用編碼通訊協定。可以配置 ScriptFreeTLV 驗證器以在 JSP 頁面中禁用各種類型的 JSP 指令碼元素 ― scriptlet、運算式和聲明。類似地, PermittedTaglibsTLV 驗證器可以用來限制可能由應用程式的 JSP 頁面訪問的定製標記庫集(包括 JSTL 標記庫)。

儘管 JSTL 最終將會成為 J2EE 平台的必要元件,但目前只有少數應用程式伺服器包括它。JSTL 1.0 的參考實現可作為 Apache 軟體基金會(Apache Software Foundation)的 Jakarta Taglibs 項目(請參閱 參考資料)的一部分而獲得。可以將該參考實現中的定製標記庫合并到任何支援 JSP 1.2 和 Servlet 2.3 規範的伺服器,以添加對 JSTL 的支援。


 回頁首
 

運算式語言

在 JSP 1.2 中,可以使用靜態字串或運算式(如果允許的話)指定 JSP 操作的屬性。例如,在清單 2 中,對 <jsp:setProperty> 操作的 name 和 property 屬性指定了靜態值,而用運算式指定了其 value 屬性。這個操作的效果是將請求參數的當前值賦予命名的 bean 特性。以這種形式使用的運算式被稱為 請求時屬性值(request-time attribute value),這是構建到 JSP 規範中的用於動態指定屬性值的唯一機制。


清單 2. 合并請求時屬性值的 JSP 操作
<jsp:setProperty name="user" property="timezonePref"
                 value='<%= request.getParameter("timezone") %>'/>


因為請求時屬性值是用運算式指定的,所以它們往往有和其它指令碼元素一樣的軟體維護問題。因此,JSTL 定製標記支援另一種用於指定動態屬性值的機制。可以用簡化的 運算式語言(EL)而不使用完整的 JSP 運算式來指定 JSTL 操作的屬性值。EL 提供了一些標識符、存取器和運算子,用來檢索和操作駐留在 JSP 容器中的資料。EL 在某種程度上以 EcmaScript(請參閱 參考資料)和 XML 路徑語言(XML Path Language,XPath)為基礎,因此頁面設計人員和程式員都應該熟悉它的文法。EL 擅長尋找對象及其特性,然後對它們執行簡單操作;它不是程式設計語言,甚至不是指令碼編製語言。但是,與 JSTL 標記一起使用時,它就能使用簡單而又方便的符號來表示複雜的行為。EL 運算式的格式是這樣的:用貨幣符號($)定界,內容包括在花括弧({})中,如清單 3 所示。


清單 3. 說明 EL 運算式定界符的 JSTL 操作
<c:out value="${user.firstName}"/>


此外,您可以將多個運算式與靜態文本組合在一起以通過字串共置來構造動態屬性值,如清單 4 所示。單獨的運算式由標識符、存取器、文字和運算子組成。標識符用來引用儲存在資料中心中的資料對象。EL 有 11 個保留標識符,對應於 11 個 EL 隱式對象。假定所有其它標識符都引用 限制了範圍的變數。存取器用來檢索對象的特性或集合的元素。文字表示固定的值 ― 數字、字元、字串、布爾型或空值。運算子允許對資料和文字進行組合以及比較。


清單 4. 組合靜態文本和多個 EL 運算式以指定動態屬性值
<c:out value="Hello ${user.firstName} ${user.lastName}"/>


 回頁首
 

限制了範圍的變數

JSP API 通過 <jsp:useBean> 操作允許從 JSP 容器內的四個不同範圍中儲存和檢索資料。JSTL 通過提供用於指定和除去這些範圍中的對象的附加操作來擴充這一能力。此外,EL 提供將這些對象作為限制了範圍的變數進行檢索的內建支援。特別地,任何出現在 EL 運算式中但不對應於任何 EL 隱式對象的標識符,都被自動假定為引用儲存在四個 JSP 範圍的其中某個中的對象,這四個範圍是:

頁面範圍
請求範圍
會話範圍
Application 領域
您可能還記得,只有在為特定請求處理頁面期間才能檢索儲存在該頁面範圍中的對象。如果對象是儲存在請求範圍中的,可以在處理所有參與處理某請求的頁面期間檢索這些對象(譬如在對某個請求的處理中遇到了一個或多個 <jsp:include> 或 <jsp:forward> 操作)。如果對象是儲存在會話範圍中的,則在與 Web 應用程式的互動式會話期間,可以由使用者訪問的任何頁面檢索它(即,直到與該使用者互動相關聯的 HttpSession 對象無效為止)。可以由任何使用者從任何頁面訪問儲存在Application 領域中的對象,直到卸載 Web 應用程式本身為止(通常是由於關閉 JSP 容器所致)。

通過將字串映射為期望範圍中的對象來將Object Storage Service到該範圍。然後,就可以通過提供相同字串來從該範圍檢索該對象。在範圍的映射中尋找字串,並返回被映射的對象。在 Servlet API 中,將此類對象稱為相應範圍的 屬性。但是,在 EL 的上下文中,也將與屬性相關聯的字串看作變數的名稱,該變數通過屬性對應的方式獲得特定的值。

在 EL 中,與隱式對象無關聯的標識符被認為是儲存在四個 JSP 範圍中的名稱對象。首先對頁面範圍檢查是否存在這樣的標識符,其次對請求範圍、然後對會話範圍、最後對Application 領域依次進行這樣的檢查,然後測試該標識符的名稱是否與儲存在該範圍中的某個對象的名稱匹配。第一個這樣的匹配作為 EL 標識符的值被返回。通過這種方法,可以將 EL 標識符看作引用限制了範圍的變數。

從更技術的方面來說,沒有映射到隱式對象的標識符是用 PageContext 執行個體的 findAttribute() 方法求值的,該執行個體表示對頁面的處理,在該頁面上,當前正在處理用於請求的運算式。標識符的名稱作為參數傳遞給這個方法,然後該方法依次在四個範圍中搜尋具有相同名稱的屬性。並將所找到的第一個匹配項作為 findAttribute() 方法的值返回。如果未在這四個範圍中找到這樣的屬性,則返回 null 。

最終,限制了範圍的變數是四個 JSP 範圍的屬性,這些屬性具有可以用作 EL 標識符的名稱。只要對限制了範圍的變數賦予由字母數字組成的名稱,就可以通過 JSP 中提供的用於設定屬性的任何機制來建立它們。這包括內建的 <jsp:useBean> 操作,以及由 Servlet API 中的幾個類定義的 setAttribute() 方法。此外,四個 JSTL 庫中定義的許多定製標記本身就能夠設定作為限制了範圍的變數使用的屬性值。


 回頁首
 

隱式對象

表 1 中列出了 11 個 EL 隱式對象的標識符。不要將這些對象與 JSP 隱式對象(一共只有九個)混淆,其中只有一個對象是它們所共有的。

表 1. EL 隱式對象

類別  標識符  描述 
JSP pageContext  PageContext 執行個體對應於當前頁面的處理 
範圍 pageScope  與頁面範圍屬性的名稱和值相關聯的 Map 類 
requestScope  與請求範圍屬性的名稱和值相關聯的 Map 類 
sessionScope  與會話範圍屬性的名稱和值相關聯的 Map 類 
applicationScope  與Application 領域屬性的名稱和值相關聯的 Map 類 
請求參數 param  按名稱儲存請求參數的主要值的 Map 類 
paramValues  將請求參數的所有值作為 String 數組儲存的 Map 類 
要求標頭 header  按名稱儲存要求標頭主要值的 Map 類 
headerValues  將要求標頭的所有值作為 String 數組儲存的 Map 類 
Cookie cookie  按名稱儲存請求附帶的 cookie 的 Map 類 
初始化參數 initParam  按名稱儲存 Web 應用程式上下文初始化參數的 Map 類 


儘管 JSP 和 EL 隱式對象中只有一個公用對象( pageContext ),但通過 EL 也可以訪問其它 JSP 隱式對象。原因是 pageContext 擁有訪問所有其它八個 JSP 隱式對象的特性。實際上,這是將它包括在 EL 隱式對象中的主要理由。

其餘所有 EL 隱式對象都是映射,可以用來尋找對應於名稱的對象。前四個映射表示先前討論的各種屬性範圍。可以用它們來尋找特定範圍中的標識符,而不用依賴於 EL 在預設情況下使用的順序尋找過程。

接下來的四個映射用來擷取請求參數和要求標頭的值。因為 HTTP 協議允許請求參數和要求標頭具有多個值,所以它們各有一對映射。每對中的第一個映射返回請求參數或頭的主要值,通常是恰巧在實際請求中首先指定的那個值。每對中第二個映射允許檢索參數或頭的所有值。這些映射中的鍵是參數或頭的名稱,但這些值是 String 對象的數組,其中的每個元素都是單一參數值或頭值。

cookie 隱式對象提供了對由請求設定的 cookie 名稱的訪問。這個對象將所有與請求相關聯的 cookie 名稱映射到表示那些 cookie 特性的 Cookie 對象。

最後一個 EL 隱式對象 initParam 是一個映射,它儲存與 Web 應用程式相關聯的所有內容相關的初始化參數的名稱和值。初始化參數是通過 web.xml 部署描述符檔案指定的,該檔案位於應用程式的 WEB-INF 目錄中。


 回頁首
 

存取器

因為 EL 標識符是作為隱式對象或限制了範圍的變數(通過屬性來實現)解析的,因此有必要將它們轉換成 Java 對象。EL 可以自動封裝和解包其相應的 Java 類中的基本類型(例如,可以在後台將 int 強制轉換成 Integer 類,反之亦可),但大多數的標識符將成為指向完整的 Java 對象的指標。

結果是,對這些對象的特性或(在對象是數組和集合的情況下)對其元素的訪問通常是令人滿意的。就為了實現這種用途,EL 提供了兩種不同的存取器(點運算子( . )和方括弧運算子( [] )),也支援通過 EL 操作特性和元素。

點運算子通常用於訪問對象的特性。例如,在運算式 ${user.firstName} 中,使用點運算子來訪問 user 標識符所引用對象的名為 firstName 的特性。EL 使用 Java bean 約定訪問對象特性,因此必須定義這個特性的 getter 方法(通常是名為 getFirstName() 的方法),以便運算式正確求值。當被訪問的特性本身是對象時,可以遞迴地應用點運算子。例如,如果我們虛構的 user 對象有一個實現為 Java 對象的 address 特性,那麼也可以用點運算子來訪問這個對象的特性。例如,運算式 ${user.address.city} 將會返回這個地址對象嵌套的 city 特性。

方括弧運算子用來檢索數組和集合的元素。在數組和有序集合(也即,實現了 java.util.List 介面的集合)的情況下,把要檢索的元素的下標放在方括弧中。例如,運算式 ${urls[3]} 返回 urls 標識符所引用的數組或集合的第四個元素(和 Java 語言以及 JavaScript 中一樣,EL 中的下標是從零開始的)。

對於實現 java.util.Map 介面的集合,方括弧運算子使用關聯的鍵尋找儲存在映射中的值。在方括弧中指定鍵,並將相應的值作為運算式的值返回。例如,運算式 ${commands["dir"]} 返回與 commands 標識符所引用的 Map 中的 "dir" 鍵相關聯的值。

對於上述兩種情況,都可允許運算式出現在方括弧中。對巢狀表格達式求值的結果將被作為下標或鍵,用來檢索集合或數組的適當元素。和點運算子一樣,方括弧運算子也可以遞迴應用。這使得 EL 能夠從多維陣列、嵌套集合或兩者的任意組合中檢索元素。此外,點運算子和方括弧運算子還可以互操作。例如,如果數組的元素本身是對象,則可以使用方括弧運算子來檢索該數組的元素,並結合點運算子來檢索該元素的一個特性(例如 ${urls[3].protocol} )。

假定 EL 充當指定動態屬性值的簡化語言,EL 存取器有一個有趣的功能(與 Java 語言的存取器不同),那就是它們在應用於 null 時不拋出異常。如果應用 EL 存取器的對象(例如, ${foo.bar} 和 ${foo["bar"]} 中的 foo 標識符)是 null ,那麼應用存取器的結果也是 null 。事實證明,在大多數情況下,這是一個相當有用的行為,不久您就會瞭解這一點。

最後,點運算子和方括弧運算子可能實現某種程度的互換。例如,也可以使用 ${user["firstName"]} 來檢索 user 對象的 firstName 特性,正如可以用 ${commands.dir} 擷取與 commands 映射中的 "dir" 鍵相關聯的值一樣。


 回頁首
 

運算子

EL 還可以通過使用標識符和存取器,遍曆包含應用程式資料(通過限制了範圍的變數公開)或關於環境的資訊(通過 EL 隱式對象)的對象階層。但是,只是訪問這些資料,通常不足以實現許多 JSP 應用程式所需的表示邏輯。

最終,EL 還包括了幾個用來操作和比較 EL 運算式所訪問資料的運算子。表 2 中匯總了這些運算子。

表 2. EL 運算子

類別  運算子 
算術運算子 + 、 - 、 * 、 / (或 div )和 % (或 mod ) 
關係運算子 == (或 eq )、 != (或 ne )、 < (或 lt )、 > (或 gt )、 <= (或 le )和 >= (或 ge ) 
邏輯運算子 && (或 and )、 || (或 or )和 ! (或 not ) 
驗證運算子 empty 


算術運算子支援數值的加法、減法、乘法和除法。還提供了一個求餘運算子。註:除法和求餘運算子都有替代的、非符號的名稱(為的是與 XPath 保持一致)。清單 5 中顯示了一個示範算術運算子用法的樣本運算式。對幾個 EL 運算式應用算術運算子的結果是將該算術運算子應用於這些運算式返回的數值所得的結果。


清單 5. 利用算術運算子的 EL 運算式
${item.price * (1 + taxRate[user.address.zipcode])}


關係運算子允許比較數字或文本資料。比較的結果作為布爾值返回。邏輯運算子允許合并布爾值,返回新的布爾值。因此,可以將 EL 邏輯運算子應用於嵌套的關係或邏輯運算子的結果,如清單 6 所示。


清單 6. 利用關係和邏輯運算子的 EL 運算式
${(x >= min) && (x <= max)}


最後一種 EL 運算子是 empty ,它對於驗證資料特別有用。 empty 運算子採用單個運算式作為其變數(也即, ${empty input} ),並返回一個布爾值,該布爾值表示對錶達式求值的結果是不是“空”值。求值結果為 null 的運算式被認為是空,即無元素的集合或數組。如果參數是對長度為零的 String 求值所得的結果,則 empty 運算子也將返回 true 。

表 3 顯示了 EL 運算子的優先順序。正如清單 5 和 6 所示,可以用圓括弧對錶達式分組,高於普通的優先順序規則。

表 3. EL 運算子優先順序(自頂到底,從左至右)

[] , . 
() 
unary - 、 not 、 ! 、 empty 
* 、 / 、 div 、 % 、 mod 
+ 、binary - 
() <</code> 、 > 、 <= 、 >= 、 lt 、 gt 、 le 、 ge 
== 、 != 、 eq 、 ne 
&& 、 and 
|| 、 or 


 


 回頁首
 

文字

在 EL 運算式中,數字、字串、布爾值和 null 都可以被指定為文字值。字串可以用單引號或雙引號定界。布爾值被指定為 true 和 false 。


 回頁首
 

Taglib 偽指令

正如我們先前討論的,JSTL 1.0 包括四個定製標記庫。為了示範 JSTL 標記和運算式語言的互動,我們將研究幾個來自 JSTL core 庫的標記。和使用任何 JSP 定製標記庫一樣,必須在您想要使用這個庫標記的任何頁面中包括 taglib 偽指令。清單 7 顯示了用於這個特定庫的偽指令。


清單 7. 用於 JSTL core 庫 EL 版本的 taglib 偽指令
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>


實際上,對應於 JSTL core 庫的 taglib 偽指令有兩種,因為在 JSTL 1.0 中,EL 是可選的。所有四個 JSTL 1.0 定製標記庫都有使用 JSP 運算式(而不是 EL)指定動態屬性值的備用版本。因為這些備用庫依賴於 JSP 的更傳統的請求時屬性值,所以它們被稱為 RT庫,而那些使用運算式語言的則被稱為 EL 庫。開發人員用不同的 taglib 偽指令來區分每個庫的這兩個版本。清單 8 顯示了使用 core 庫的 RT 版本的偽指令。但是,由於現在我們討論的重點是 EL,所以首先需要這些偽指令。


清單 8. 用於 JSTL core 庫 RT 版本的 taglib 偽指令
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>


 回頁首
 

變數標記

我們首先要考慮的 JSTL 定製標記是 <c:set> 操作。正如已經說明的,限制了範圍的變數在 JSTL 中起關鍵作用, <c:set> 操作提供基於標記的機制來建立和設定限制了範圍的變數。清單 9 中顯示了該操作的文法,其中 var 屬性指定了限制了範圍的變數的名稱, scope 屬性工作表明了該變數駐留在哪個範圍中, value 屬性指定了分配給該變數的值。如果指定變數已經存在,則簡單地將所指明的值賦給它。如果不存在,則建立新的限制了範圍的變數,並用該值初始化這個變數。


清單 9. <c:set> 操作的文法
<c:set var="
        name" scope="
        scope" value="
        expression"/>

     
 


scope 屬性是可選的,其預設值是 page 。

清單 10 中顯示了 <c:set> 的兩個樣本。在第一個樣本中,將會話範圍變數設定成 String 值。在第二個樣本中,用運算式來設定數值:將頁面範圍內名為 square 的變數賦值為名為 x 的請求參數的值的平方。


清單 10. <c:set> 操作樣本
<c:set var="timezone" scope="session" value="CST"/>
<c:set var="square" value="${param['x'] * param['x']}"/>


您還可以將限制了範圍的變數的值指定為 <c:set> 操作的主體內容,而不是使用屬性。使用這種方法,您可以重新編寫清單 10 中的第一個樣本,如清單 11 所示。此外,正如我們馬上可以看到的, <c:set> 標記的主體內容本身也可以使用定製標記。 <c:set> 主體內產生的所有內容都將作為一個 String 值賦給指定變數。


清單 11. 通過主體內容指定 <c:set> 操作的值
<c:set var="timezone" scope="session">CST</c:set>


JSTL core 庫包含第二個用於管理限制了範圍的變數的標記 ― <c:remove> 。顧名思義, <c:remove> 操作是用來刪除限制了範圍的變數的,它擷取兩個屬性。 var 屬性指定待刪除變數的名稱, scope 屬性是可選的,它表示待刪除變數來自哪個範圍,預設為 page ,如清單 12 所示。

清單 12. <c:remove> 操作樣本 <c:remove var="timezone" scope="session"/>


 回頁首
 

輸出

儘管 <c:set> 操作允許將運算式結果賦給限制了範圍的變數,但開發人員通常會希望只顯示運算式的值,而不儲存它。JSTL <c:out> 定製標記承擔這一任務,其文法如清單 13 所示。該標記對由其 value 屬性指定的運算式進行求值,然後列印結果。如果指定了可選屬性 default ,那麼,在對 value 屬性的運算式求值所得結果為 null 或空 String 的情況下, <c:out> 將列印其值。


清單 13. <c:out> 操作的文法
<c:out value="
        expression" default="
        expression" escapeXml="
        boolean"/>

     
 


escapeXml 屬性也是可選的。它控制當用 <c:out> 標記輸出諸如“<”、“>”和“&”之類的字元(在 HTML 和 XML 中具有特殊意義)時是否應該進行轉義。如果將 escapeXml 設定為 true,則會自動將這些字元轉換成相應的 XML 實體(此處提到的字元分別轉換成 < 、 > 和 & )。

例如,假定有一個名為 user 的會話範圍變數,它是一個類的執行個體,該類為使用者定義了兩個特性: username 和 company 。每當使用者訪問網站時,這個對象被自動分配給會話,但直到使用者實際登入後,才會設定這兩個特性。假定是這種方案,請考慮清單 14 中的 JSP 片段。在使用者登入之後,這個片段將顯示單詞“Hello”,其後是他/她的使用者名稱和一個驚歎號。但是,在使用者登入之前,由這個片段產生的內容則是短語“Hello Guest!”。在這種情況下,因為 username 特性還有待初始化,所以 <c:out> 標記將轉而列印出 default 屬性的值(即字串“Guest”)。


清單 14. 帶預設內容的 <c:out> 操作樣本
Hello <c:out value="${user.username}" default=="Guest"/>!


接下來,考慮清單 15,它使用了 <c:out> 標記的 escapeXml 屬性。如果在這種情況下已經將 company 特性設定成 Java String 值 "Flynn & Sons" ,那麼,實際上該操作產生的內容將是 Flynn & Sons 。如果這個操作是產生 HTML 或 XML 內容的 JSP 頁面的一部分,那麼,這個字串中間的“&”符號最終可能被解釋為 HTML 或 XML 控制字元,從而妨礙了對該內容的顯示或解析。但是,如果將 escapeXml 屬性值設定成 true ,則所產生的內容將是 Flynn & Sons 。瀏覽器或解析器不會因在解釋時遇到這種內容而出問題。假定 HTML 和 XML 是 JSP 應用程式中最常見的內容類型,所以 escapeXml 屬性的預設值是 true 就不足為奇了。


清單 15. 禁用轉義的 <c:out> 操作樣本
<c:out value="${user.company}" escapeXml=="false"/>


 回頁首
 

用預設值設定變數

除了簡化動態資料的顯示之外,當通過 <c:set> 設定變數值時, <c:out> 指定預設值的能力也很有用。正如 清單 11 所示,用來賦給限制了範圍的變數的值可以指定為 <c:set> 標記的主體內容,也可以通過其值屬性來指定。通過將 <c:out> 操作嵌套在 <c:set> 標記的主體內容中,變數賦值就可以利用其預設值能力。

清單 16 中說明了這種方法。外部 <c:set> 標記的行為非常簡單:它根據其主體內容設定會話範圍 timezone 變數的值。但是,在這種情況下,主體內容是通過 <c:out> 操作產生的。這個嵌套操作的值屬性是運算式 ${cookie['tzPref'].value} ,它嘗試通過 cookie 隱式對象返回名為 tzPref 的 cookie 值。( cookie 隱式對象將 cookie 名稱映射到相應的 Cookie 執行個體,這意味著必須通過對象的 value 特性使用點運算子來檢索儲存在 cookie 中的實際資料。)


清單 16. 合并 <c:set> 和 <c:out> 以提供預設變數值
<c:set var="timezone" scope=="session">
   <c:out value="${cookie['tzPref'].value}" default=="CST"/>
</c:set>


但是,請考慮以下情況,使用者是第一次嘗試使用這段代碼的 Web 應用程式。結果是,請求中沒有提供名為 tzPref 的 cookie。這意味著使用隱式對象的尋找將返回 null ,在這種情況下整個運算式將返回 null 。因為對 <c:out> 標記的 value 屬性求值的結果是 null ,所以 <c:out> 標記會轉而輸出對其 default 屬性求值的結果。在這裡是字串 CST 。因此,實際的結果是將 timezone 限制了範圍的變數設定成使用者的 tzPref cookie 中儲存的時區,或者,如果沒有,則使用預設時區 CST 。

 EL 和 JSP 2.0

目前,運算式語言僅可用於指定 JSTL 定製標記中的動態屬性值。但 JSTL 1.0 運算式語言的一個擴充已經被提出,會把它包括到 JSP 2.0 中去,眼下進行中最後評審。這個擴充將允許開發人員通過自己的定製標記來使用 EL。頁面作者將可以在目前允許使用 JSP 運算式的任何地方使用 EL 運算式,譬如將動態值插入模板文本中: <p>Your preferred time zone is ${timezone}</p> 。

這個 JSP 2.0 功能(就象 JSTL 本身一樣)將支援頁面作者進一步減少對 JSP 編製指令碼元素的依賴,從而改進 JSP 應用程式的可維護性。
 
 


 


 回頁首
 

結束語

EL(與四個 JSTL 定製標記庫提供的操作結合起來)允許頁面作者不使用指令碼元素即可實現展示層邏輯。例如,對比本文開頭 清單 1 中的 JSP 代碼和清單 17 中顯示的通過 JSTL 實現的同樣功能。(JSTL core 庫中其餘的標記,包括 <c:choose> 及其子標記,將在本系列的下一篇文章中討論。)儘管顯然執行了條件邏輯,但是 JSTL 版本中沒有 Java 語言原始碼,並且標記之間的關係(尤其是關於嵌套需求)對於任何精通 HTML 文法的人都應該是熟悉的。


清單 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>
 


通過提供大多數 Web 應用程式常用功能的標準實現,JSTL 有助於加速開發週期。與 EL 結合起來,JSTL 可以不需要對錶示層程式編寫代碼,這極大地簡化了 JSP 應用程式的維護。


 回頁首
 

參考資料

您可以參閱本文在 developerWorks 全球網站上的 英文原文.


Sun 的 JSP 標準標記庫首頁是瞭解關於 JSTL 的更多資訊的良好起點。

JSTL 1.0 規範是關於 EL 和四個 JSTL 標記庫的最終權威文本。

Jakarta Taglibs項目是 JSTL 1.0 參考實現的起源。

Shawn Bayern 所著的 JSTL in Action (Manning Publications Co.,2002 年)提供了對所有 JSTL 功能的精彩論述,作者是該參考實現的領導。

David Geary 是 Java 技術方面很受歡迎的作者,他也寫了一本關於 JSTL 的書,書名是 Core JSTL 。

JSPTags.com是 JSP 技術參考資料的目錄,它尤其專註於定製標記庫。

Sun 的 Java Web Services Tutorial中包含了對 JSTL 的討論。

“ Using JSPs and custom tags within VisualAge for Java and WebSphere Studio”( WebSphere 開發人員園地)是一篇 WBOnline 實用論文,它示範了 servlet、JSP 和定製標記庫的使用。

通過 Jeff Wilson 精彩的文章“ 使用定製標記控制 JSP 頁面”( developerWorks,2002 年 1 月)瞭解關於定製標記庫的一切。

Noel Bergman 的文章“ JSP 標記庫:著意設計的更好的可用性”( developerWorks,2001 年 12 月)向您展示了聲明性標記是如何協助提高 JSP 頁面的可用性的。

有關 EcmaScript 的更多詳細資料,請參閱 Sing Li 的“ 快速上手 Java 編程”( developerWorks,2001 年 7 月)。

在 developerWorksJava 技術專區 可以找到多達數百篇的 Java 技術參考資料。


 回頁首
 

關於作者

  Mark Kolb 是一名在德克薩斯州奧斯汀工作的軟體工程師。他經常就伺服器端 Java 主題在業界發表演講,並且與人合著了 Web Development with JavaServer Pages,第二版 一書。可通過 mak@taglib.com與 Mark 聯絡。
 



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。