<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kapok

    垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks
    http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html

    使用定制標(biāo)記進行流控制和 URL 管理

    Mark A. Kolb
    軟件工程師
    2003 年 6 月 21 日

    顧名思義,JSP 標(biāo)準(zhǔn)標(biāo)記庫(JSP Standard Tag Library,JSTL) core 庫為一些基本功能(如,管理限定了作用域的變量和與 URL 交互等)和基本操作(如,迭代和條件化)提供了定制標(biāo)記。這些標(biāo)記不僅可以由頁面設(shè)計人員直接利用,而且還為與其它 JSTL 庫相結(jié)合從而提供更復(fù)雜的表示邏輯奠定了基礎(chǔ)。Mark Kolb 在本文中繼續(xù)對 JSTL 和 core 庫進行探討,研究用標(biāo)記來協(xié)助流控制和 URL 管理。

    通過閱讀本系列的 第一篇文章,您對 JSTL 有了初步的了解。我們描述了使用其 表達式語言(EL)來訪問數(shù)據(jù)和操作數(shù)據(jù)。正如您所了解的那樣,EL 用來為 JSTL 定制標(biāo)記的屬性賦予動態(tài)值,因此,它所起的作用與 JSP 表達式一樣,為內(nèi)置操作及其它定制標(biāo)記庫指定請求時的屬性值。

    為了演示 EL 的用法,我們介紹了 core 庫中的三個標(biāo)記: <c:set><c:remove><c:out><c:set><c:remove> 用于管理限定了作用域的變量;而 <c:out> 用于顯示數(shù)據(jù),尤其是顯示用 EL 計算出的值。在此基礎(chǔ)上,接下來本文把注意力集中在 core 庫的其余標(biāo)記上,這些標(biāo)記可以大致歸為兩大類別:流控制和 URL 管理。

    示例應(yīng)用程序
    為了演示 JSTL 標(biāo)記,我們將使用來自一個工作應(yīng)用程序的示例,本系列中余下的文章都將使用此應(yīng)用程序。由于基于 Java 的 Weblog 日漸流行及為人們所熟悉,因此我們將出于此目的使用一個簡單的基于 Java 的 Weblog;參閱 參考資料以下載該應(yīng)用程序的 JSP 頁面和源代碼。Weblog(也稱為 blog)是一種基于 Web 的簡短注釋的日志,這些注釋是有關(guān) Weblog 的作者所感興趣的主題,通常帶有與 Web 上其它地方的相關(guān)文章及討論的鏈接。圖 1 中顯示了該應(yīng)用程序正在運行時的抓屏。

    圖 1. Weblog 應(yīng)用程序
    Weblog 示例應(yīng)用程序的抓屏

    雖然完整的實現(xiàn)需要二十四個 Java 類,但在表示層中卻只涉及 Weblog 應(yīng)用程序中的兩個類, EntryUserBean 。這樣,對于理解 JSTL 示例而言,只有這兩個類比較重要。圖 2 顯示了 EntryUserBean 的類圖。

    圖 2. Weblog 應(yīng)用程序的類圖
    Weblog 示例應(yīng)用程序的類圖

    Entry 類表示 Weblog 中一個標(biāo)有日期的項。其 id 屬性用于在數(shù)據(jù)庫中存儲及檢索該項,而 titletext 屬性則表示該項的實際內(nèi)容。 createdlastModified 屬性引用了 Java 語言中 Date 類的兩個實例,分別用來表示最初創(chuàng)建該項的時間和最后編輯該項的時間。 author 屬性引用了標(biāo)識該項的創(chuàng)建者的 UserBean 實例。

    UserBean 類存儲了有關(guān)應(yīng)用程序的已認(rèn)證用戶的信息,如用戶名、全名和電子郵件地址。該類還包含一個用于與相關(guān)數(shù)據(jù)庫進行交互的 id 屬性。其最后一個屬性 roles 引用一列 String 值,這列值標(biāo)識與相應(yīng)用戶相關(guān)的、特定于應(yīng)用程序的角色。對于 Weblog 應(yīng)用程序,相關(guān)的角色是“User”(所有應(yīng)用程序用戶常用的缺省角色)和“Author”(該角色指定可以創(chuàng)建和編輯 Weblog 項的用戶)。

    流控制
    由于可以用 EL 替代 JSP 表達式來指定動態(tài)屬性值,因此頁面創(chuàng)作人員無需使用腳本編制元素。因為腳本編制元素可能是引起 JSP 頁面中維護問題的主要原因,所以 JSTL 的主要優(yōu)點就在于提供了這樣簡單(且標(biāo)準(zhǔn))的替代方法。

    EL 從 JSP 容器檢索數(shù)據(jù),遍歷對象層次結(jié)構(gòu),然后對結(jié)果執(zhí)行簡單的操作。不過,除了訪問和操作數(shù)據(jù)之外,JSP 腳本編制元素的另一個常見用法是流控制。尤其是,頁面創(chuàng)作人員常借助 scriptlet 來實現(xiàn)迭代或條件內(nèi)容。然而,因為這樣的操作超出了 EL 的能力,所以 core 庫提供了幾個定制操作來管理流控制,其形式有 迭代條件化異常處理

    迭代
    在 Web 應(yīng)用程序環(huán)境中,迭代主要用于訪存和顯示數(shù)據(jù)集,通常是以列表或表中的一系列行的形式顯示。實現(xiàn)迭代內(nèi)容的主要 JSTL 操作是 <c:forEach> 定制標(biāo)記。該標(biāo)記支持兩種不同樣式的迭代:整數(shù)范圍上的迭代(類似 Java 語言的 for 語句)和集合上的迭代(類似 Java 語言的 IteratorEnumeration 類)。

    進行整數(shù)范圍迭代用到了清單 1 中所示的 <c:forEach> 標(biāo)記的語法。 beginend 屬性要么是靜態(tài)整數(shù)值,要么是可以得出整數(shù)值的表達式。它們分別指定迭代索引的初始值以及迭代索引的終止值。當(dāng)使用 <c:forEach> 在整數(shù)范圍內(nèi)進行迭代時,這兩個屬性是必需的,而其它所有屬性都是可選的。

    清單 1. 通過 <c:forEach> 操作進行數(shù)字迭代的語法
    <c:forEach var="
            name" varStatus="
            name"
        begin="
            expression" end="
            expression" step="
            expression">
      
            body content
    </c:forEach>
    
          

    當(dāng)出現(xiàn) step 時,它也必須是整數(shù)值。它指定每次迭代后索引的增量。這樣,迭代索引從 begin 屬性的值開始,以 step 屬性的值為增量進行遞增,在迭代索引超過 end 屬性的值時停止迭代。注:如果省略了 step 屬性,那么步長缺省為 1。

    如果指定了 var 屬性,那么將會創(chuàng)建一個帶有指定名稱的并限定了作用域的變量,并將每次迭代的當(dāng)前索引值賦給該變量。這一限定了作用域的變量具有嵌套式可視性 ― 只可以在 <c:forEach> 標(biāo)記體內(nèi)對其進行訪問。(我們很快將討論可選屬性 varStatus 的用法。)清單 2 顯示了對一組固定整數(shù)值進行迭代的 <c:forEach> 操作示例。

    清單 2. 使用 <c:forEach> 標(biāo)記來生成表列數(shù)據(jù),這些數(shù)據(jù)對應(yīng)于某一范圍內(nèi)的數(shù)值
    <table>
    <tr><th>Value</th>
        <th>Square</th></tr>
    <c:forEach var="x" begin="0" end="10" step="2">
      <tr><td><c:out value="${x}"/></td>
          <td><c:out value="${x * x}"/></td></tr>
    </c:forEach>
    </table>
    

    如圖 3 中所示,上面的示例代碼生成了一張表,顯示前五個偶數(shù)及其平方。這是通過將 beginstep 屬性值指定為 2,而將 end 屬性值指定為 10 實現(xiàn)的。此外,用 var 屬性創(chuàng)建用于存儲索引值的限定了作用域的變量, <c:forEach> 標(biāo)記體內(nèi)引用了該變量。尤其是,使用了一對 <c:out> 操作來顯示索引及其平方,其中索引的平方是使用一個簡單的表達式計算得來的。

    圖 3. 清單 2 的輸出
    清單 2 的輸出

    在對集合的成員進行迭代時,用到了 <c:forEach> 標(biāo)記的另一個屬性: items 屬性,清單 3 中顯示了該屬性。當(dāng)使用這種形式的 <c:forEach> 標(biāo)記時, items 屬性是唯一必需的屬性。 items 屬性的值應(yīng)該是一個集合,對該集合的成員進行迭代,通常使用 EL 表達式指定值。如果變量名稱是通過 <c:forEach> 標(biāo)記的 item 屬性指定的,那么對于每次迭代該已命名變量都將被綁定到集合后續(xù)元素上。

    清單 3. 通過 <c:forEach> 操作對集合進行迭代的語法
    <c:forEach var="
            name" items="
            expression" varStatus="
            name"
        begin="
            expression" end="
            expression" step="
            expression">
      
            body content
    </c:forEach>
    
          

    <c:forEach> 標(biāo)記支持 Java 平臺所提供的所有標(biāo)準(zhǔn)集合類型。此外,您可以使用該操作來迭代數(shù)組(包括基本類型數(shù)組)中的元素。表 1 列出了 items 屬性所支持的所有值。正如表的最后一行所指出的那樣,JSTL 定義了它自己的接口 javax.servlet.jsp.jstl.sql.Result ,用來迭代 SQL 查詢的結(jié)果。(我們將在本系列后面的文章中詳細討論這一功能。)

    表 1. <c:forEach> 標(biāo)記的 items 屬性所支持的集合
    items 的值 所產(chǎn)生的 item
    java.util.Collection 調(diào)用 iterator() 所獲得的元素
    java.util.Map java.util.Map.Entry 的實例
    java.util.Iterator 迭代器元素
    java.util.Enumeration 枚舉元素
    Object 實例數(shù)組 數(shù)組元素
    基本類型值數(shù)組 經(jīng)過包裝的數(shù)組元素
    用逗號定界的 String 子字符串
    javax.servlet.jsp.jstl.sql.Result SQL 查詢所獲得的行

    可以使用 beginendstep 屬性來限定在迭代中包含集合中哪些元素。和通過 <c:forEach> 進行數(shù)字迭代的情形一樣,在迭代集合中的元素時同樣要維護一個迭代索引。 <c:forEach> 標(biāo)記實際上只處理那些與索引值相對應(yīng)的元素,這些索引值與指定的 beginendstep 值相匹配。

    清單 4 顯示了用來迭代集合的 <c:forEach> 標(biāo)記。對于該 JSP 代碼段, entryList 這一限定了作用域的變量被設(shè)置成了 Entry 對象列表(確切的說, ArrayList )。 <c:forEach> 標(biāo)記依次處理列表中的每個元素,將其賦給一個限定了作用域的變量 blogEntry ,然后生成兩個表行 ― 一個用于 Weblog 項的 title ,另一個則用于該項 text 。這些特性是通過一對帶有相應(yīng) EL 表達式的 <c:out> 操作從 blogEntry 變量檢索得到的。注:由于 Weblog 項的標(biāo)題和文本都可能包含 HTML 標(biāo)記,因此這兩個 <c:out> 標(biāo)記的 escapeXml 屬性都被設(shè)置成了 false。圖 4 顯示了結(jié)果。

    清單 4. 使用 <c:forEach> 標(biāo)記顯示表示給定日期的 Weblog 項
    <table>
      <c:forEach items="${entryList}" var="blogEntry">
        <tr><td align="left" class="blogTitle">
          <c:out value="${blogEntry.title}" escapeXml="false"/>
        </td></tr>
        <tr><td align="left" class="blogText">
          <c:out value="${blogEntry.text}" escapeXml="false"/>
        </td></tr>
      </c:forEach>
    </table>
    

    圖 4. 清單 4 的輸出
    清單 4 的輸出

    不論是對整數(shù)還是對集合進行迭代, <c:forEach> 剩余的屬性 varStatus 所起的作用相同。和 var 屬性一樣, varStatus 用于創(chuàng)建限定了作用域的變量。不過,由 varStatus 屬性命名的變量并不存儲當(dāng)前索引值或當(dāng)前元素,而是賦予 javax.servlet.jsp.jstl.core.LoopTagStatus 類的實例。該類定義了一組特性,它們描述了迭代的當(dāng)前狀態(tài),表 2 中列出了這些特性。

    表 2. LoopTagStatus 對象的特性
    特性 Getter 描述
    current getCurrent() 當(dāng)前這次迭代的(集合中的)項
    index getIndex() 當(dāng)前這次迭代從 0 開始的迭代索引
    count getCount() 當(dāng)前這次迭代從 1 開始的迭代計數(shù)
    first isFirst() 用來表明當(dāng)前這輪迭代是否為第一次迭代的標(biāo)志
    last isLast() 用來表明當(dāng)前這輪迭代是否為最后一次迭代的標(biāo)志
    begin getBegin() begin 屬性值
    end getEnd() end 屬性值
    step getStep() step 屬性值

    清單 5 顯示了關(guān)于如何使用 varStatus 屬性的一個示例。這個示例修改了清單 4 中的代碼,將 Weblog 項的編號添加到顯示 Weblog 標(biāo)題(title)的表行。它是通過為 varStatus 屬性指定一個值,然后訪問所生成的限定了作用域的變量的 count 特性來實現(xiàn)這一點的。結(jié)果顯示在圖 5 中。

    清單 5. 使用 varStatus 屬性來顯示 Weblog 項的數(shù)目
    <table>
      <c:forEach items=
        "${entryList}" var="blogEntry" varStatus="status">
        <tr><td align="left" class="blogTitle">
          <c:out value="${status.count}"/>.
          <c:out value="${blogEntry.title}" escapeXml="false"/>
        </td></tr>
        <tr><td align="left" class="blogText">
          <c:out value="${blogEntry.text}" escapeXml="false"/>
        </td></tr>
      </c:forEach>
    </table>
    

    圖 5. 清單 5 的輸出
    清單 5 的輸出

    <c:forEach> 以外, core 庫還提供了另一個迭代標(biāo)記: <c:forTokens> 。JSTL 的這個定制操作與 Java 語言的 StringTokenizer 類的作用相似。清單 6 中顯示的 <c:forTokens> 標(biāo)記除了比 <c:forEach> 的面向集合版本多一個屬性之外,其它屬性都相同。對于 <c:forTokens> 而言,通過 items 屬性指定要標(biāo)記化的字符串,而通過 delims 屬性提供用于生成標(biāo)記的一組定界符。和 <c:forEach> 的情形一樣,可以使用 beginendstep 屬性將要處理的標(biāo)記限定為那些與相應(yīng)索引值相匹配的標(biāo)記。

    清單 6. 使用 <c:forTokens> 操作來迭代字符串標(biāo)記的語法
    <c:forTokens var="
            name" items="
            expression"
        delims="
            expression" varStatus="
            name"
        begin="
            expression" end="
            expression" step="
            expression">
      
            body content
    </c:forTokens>
    
          

    條件化
    對于包含動態(tài)內(nèi)容的 Web 頁面,您可能希望不同類別的用戶看到不同形式的內(nèi)容。例如,在我們的 Weblog 中,訪問者應(yīng)該能夠閱讀各項,也許還應(yīng)該能夠提交反饋,但只有經(jīng)過授權(quán)的用戶才能公布新項,或編輯已有內(nèi)容。

    在同一個 JSP 頁面內(nèi)實現(xiàn)這樣的功能,然后使用條件邏輯來根據(jù)每條請求控制所顯示的內(nèi)容,這樣做常常能夠改善實用性和軟件維護。 core 庫提供了兩個不同的條件化標(biāo)記 ― <c:if><c:choose> ― 來實現(xiàn)這些功能。

    <c:if> 是這兩個操作中較簡單的一個,它簡單地對單個測試表達式進行求值,接下來,僅當(dāng)對表達式求出的值為 true 時,它才處理標(biāo)記的主體內(nèi)容。如果求出的值不為 true ,就忽略該標(biāo)記的主體內(nèi)容。如清單 7 所示, <c:if> 可以通過其 varscope 屬性(它們所起的作用和在 <c:set> 中所起的作用一樣)選擇將測試結(jié)果賦給限定了作用域的變量。當(dāng)測試代價非常高昂時,這種能力尤為有用:可以將結(jié)果高速緩存在限定了作用域的變量中,然后在隨后對 <c:if> 或其它 JSTL 標(biāo)記的調(diào)用中檢索該結(jié)果。

    清單 7. <c:if> 條件操作的語法
    <c:if test="
            expression" var="
            name" scope="
            scope">
      
            body content
    </c:if>
    
          

    清單 8 顯示了與 <c:forEach> 標(biāo)記的 LoopTagStatus 對象的 first 特性一起使用的 <c:if> 。如圖 6 中所示,在這種情況下,只在 Weblog 項的第一項上顯示這組項的創(chuàng)建日期,而不在任何其它項前面重復(fù)該日期。

    清單 8. 使用 <c:if> 來為 Weblog 項顯示日期
    <table>
      <c:forEach items=
        "${entryList}" var="blogEntry" varStatus="status">
        <c:if test="${status.first}">
          <tr><td align="left" class="blogDate">
                <c:out value="${blogEntry.created}"/>
          </td></tr>
        </c:if>
        <tr><td align="left" class="blogTitle">
          <c:out value="${blogEntry.title}" escapeXml="false"/>
        </td></tr>
        <tr><td align="left" class="blogText">
          <c:out value="${blogEntry.text}" escapeXml="false"/>
        </td></tr>
      </c:forEach>
    </table>
    

    圖 6. 清單 8 的輸出
    清單 8 的輸出

    如清單 8 所示, <c:if> 標(biāo)記為條件化內(nèi)容的一些簡單情形提供了一種非常簡潔的表示法。對于需要進行互斥測試來確定應(yīng)該顯示什么內(nèi)容的情況下,JSTL core 庫還提供了 <c:choose> 操作。清單 9 中顯示了 <c:choose> 的語法。

    清單 9. <c:choose> 操作的語法
    <c:choose>
      <c:when test="
            expression">
        
            body content
      </c:when>
      ...
      <c:otherwise>
        
            body content
      </c:otherwise>
    </c:choose>
    
          

    每個要測試的條件都由相應(yīng)的 <c:when> 標(biāo)記來表示,至少要有一個 <c:when> 標(biāo)記。只會處理第一個其 test 值為 true<c:when> 標(biāo)記體內(nèi)的內(nèi)容。如果沒有一個 <c:when> 測試返回 true ,那么會處理 <c:otherwise> 標(biāo)記的主體內(nèi)容。注:盡管如此, <c:otherwise> 標(biāo)記卻是可選的; <c:choose> 標(biāo)記至多可有一個嵌套的 <c:otherwise> 標(biāo)記。如果所有 <c:when> 測試都為 false ,而且又沒有給出 <c:otherwise> 操作,那么不會處理任何 <c:choose> 標(biāo)記的主體內(nèi)容。

    清單 10 顯示了運用 <c:choose> 標(biāo)記的示例。在這里,檢索請求對象而獲得協(xié)議信息(通過 EL 的 pageContext 隱式對象),并用簡單的字符串比較對協(xié)議信息進行測試。根據(jù)這些測試的結(jié)果,會顯示相應(yīng)的文本消息。

    清單 10. 使用 <c:choose> 進行內(nèi)容條件化
    <c:choose>
      <c:when test="${pageContext.request.scheme eq 'http'}">
        This is an insecure Web session.
      </c:when>
      <c:when test="${pageContext.request.scheme eq 'https'}">
        This is a secure Web session.
      </c:when>
      <c:otherwise>
        You are using an unrecognized Web protocol. How did this happen?!
      </c:otherwise>
    </c:choose>
    

    異常處理
    最后一個流控制標(biāo)記是 <c:catch> ,它允許在 JSP 頁面內(nèi)進行初級的異常處理。更確切地說,在該標(biāo)記的主體內(nèi)容中產(chǎn)生的任何異常都會被捕獲并被忽略(即,不會調(diào)用標(biāo)準(zhǔn)的 JSP 錯誤處理機制)。然而,如果產(chǎn)生了一個異常并且已經(jīng)指定了 <c:catch> 標(biāo)記的可選屬性 var ,那么會將異常賦給(具有頁面作用域的)指定的變量,這使得能夠在頁面自身內(nèi)部進行定制錯誤處理。清單 11 顯示了 <c:catch> 的語法(稍后在 清單 18中給出一個示例)。

    清單 11. <c:catch> 操作的語法
    <c:catch var="
            name">
      
            body content
    </c:catch>
    
          

    URL 操作
    JSTL core 庫中的其余標(biāo)記主要是關(guān)于 URL。這些標(biāo)記中的第一個被適當(dāng)?shù)孛麨?<c:url> 標(biāo)記,用于生成 URL。尤其是, <c:url> 提供了三個功能元素,它們在為 J2EE Web 應(yīng)用程序構(gòu)造 URL 時特別有用:

    • 在前面附加當(dāng)前 servlet 上下文的名稱
    • 為會話管理重寫 URL
    • 請求參數(shù)名稱和值的 URL 編碼

    清單 12 顯示了 <c:url> 標(biāo)記的語法。 value 屬性用來指定基本 URL,然后在必要時標(biāo)記對其進行轉(zhuǎn)換。如果這個基本 URL 以一個斜杠開始,那么會在它前面加上 servlet 的上下文名稱。可以使用 context 屬性提供顯式的上下文名稱。如果省略該屬性,那么就使用當(dāng)前 servlet 上下文的名稱。這一點特別有用,因為 servlet 上下文名稱是在部署期間而不是開發(fā)期間決定的。(如果這個基本 URL 不是以斜杠開始的,那么就認(rèn)為它是一個相對 URL,這時就不必添加上下文名稱。)

    清單 12. <c:url> 操作的語法
    <c:url value="
            expression" context="
            expression"
        var="
            name" scope="
            scope">
      <c:param name="
            expression" value="
            expression"/>
      ...
    </c:url>
    
          

    URL 重寫是由 <c:url> 操作自動執(zhí)行的。如果 JSP 容器檢測到一個存儲用戶當(dāng)前會話標(biāo)識的 cookie,那么就不必進行重寫。但是,如果不存在這樣的 cookie,那么 <c:url> 生成的所有 URL 都會被重寫以編碼會話標(biāo)識。注:如果在隨后的請求中存在適當(dāng)?shù)?cookie,那么 <c:url> 將停止重寫 URL 以包含該標(biāo)識。

    如果為 var 屬性提供了一個值(還可以同時為 scope 屬性提供一個相應(yīng)的值,這是可選的),那么將生成的 URL 賦值給這個限定了作用域的指定變量。否則,將使用當(dāng)前的 JspWriter 輸出生成的 URL。這種直接輸出其結(jié)果的能力允許 <c:url> 標(biāo)記作為值出現(xiàn),例如,作為 HTML <a> 標(biāo)記的 href 屬性的值,如清單 13 中所示。

    清單 13. 生成 URL 作為 HTML 標(biāo)記的屬性值
    <a href="<c:url value='/content/sitemap.jsp'/>">View sitemap</a>
    

    最后,如果通過嵌套 <c:param> 標(biāo)記指定了任何請求參數(shù),那么將會使用 HTTP GET 請求的標(biāo)準(zhǔn)表示法將它們的名稱和值添加到生成的 URL 后面。此外,還進行 URL 編碼:為了生成有效的 URL,將對這些參數(shù)的名稱或值中出現(xiàn)的任何字符適當(dāng)?shù)剡M行轉(zhuǎn)換。清單 14 演示了 <c:url> 的這種行為。

    清單 14. 生成帶請求參數(shù)的 URL
    <c:url value="/content/search.jsp">
      <c:param name="keyword" value="${searchTerm}"/>
      <c:param name="month" value="02/2003"/>
    </c:url>
    

    清單 14 中的 JSP 代碼被部署到一個名為 blog 的 servlet 上下文,限定了作用域的變量 searchTerm 的值被設(shè)置為 "core library" 。如果檢測到了會話 cookie,那么清單 14 生成的 URL 將類似于清單 15 中的 URL。注:在前面添加上下文名稱,而在后面附加請求參數(shù)。此外, keyword 參數(shù)值中的空格和 month 參數(shù)值中的斜杠都被按照 HTTP GET 參數(shù)的需要進行了編碼(確切地說,空格被轉(zhuǎn)換成了 + ,而斜杠被轉(zhuǎn)換成了 %2F 序列)。

    清單 15. 有會話 cookie 時生成的 URL
    /blog/content/search.jsp?keyword=foo+bar&month=02%2F2003
    

    當(dāng)沒有會話 cookie 時,生成的結(jié)果如清單 16 中所示。同樣,servlet 上下文被添加到了前面,而 URL 編碼的請求參數(shù)被附加到了后面。不過,除此以外還重寫了基本 URL 以包含指定的會話標(biāo)識。當(dāng)瀏覽器發(fā)送用這種方式重寫的 URL 請求時,JSP 容器自動抽取會話標(biāo)識,并將請求與相應(yīng)的會話進行關(guān)聯(lián)。這樣,需要會話管理的 J2EE 應(yīng)用程序就無需依賴由應(yīng)用程序用戶啟用的 cookie 了。

    清單 16. 沒有會話 cookie 時生成的 URL
    /blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290
      ?keyword=foo+bar&month=02%2F2003
    

    導(dǎo)入內(nèi)容
    JSP 有兩種內(nèi)置機制可以將來自不同 URL 的內(nèi)容合并到一個 JSP 頁面: include 偽指令和 <jsp:include> 操作。不過,不管是哪種機制,要包含的內(nèi)容都必須屬于與頁面本身相同的 Web 應(yīng)用程序(或 servlet 上下文)。兩個標(biāo)記之間的主要區(qū)別在于: include 偽指令在頁面編譯期間合并被包含的內(nèi)容,而 <jsp:include> 操作卻在請求處理 JSP 頁面時進行。

    從本質(zhì)上講, core 庫的 <c:import> 操作是更通用、功能更強大的 <jsp:include> 版本(好像是 <jsp:include> “服用了興奮劑”的)。和 <jsp:include> 一樣, <c:import> 也是一種請求時操作,它的基本任務(wù)就是將其它一些 Web 資源的內(nèi)容插入 JSP 頁面中。如清單 17 中所示,它的語法非常類似于 <c:url> 的語法。

    清單 17. <c:import> 操作的語法
    <c:import url="
            expression" context="
            expression"
        charEncoding="
            expression" var="
            name" scope="
            scope">
      <c:param name="
            expression" value="
            expression"/>
      ...
    </c:import>
    
          

    通過 url 屬性指定將要導(dǎo)入內(nèi)容的 URL,這個屬性是 <c:import> 的唯一一個必選屬性。這里允許使用相對 URL,并且根據(jù)當(dāng)前頁面的 URL 來解析這個相對 URL。但是,如果 url 屬性的值以斜杠開始,那么它就被解釋成本地 JSP 容器內(nèi)的絕對 URL。如果沒有為 context 屬性指定值,那么就認(rèn)為這樣的絕對 URL 引用當(dāng)前 servlet 上下文內(nèi)的資源。如果通過 context 屬性顯式地指定了上下文,那么就根據(jù)指定的 servlet 上下文解析絕對(本地)URL。

    <c:import> 操作并不僅僅限于訪問本地內(nèi)容。也可以將包含協(xié)議和主機名的完整 URI 指定為 url 屬性的值。實際上,協(xié)議甚至不僅局限于 HTTP。 <c:import>url 屬性值可以使用 java.net.URL 類所支持的任何協(xié)議。清單 18 中顯示了這種能力。

    其中, <c:import> 操作用來包含通過 FTP 協(xié)議訪問的文檔內(nèi)容。此外,還使用了 <c:catch> 操作,以便在本地處理 FTP 文件傳送期間可能發(fā)生的任何錯誤。錯誤處理是這樣實現(xiàn)的:使用 <c:catch>var 屬性為異常指定一個限定了作用域的變量,然后使用 <c:if> 檢查其值。如果產(chǎn)生了異常,那么就會對那個限定了作用域的變量進行賦值:如清單 18 中的 EL 表達式所顯示的那樣,該變量的值將 會為空。由于 FTP 文檔的檢索將會失敗,因此會顯示有關(guān)這種情況的錯誤消息。

    清單 18. 將 <c:import> 與 <c:catch> 相結(jié)合的示例
    <c:catch var="exception">
      <c:import url="ftp://ftp.example.com/package/README"/>
    </c:catch>
    <c:if test="${not empty exception}">
      Sorry, the remote content is not currently available.
    </c:if>
    

    <c:import> 操作的最后兩個(可選的)屬性是 varscopevar 屬性會導(dǎo)致從指定 URL 獲取的內(nèi)容(作為 String 值)被存儲在一個限定了作用域的變量中,而不是包含在當(dāng)前 JSP 頁面中。 scope 屬性控制該變量的作用域,缺省情況下是頁面作用域。如同我們在今后的文章中將要看到的那樣,JSTL xml 庫中的標(biāo)記利用了 <c:import> 這種能力,即將整個文檔存儲在一個限定了作用域的變量中。

    還要注意的是,可以使用(可選的)嵌套的 <c:param> 標(biāo)記來為正在導(dǎo)入的 URL 指定請求參數(shù)。與在 <c:url> 中嵌套 <c:param> 標(biāo)記一樣,必要時也要對參數(shù)名稱和參數(shù)值進行 URL 編碼。

    請求重定向
    最后一個 core 庫標(biāo)記是 <c:redirect> 。該操作用于向用戶的瀏覽器發(fā)送 HTTP 重定向響應(yīng),它是 JSTL 中與 javax.servlet.http.HttpServletResponsesendRedirect() 方法功能相當(dāng)?shù)臉?biāo)記。清單 19 中顯示了該標(biāo)記的 urlcontext 屬性,它們的行為分別等同于 <c:import>urlcontext 屬性的行為,是嵌套任何 <c:param> 標(biāo)記的結(jié)果。

    清單 19. <c:redirect> 操作的語法
    <c:redirect url="
            expression" context="
            expression">
      <c:param name="
            expression" value="
            expression"/>
      ...
    </c:redirect>
    
          

    清單 20 顯示了 <c:redirect> 操作,它用一個到指定錯誤頁面的重定向代替了清單 18 中的錯誤消息。在該示例中, <c:redirect> 標(biāo)記的用法與標(biāo)準(zhǔn) <jsp:forward> 操作的用法類似。不過請回憶一下:通過請求分派器進行轉(zhuǎn)發(fā)是在服務(wù)器端實現(xiàn)的,而重定向卻是由瀏覽器來執(zhí)行的。從開發(fā)人員的角度來講,轉(zhuǎn)發(fā)比重定向更有效率,但 <c:redirect> 操作卻更靈活一些,因為 <jsp:forward> 只能分派到當(dāng)前 servlet 上下文內(nèi)的其它 JSP 頁面。

    清單 20. 響應(yīng)異常的重定向
    <c:catch var="exception">
      <c:import url="ftp://ftp.example.com/package/README"/>
    </c:catch>
    <c:if test="${not empty exception}">
      <c:redirect url="/errors/remote.jsp"/>
    </c:if>
    

    從用戶的角度來看,主要區(qū)別在于重定向會更新瀏覽器所顯示的 URL,并因此影響書簽的設(shè)置。轉(zhuǎn)發(fā)卻不這樣,它對最終用戶是透明的。這樣,選擇 <c:redirect> 還是 <jsp:forward> 還取決于所期望的用戶體驗。

    結(jié)束語
    JSTL core 庫含有多種通用的定制標(biāo)記,廣大的 JSP 開發(fā)人員都會使用這些標(biāo)記。例如,URL 和異常處理標(biāo)記很好地補充了現(xiàn)有的 JSP 功能,如 <jsp:include><jsp:forward> 操作、 include 偽指令以及 page 偽指令的 errorpage 屬性。迭代和條件操作使得無需腳本編制元素就能夠?qū)崿F(xiàn)復(fù)雜的表示邏輯,尤其在將變量標(biāo)記( <c:set><c:remove> )與 EL 相結(jié)合使用時更是如此。

    參考資料

    關(guān)于作者
    Mark Kolb 是一位在德克薩斯州奧斯汀市(Austin)工作的軟件工程師。他常就服務(wù)器端 Java 這一主題在業(yè)界演講,而且還是 Web Development with JavaServer Pages, 第二版 一書的合著者。可以通過 mak@taglib.com與 Mark 聯(lián)系。

    posted on 2005-04-13 15:58 笨笨 閱讀(434) 評論(0)  編輯  收藏 所屬分類: J2EEALLJ2SE
    主站蜘蛛池模板: 免费视频成人国产精品网站| 日韩免费三级电影| 亚洲高清无码专区视频| 亚洲色偷精品一区二区三区| 67194国产精品免费观看| 亚洲av无码国产精品色午夜字幕| 成人av片无码免费天天看| 在线观看亚洲天天一三视| 国产高潮久久免费观看| 不卡一卡二卡三亚洲| 伊人久久大香线蕉免费视频| 亚洲男人的天堂www| 日日麻批免费40分钟无码| 久久精品国产亚洲av麻豆色欲| 99在线视频免费| 亚洲人成电影院在线观看 | 丝袜足液精子免费视频| 亚洲香蕉成人AV网站在线观看| a成人毛片免费观看| 亚洲国产一区在线| 国产va免费精品观看精品| 国产精品亚洲lv粉色| 一级一级毛片免费播放| 天天天欲色欲色WWW免费| 特级无码毛片免费视频| 在线亚洲97se亚洲综合在线| 免费无码VA一区二区三区| 亚洲va久久久久| 日韩免费观看的一级毛片| 一区二区免费在线观看| 亚洲综合精品一二三区在线| 成年网站免费视频A在线双飞| 久久综合亚洲色hezyo| 日韩亚洲人成在线综合日本| 成人免费午夜无码视频| 深夜福利在线视频免费| 亚洲第一福利视频| 亚洲一区免费观看| 麻豆国产人免费人成免费视频| 男女污污污超污视频免费在线看| 亚洲第一精品福利|