程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> J2EE探索者: 用五個容易的步驟實現JSP自定義標記

J2EE探索者: 用五個容易的步驟實現JSP自定義標記

編輯:關於JAVA

您可能聽說現在有上百種不同的方式,但是在開發 Web 應用程序時將表示邏輯與業務 邏輯分離是很重要的。近年來,Java 平台已經發展為在體系結構層次上加入了這種分離。 例如,在 JSP 體系結構中加入 JavaBean 組件使開發人員使用 JSP 標記獲得和設置經過 特別編碼的 Java 組件上的屬性。這些組件或者 JavaBean 再代表表示層執行後端業務處 理。

JSP 自定義標記是 JSP/JavaBean 體系結構的產物。像 JavaBean 技術一樣,自定義標 記有助於將表示邏輯與業務邏輯分離。並且自定義標記成了 Web 設計者的 HTML、XML 和 Javascript 世界與軟件工程師的 Java 代碼、SQL 調用和算法世界之間的橋梁。

在本月的 J2EE 探索者 中,您將學到在 JSP 頁中使用 JSP 自定義標記的一些基本知 識。我們首先介紹 JSP 標記,然後直接進入創建標記、將它結合到 JSP 容器並在 JSP 頁 面中使用它的過程。在本文的最後,我們將簡要討論 Java 標准標記庫(Java Standard Tag Library, JSTL),這是一組可以在您的 Java 開發項目中使用的、標准化的 JSP 自 定義標記。

JSP 自定義標記

JSP 自定義標記是用戶定義的標記,它遵循 JSP JavaBean 標記(即 useBean 、 getProperty 和 setProperty )所使用的一種特殊的 XML 語法。當 servlet 容器處理自 定義標記時,會調用一個或者多個 Java 類文件處理它,與用 Java 類文件處理 JSP 頁面 的 JavaBean 調用的方式基本一樣。處理標記以後,容器將取其名字和屬性、以及標記正 文中可能有的任何內容,並將它傳遞給一個或者多個類文件進行處理。

Java 開發人員編寫標記處理程序類以處理標記並處理所有需要的 Java 代碼和數據操 作。對於 Web 設計者來說,自定義標記與標准 HTML 標記除了都可以利用後端動態數據外 ,它們看上去與使用起來沒什麼區別。正確編寫自定義標記可以讓 Web 設計者創建、查詢 和操作數據而無需編寫一行 Java 代碼。正確使用自定義標記使 Java 開發人員不必再在 編碼過程中考慮表示層。這樣應用程序開發小組的每一位成員都可以關注於他或者她最擅 長的事物。

實現 JSP 自定義標記

JSP 體系結構需要以下組件以實現自定義標記:

在每一頁中有一個 JSP 聲明

Web 應用程序描述符(web.xml)中的一個項

一個包含特殊 XML 文件和為處理自定義標記而調用的 Java 類的 JAR 文件

在下面幾節,您將一步一步地學習如何滿足這些要求並將自定義標記加入到 JSP 頁面 中。要想成功實現 JSP 自定義標記,您需要采取下面五個步驟:

編寫標記處理程序類。

創建標記庫描述符(TLD)。

使 TLD 文件和處理程序類可訪問。

引用標記庫。

在 JSP 頁面中使用標記。

這些內容是相當基本的,也不用花很長時間。就讓我們開始吧。

第 1 步. 編寫標記處理程序類

在下面的例子中,我們將使用一個非常簡單的顯示當前時間和日期的自定義標記例子。 下面就是 DateTag :

<abc:displayDate />

我們要做的第一件事是編寫標記處理程序類。在執行引用自定義標記的 JSP 頁面時, JSP 容器判斷每一個自定義標記。當容器遇到一個標記時,它調用與這個自定義標記相關 聯的標記處理程序,我們將在後面更多地討論這個過程。然後,每一個標記處理程序實現 JSP API 中的一個特殊接口。標記有兩種類型:可以處理標記內容(或者正文)的標記和 不能處理標記內容的標記:

<abc:tagWithNoBody attribute="value"/>
<abc:tagWithBody attribute="value">
   This is some body content that the tag handler can operate upon.
</abc:tagWithBody>

在 DateTag 例子中不需要加入正文內容,因為它只顯示當前日期。因此,我們的處理 程序類將實現 Tag 接口(一般是通過擴展 TagSupport 類)。如果我們要創建一個可以處 理正文的標記,那麼我們就需要實現 BodyTag 接口(一般是通過擴展 BodyTagSupport 類 )。清單 1 顯示了 DateTag 的處理程序類:

清單 1. 標記處理程序類

package myTags;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import javax.servlet.http.*;
import java.text.*;
import java.util.*;
public DateTag extends TagSupport {

   public int doStartTag() throws javax.servlet.jsp.JspException {
     HttpServletRequest   req;
       Locale         locale;
      HttpJspPage     g;
       DateFormat      df;
      String        date;
       JSPWriter      out;

       req = ( HttpServletRequest )pageContext.getRequest();
       locale = req.getLocale();
       df = SimpleDateFormat.getDateInstance(
          SimpleDateFormat.FULL,locale );
       date = df.format( new java.util.Date() );

       try {
        out = pageContext.getOut();
        out.print( date );
       } catch( IOException ioe ) {
        throw new JspException( "I/O Error : " + ioe.getMessage() );
       }//end try/catch
     return Tag.SKIP_BODY;
    }//end doStartTag()
}//end DateTag

關於這段代碼的說明

關於 DateTag 處理程序類有幾件事值得一說。首先看一下方法聲明。如果我們直接實 現 Tag 接口,那麼就需要完成幾個方法聲明。因為 TagSupport 類是簡單的、具體類,它 完全實現了在 Tag 接口中聲明的方法,我們可以只實現那些在自定義標記中要使用的方法 。在這個簡單的例子中,我們只實現了 doStartTag() 方法,它是在遇到開始標記時調用 的。

您還可能注意到 doStartTag() 方法返回 SKIP_BODY 。當然其原因是我們的簡單日期 標記沒有正文。您要注意的最後一件重要的事情是使用了 pageContext 對象訪問輸出緩存 以直接向輸出流發送內容。您可能還記得在本系列以前的文章說過, pageContext 對象是 一個隱式對象,它提供對與當前頁面有關的屬性的訪問。

編寫了源代碼文件後,我們像編譯所有其他 Java 類一樣編譯這個類(確保在類路徑中 加入 Servlet/JSP JAR 文件),然後將編譯的類文件放到 Web 應用程序的類目錄(WEB- INF/classes)中。如果我們開發的是幾個標記或者定義有標記變量的標記,那麼我們就會 有多個標記處理程序類。在這種情況下我們可能選擇將處理程序類打包在一個 JAR 文件中 而不是使它們成為類目錄中的分散的文件。

第 2 步. 創建 TLD

下一步是定義包含自定義標記與處理它的 Java 類(或多個類)之間的映射的庫。這個 庫是在一個名為標記庫描述符(TLD)的 XML 文檔中定義的。我們將從 DateTag 例子 DateTagLib.tld中調用這個 TLD。注意“.tld”是這種文件的標准擴展名。

清單 2. DateTagLib.tld 文件

<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
  <tlibversion>1.0</tlibversion>
  <info>A simple tag library</info>
  <tag>
   <name>displayDate</name>
   <tagclass>myTags.DateTag</tagclass>
   <bodycontent>empty</bodycontent>
   <info>Display Date</info>
  </tag>
</taglib>

DateTagLib.tld 是一個出色的、最小的標記庫描述符文件。所有關鍵信息都包含在 Tag 標記中,在這裡映射了標記名和處理程序類,我們聲明了標記對於正文內容的敏感性 。對於更復雜的情況,我們可以使用其他的 XML 標記以提供有關庫和標記的更多信息。在 一個庫中定義多個標記也很常見。

第 3 步. 使 TLD 和處理程序類可訪問

第 3 步是使這個類或者這些類和 TLD 可以被 Web 應用程序訪問。有兩種方法:可以 將類和 TLD 打包到一個 JAR 文件中,再將這個 JAR 文件儲存在 Web 應用程序的 lib 目 錄中,也可以將類文件分散地放到 classes 子目錄中並將 TLD 文件放到 Web 應用程序的 WEB-INF 目錄下面的某一位置。

在這個例子中,我們將使用第二種方法,將 TLD 文件和類分散地放到 Web 應用程序目 錄結構中。您可以回憶起在第 1 步中我們已經將標記處理程序類放到了 classes 目錄中 ,所以我們實際上只需儲存 TLD 文件。TLD 文件被儲存在 WEB-INF 目錄或者子目錄中, 如果是部署 Java 文件,則儲存在 JAR 的 META-INF/ 目錄或者子目錄。在這裡,我們沒 有使用 JAR 文件,所以我們只將 TLD 儲存到 Web 應用程序的 WEB-INF/lib 目錄中。

第 4 步. 引用這個庫

這時,我們已經編譯了標記處理程序類、創建了 TLD 文件以定義處理程序類和標記之 間的映射、並保證類和標記在應用程序中都是可訪問的。下一步是建立 JSP 頁面與標記庫 之間的引用。有兩種方法聲明 JSP 頁面與其庫之間的引用。可以通過 Web 應用程序描述 符(web.xml)聲明一個靜態引用,也可以直接在頁面中聲明一個動態引用。我們將試用這 兩種方法。

為了進行靜態引用,首先必須將下面的項加入到 web.xml 文件中:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<Web-app>

  <!-- Define Servlets, Servlet Mappings, etc. -->

  <taglib>
    <taglib-uri>myTags</taglib-uri>
    <taglib-location>/WEB-INF/lib/DateTagLib.tld</taglib-location>
  </taglib>
</Web-app>

然後,將 JSP 聲明加入到所有需要使用自定義標記庫的頁面中:

<%@ taglib uri="myTags" prefix="abc" %>

注意指定的 uri 屬性與在 web.xml 文件中指定的 taglib-uri 值相匹配。

為了進行動態引用,只需在所有需要使用這個庫的頁面中加入一個 JSP 聲明即可:

<%@ taglib uri="/WEB-INF/lib/DateTagLib.tld" prefix="abc" % >

靜態引用與動態引用的比較

在進行標記庫的靜態引用時,JSP 聲明必須查詢 web.xml 文件以執行庫查詢。這意味 著如果移動或者重命名了庫,或者希望在 web.xml 文件中加入更多的庫,就必須停止服務 器、更新 web.xml 文件、然後重新啟動服務器。動態方法讓 JSP 頁直接指向 TLD 位置, 因而是在解釋 JSP 頁面時進行處理。

靜態方法提供了頁面與庫的實際名和位置之間一定程度的非直接性,這可以為您提供一 些改變這些屬性而不修改頁面的靈活性。另一方面,動態方法提供了更大的靈活性,讓您 可以在運行時增加和移動標記聲明。如果您對動態方法感興趣,但是又擔心做了一些改變 後、有可能要更新多個頁面的維護負擔,那麼您可以始終將 JSP 聲明放到一個單獨的 JSP 文件中,並在每一個要訪問 Web 應用程序的自定義庫的頁面中加入這一頁。這使您具有在 運行時只需要更新信息一次就可以增加庫的靈活性。

靜態引用與動態引用的比較

在進行標記庫的靜態引用時,JSP 聲明必須查詢 web.xml 文件以執行庫查詢。這意味 著如果移動或者重命名了庫,或者希望在 web.xml 文件中加入更多的庫,就必須停止服務 器、更新 web.xml 文件、然後重新啟動服務器。動態方法讓 JSP 頁直接指向 TLD 位置, 因而是在解釋 JSP 頁面時進行處理。

靜態方法提供了頁面與庫的實際名和位置之間一定程度的非直接性,這可以為您提供一 些改變這些屬性而不修改頁面的靈活性。另一方面,動態方法提供了更大的靈活性,讓您 可以在運行時增加和移動標記聲明。如果您對動態方法感興趣,但是又擔心做了一些改變 後、有可能要更新多個頁面的維護負擔,那麼您可以始終將 JSP 聲明放到一個單獨的 JSP 文件中,並在每一個要訪問 Web 應用程序的自定義庫的頁面中加入這一頁。這使您具有在 運行時只需要更新信息一次就可以增加庫的靈活性。

第 5 步. 在 JSP 頁面中使用標記

完成了所有這些准備工作後,我們就可以在 JSP 頁面中使用這些自定義標記了。清單 3 顯示了包含 DateTag 的 JSP 頁面的浏覽器輸出:

清單 3. 帶有自定義標記的 JSP 頁

<%@ taglib uri="/WEB-INF/lib/DateTagLib.tld" prefix="abc" % >
<HTML>
   <HEAD>
     <TITLE>Date tag example</TITLE>
   </HEAD>

   <BODY>
     <H1>Date tag Example</H1>
     <p>Hi today is <b><abc:displayDate /></b> </p>
   </BODY>
</HTML>

重新啟動 Web 服務器並測試自己的 JSP 頁面 !結果看起來類似於圖 1 所示。

圖 1. DateTag 的浏覽器輸出

用 JSTL 節省時間

您所需要的自定義標記功能中也許有多達百分之八十已經由 J2EE 團體創建並標准化了 。使用現有的標記庫而不是從頭創建所有東西會使您節省大量時間和精力。盡管在公共域 有數十種庫,不過業界匯集了一個特定的自定義庫。Java 標准標記庫(JSTL)是由 Java Community Process 設計的,其參考實現是由 Apache Group 通過 Jakarta Taglibs 項目 所開發和維護的(參閱 參考資料)。

JSTL 定義了針對常見 Web 應用程序處理需求,如變量支持、流程控制、URL 管理、 XML 操作、國際化、數據庫訪問等等的標記。除了一組豐富的標記外,JSTL 還定義了自己 的表達式語言(EL)。EL 使我們可以容易地訪問應用程序數據並更容易在不使用腳本或者 請求時表達式的條件下操作這些數據。

除了節省您從頭開發所有標記的時間和精力,JSTL 還具有標准化和業界承認的所有好 處。這些好處包括廠商支持、大量介紹文字、以及有很大的機會找到具有 JSTL 經驗的雇 員或者承包商。

結束語

在 J2EE Web 開發中越來越多地需要將業務和表示邏輯分離,JSP 自定義標記提供了替 代簡單的老 JavaBean 和 Java 腳本的一個有吸引力的方法。更好的是在 JSTL 中已存在 一組已定義的標准的自定義標記庫。在 J2EE 探索者 的這篇文章中,您經歷了從頭創建一 個自定義標記並在 JSP 頁面中實現它的過程。我還簡單介紹了 JSTL 並闡述了使用它而不 是從頭創建所有的自定義標記的好處。

下個月,我們將繼續探索 J2EE 技術,對 Web 應用程序安全體系結構進行分析。祝這 段時間裡探索快樂!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved