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

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

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

    posts - 51, comments - 17, trackbacks - 0, articles - 9
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    Jsp 自定義標簽

    Posted on 2007-06-26 19:19 chenweicai 閱讀(1950) 評論(0)  編輯  收藏
    本教程目的 第 1 頁(共3 頁)
                                                                                            

    想要在 JavaServer Pages (JSP) 應用程序中添加自定義標簽嗎?本教程將為您展示如何用這些標簽編寫類似于 JSP 技術自帶操作 —— 如 jsp:useBeanjsp:getPropertyjsp:forward —— 的自定義操作。介紹如何用特定于自已的域的表示邏輯的自定義操作來擴展 JSP 語法。

    在 JSP 應用程序中添加 自定義標簽 的能力可以使您將工作重點放到以文檔為中心的開發方式上。可以使 Java 代碼不出現在 JSP 頁中,從而使這些頁面更容易維護。(我從經驗中學到,在 JSP 頁中放入過多的 Java 代碼時,代碼維護就會成為可怕的任務)。本教程將使您可以立即開發出自定義標簽。了解了 JSP 自定義標簽開發的好處后,您可能會對程序員沒有更多地使用它而感到意外。

    在本教程中,我將討論使用自定義標簽的基本內容。將介紹如何用自定義標簽創建可重用的表示組件并避免在 JSP 頁加入 Java scriptlet。

    在本教程中,我們將:

    • 定義一個 JSP 自定義標簽體系結構。
    • 解釋簡單標簽。
    • 定義嵌套標簽。
    • BodyContent 解釋標簽。
    • 在標簽中添加屬性。
    • 在標簽中添加 scriptlet 變量。
    • 用自定義標簽實現控制流程。
    • 用 Struts 簡化標簽部署。

    我要學習本教程嗎? 第 2 頁(共3 頁)


    如果發現自己在 JSP 應用程序中加入了大量 Java scriptlet,那么本教程就是為您準備的。 閱讀本教程后,就會掌握將 Java 代碼從 JSP 頁面中清除出去所需要的信息。

    本教程假定讀者熟悉 Java 平臺、JavaServer Pages (JSP) 技術、MVC 模式、Reflection API、Model 2,最好還有 Struts 框架。此外,要從本教程中得到最大的收獲,還需要很好的使用標簽庫的經驗

    關于作者 第 3 頁(共3 頁)


    Rick Hightower 是一位 J2EE 開發人員和顧問,他熱衷于使用 J2EE、Ant、Hibernate、Struts、IMB 的 ETTK 和 Xdoclet。 Rick 是 Trivera Technologies 的前任 CTO,這是一家全球培訓、指導和咨詢公司,其重點是企業開發。他經常在 IBM developerWorks 上發表文章,并編寫了 10 多篇 developerWorks 教程,內容從 EJB 技術到 Web 服務到 XDoclet。 Rick 不久前與別人共同開辦了另一家名為 ArcMind 的公司,它專門研究 agile 方法,還從事 Struts/JavaServer Faces 開發、咨詢和指導。

    在為 eBlox 工作時,Rick 和 eBlox 小組遠在 1.0 版本之前就已使用 Struts 為電子商務站點構建了兩個框架和一個 ASP (應用程序服務提供者)。這個框架目前正在為 2000 多個在線商店店面提供支持。

    Rick 最近完成了一本名為 Professional Jakarta Struts 的書。在周游全國對 J2EE 和 Struts 項目提供咨詢,或者在大會上發表關于 J2EE 和極端編程 (extreme programing)的講演之余,Rick 喜歡在通宵咖啡店喝咖啡,寫一些有關 Struts、J2EE 和其他內容的文章,并以第三人稱描寫他自己。

    標簽處理程序 第 1 頁(共2 頁)


    在創建自定義標簽之前,需要創建一個 標簽處理程序。標簽處理程序是一個執行自定義標簽操作的 Java 對象。在使用自定義標簽時,要導入一個 標簽庫 —— 即一組標簽/標簽處理程序對。通過在 Web 部署描述符中聲明庫導入它,然后用指令 taglib 將它導入 JSP 頁。

    如果 JSP 容器在轉換時遇到了自定義標簽,那么它就檢查 標簽庫描述符(tag library descriptor) (TLD) 文件以查詢相應的標簽處理程序。TLD 文件對于自定義標簽處理程序,就像 Web 部署描述符對于 servlet 一樣。

    在運行時,JSP 頁生成的 servlet 得到對應于這一頁面所使用的標簽的標簽處理程序的一個實例。生成的 servlet 用傳遞給它的屬性初始化標簽處理程序。

    標簽處理程序實現了 生存周期 方法。生成的 servlet 用這些方法通知標簽處理程序應當啟動、停止或者重復自定義標簽操作。生成的 servlet 調用這些生存周期方法執行標簽的功能。

    標簽的類型 第 2 頁(共2 頁)


    可以定義兩種類型的標簽:

    • javax.servlet.jsp.tagext.Tag
    • javax.servlet.jsp.tagext.BodyTag

    正文 進行操作 —— 即對在開始和結束標簽之間的內容進行操作的 —— 標簽必須實現 BodyTag 接口。在這個教程中,我們將稱這些標簽為 正文標簽。我們將不對其正文操作的標簽稱為 簡單標簽。簡單標簽可以實現 Tag 接口,盡管不要求它們這樣做。要記住不對其正文操作的標簽仍然 正文,只不過,它的標簽處理程序不能讀取這個正文。

    簡單標簽的例子 第 1 頁(共9 頁)
                                                                                                       上一頁      下一頁

    Struts 框架帶有幾個自定義標簽庫(有關 Struts 的更多信息的鏈接請參閱 參考資料 )。這些庫中的一個標簽可以創建一個支持改寫 URL 的鏈接并用 jsessionid 對改寫的連接編碼。

    不過有一個問題:如果希望傳遞一組請求參數(如查詢字符串),也許必須為此創建一個 Java scriptlet。真是亂!下面的清單 (search_results.jap) 展示了一個 JSP 頁,它被迫加入了這樣一個 scriptlet。

     <%@ taglib uri="struts-html" prefix="html" %> <jsp:useBean class="java.util.HashMap" id="deleteParams" /> <% deleteParams.put("id", cd.getId()); deleteParams.put("method","delete"); %> <!-- Pass the map named deleteParams to html:link to generate the request parameters--> <html:link action="/deleteCD" name="deleteParams">delete </html:link> </font></td>  

    search_results.jsp 創建一個 hashmap 并向這個 map 傳遞兩個屬性。在下面幾小節,我們將創建一個不用 Java 代碼完成這項工作的自定義標簽。我們的標簽將定義如下的一個 hashmap:

     <map:mapDefine id="deleteParams"> <map:mapEntry id="id" name="cd" property="id"/> <map:mapEntry id="method" value="delete"/> </map:mapDefine> <!-- Pass the map named deleteParams to html:link to generate the request parameters--> <html:link action="/deleteCD" name="deleteParams">delete </html:link> </font></td>  

    這將使我們可以容易地創建小型 map。

    這個例子將展示幾個關鍵概念,包括使用嵌套標簽和定義 scriplet 變量。首先我將解釋這個標簽是如何工作的。然后在以后的幾節中建立這些概念,并介紹如何編寫這個標簽的不同形式,使它們處理其正文并控制執行流程。

    構建簡單標簽的步驟 第 2 頁(共9 頁)


    讓我們創建一個定義一個 HashMap scriptlet 變量的標簽。為此,需要實現標簽處理程序接口 (javax.servlet.jsp.tagext.Tag)。因此,我們要創建的第一個標簽將是一個簡單標簽。

    這個標簽將實例化一個 map。使用這個標簽的開發人員可以指定要實例化的 map 的類型 —— HashMapTreeMapFastHashMap 或者 FastTreeMapFastHashMapFastTreeMap 來自 Jakarta Commons Collection library (有關鏈接請參閱 參考資料)。開發人員還可以指定標簽所在的范圍 —— 頁、請求、會話還是應用程序范圍。

    要構建這個簡單標簽,我們需要完成以下步驟:

    1. 創建實現了 Tag 接口(準確地說是 javax.servlet.jsp.tagext.Tag)的標簽處理程序類。

    2. 創建一個 TLD 文件。

    3. 在標簽處理程序 Java 類中創建屬性。

    4. 在 TLD 文件中定義與標簽處理程序 Java 類中定義的屬性對應的屬性。

    5. 在 TLD 文件中聲明 scriptlet 變量。

    6. 實現 doStartTag() 方法。在標簽處理程序類中,根據屬性將值設置到 scriptlet 變量中。

    如果您像我一樣,可能會提前閱讀書的結尾,所以請查看 附錄 中標簽處理程序類的完整列表以了解這個過程是如何結束的。

    在下面幾小節中,我們將分析 MapDefineTag 的實現,并分析如何到達這一步。

    第 1 步:創建一個實現了 Tag 接口的標簽處理程序 第 3 頁(共9 頁)


    為了編寫標簽處理程序,必須實現 Tag 接口。如前所述,這個接口用于不操縱其標簽正文的簡單標簽處理程序。就像 J2EE API 文檔 (有關鏈接請參閱 參考資料)所說的:Tag 接口定義了標簽處理程序和 JSP 頁實現類之間的基本協議。它定義了在標簽開始和結束時調用的生存周期和方法。

    標簽處理程序接口有以下方法:

    方法 作用
    int doStartTag() throws JspException 處理開始標簽
    int doEndTag() throws JspException 處理結束標簽
    Tag getParent()/void setParent(Tag t) 獲得/設置標簽的父標簽
    void setPageContext(PageContext pc) pageContext 屬性的 setter 方法
    void release() 釋放獲得的所有資源

    TagSupport

    現在,不必直接實現 Tag 接口,相反,用 map 定義的(map-defining)標簽將繼承 TagSupport 類。這個類以有意義的默認方法實現 Tag 接口,因而使開發自定義標簽更容易 (有關 TagSupport 的 API 文檔的鏈接請參閱 參考資料)。 例如,TagSupport 類定義了 get/setParent()setPageContext(),這與所有標簽處理程序幾乎相同。 get/setParent() 方法允許標簽嵌套。TagSupport 類還定義了一個可以被子類使用的 pageContext 實例變量 (protected PageContext pageContext),這個變量是由 setPageContext() 方法設置的。

    在默認情況下,TagSupport 實現了 doStartTag() 以使它返回 SKIP_BODY 常量,表示將不對標簽正文進行判斷。 此外,在默認情況下,doEndTag() 方法返回 EVAL_PAGE,它表示 JSP 運行時引擎應當對頁面的其余部分進行判斷。 最后,TagSupport 實現了 release(),它設置 pageContext 及其父元素為 null

    TagSupport 類還實現了 IterationTag 接口和 doAfterBody(),這樣它就返回 SKIP_BODY。 在后面討論進行迭代的標簽時我將對此加以更詳細的解釋(請參閱 用自定義標簽控制流程)。

    好了,現在讓我們通過繼承 TagSupport 來實現 Tag 接口:

     ... import javax.servlet.jsp.tagext.TagSupport; ... public class MapDefineTag extends TagSupport { ...  

    我們已經定義了標簽處理程序,現在需要增加從處理程序到 TLD 文件中的標簽的映射。我們將在下一小節中對此進行處理。然后,將完成 MapDefineTag 中剩余的代碼。

    第 2 步:創建一個 TLD 文件 第 4 頁(共9 頁)


    TLD 文件對自定義標簽處理程序的作用就像 Web 部署描述符對 servlet 的作用。 TLD 文件列出了從標簽名到標簽處理程序的映射。 這個文件中的大多數數據都是在 JSP 頁轉換時使用的。 TLD 文件通常保存在 Web 應用程序的 WEB-INF 目錄,并在 web.xml 文件中聲明。它們一般用 .tld 擴展名結束。

    TLD 文件有一個 導言(preamble),在這里標識 JSP 技術的版本和使用的標簽庫。這個導言通常看起來像這樣:

     <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>map</short-name>  

    讓我們更詳細地分析一下這些標簽:

    • TLD 文件的根元素是 taglibtaglib 描述了一個 標簽庫 —— 即一組標簽/標簽處理程序對。

    • 因為我們使用的是 JSP 版本 1.2,所以在這個例子中需要 tlib-versionshort-name 元素。

    • tlib-version 元素對應于標簽庫版本。

    • jsp-version 對應于標簽庫所依賴的 JSP 技術的版本。

    • short-name 元素定義了 IDE 和其他開發工具可以使用的標簽庫的簡單名。

    • taglib 元素包含許多 tag 元素,標簽庫中每一個標簽有一個 tag 元素。

    因為我們剛創建了自己的類,所以我們將繼續往下進行,在 TLD 文件中聲明這個類,如下所示:

     <taglib> 
    ...
    <tag>
    <name>mapDefine</name>
    <tag-class>trivera.tags.map.MapDefineTag</tag-class>
    <body-content>JSP</body-content>
    ...

    tag 元素用于將自定義標簽映射到它們的自定義標簽處理程序。上述清單中的 tag 元素將自定義標簽 mapDefine 映射到處理程序 trivera.tags.map.MapDefineTag。 因此,不論在 mapDefine 上運行的是什么轉換引擎,都會調用 trivera.tags.map.MapDefineTag

    已經在 TLD 中定義了標簽,接下來要在標簽處理程序類中定義這個標簽的一些屬性了。

    第 3 步:在標簽處理程序 Java 類中創建屬性 第 5 頁(共9 頁)
                                                                                                                   上一頁      下一頁

    我們希望為 mapDefine 標簽指定三個屬性,如下所示:

    屬性說明
    id 新 scriptlet 變量的名字。
    scope 新 scriptlet 變量所在的范圍。
    type 新 scriptlet 變量的類型 (HashMapFastHashMapTreeMap 或者 FastTreeMap)。 如果 type 設置為 hash,那么就會創建一個 HashMap。如果 type 設置為 fasthash,那么將創建 FastHashMap

    在 JSP 頁中使用這個標簽時,它看起來將像下面這樣:

     <map:mapDefine id="editParams" scope="session" type="hash"> 
    ...
    </map:mapDefine>

    這個標簽將在會話范圍內創建一個名為 editParamsHashMap

    為了在標簽處理程序中創建屬性,需要定義相應的 JavaBean 屬性。 因此,每一個屬性在標簽處理程序中都有對應的 setter 方法,如下所示:

     public class MapDefineTag extends TagSupport { 
    ...
    private String type = FASTTREE;
    private String id;
    private String scope;


    public void setType(String string)
    { type = string; }

    public void setId(String string)
    { id = string; }
    public void setScope(String string)
    { scope = string; }

    轉換引擎將用硬編碼的配置數據或者運行時表達式設置這個標簽的屬性。 我們將在 第 4 步:在 TLD 文件中定義屬性 中對此做更詳細的討論。

    第 5 步:實現 doStartTag() 方法 中,我們將在標簽處理程序的 doStartTag() 方法中使用這些屬性。

    第 4 步:在 TLD 文件中定義屬性 第 6 頁(共9 頁)


    就 像上一小節中所做的那樣,通過聲明 JavaBean 屬性定義自定義屬性,然后在 TLD 文件中聲明這些屬性。 每一個 JavaBean 屬性都必須與相應的自定義標簽屬性相匹配。 在 TLD 中定義的屬性必須匹配 JavaBean 屬性,不過卻可以有與標簽屬性不匹配的 JavaBean 屬性。

    下面是 MapDefineTag 的屬性聲明:

     <tag> <name>mapDefine</name> <tag-class>trivera.tags.map.MapDefineTag</tag-class> <body-content>JSP</body-content> ... <attribute> <name>id</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <description>The id attribute</description> </attribute> <attribute> <name>scope</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <description>The scope attribute</description> </attribute> <attribute> <name>type</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <description> Specifies the type of map valid values are fasttree, fasthash, hash, tree </description> </attribute> </tag>  

    name 元素指定屬性的名字。required 元素指定屬性是否是必需的(默認值是 false)。rtexprvalue 元素表明屬性是硬編碼了轉換時的值還是允許使用運行時 scriptlet 表達式。

    記住,MapDefineTag 類必須為前面描述的每一個屬性定義一個 JavaBean 屬性,我們在 第 3 步:在標簽處理程序 Java 類中創建屬性 中完成這個任務。

    第 5 步:實現 doStartTag() 方法 第 7 頁(共9 頁)


    標簽開始時調用 doStartTag() 方法 —— 從開發人員的角度看,這是當引擎遇到 <map:mapDefine> 時發生的。如果 doStartTag() 返回 SKIP_BODY,那么將不處理標簽正文。 如果它返回一個 EVAL_BODY_INCLUDE,那么將處理正文。

    MapDefine 類的 doStartTag() 方法完成以下工作:

    • 根據 type 屬性確定要創建的 map 的屬性。
    • 根據 scope 屬性確定新的 map 對象放在什么范圍內。
    • 根據 id 屬性確定新 map 對象要放入的范圍的名字。

    讓我們更詳細地分析這個過程。MapDefine 類檢查 type 屬性是設置為 FASTTREEHASHTREE 還是 FASTHASH。然后創建相應的 map,如下所示:

     /* String constants for the different types of maps we support */ public static final String FASTHASH = "FASTHASH"; public static final String FASTTREE = "FASTTREE"; public static final String HASH = "HASH"; public static final String TREE = "TREE"; /** The map we are going to create */ private Map map = null; /** The member variable that holds the type attribute */ private String type = FASTTREE; ... public int doStartTag() throws JspException { /** Based on the type attribute, determines which type of Map to create */ if (type.equalsIgnoreCase(FASTTREE)) { map = new FastTreeMap(); } else if (type.equalsIgnoreCase(HASH)) { map = new HashMap(); } else if (type.equalsIgnoreCase(TREE)) { map = new TreeMap(); } else if (type.equalsIgnoreCase(FASTHASH)) { map = new FastHashMap(); }  

    然后,用 idscope 屬性將 hashmap 以一個給定的名字設置到一個給定范圍中:

     private String id; private String scope; public int doStartTag() throws JspException { ... if (scope == null){ pageContext.setAttribute(id, map); }else if("page".equalsIgnoreCase(scope)){ pageContext.setAttribute(id, map); }else if("request".equalsIgnoreCase(scope)){ pageContext.getRequest().setAttribute(id, map); }else if("session".equalsIgnoreCase(scope)){ pageContext.getSession().setAttribute(id, map); }else if("application".equalsIgnoreCase(scope)){ pageContext.getServletContext().setAttribute(id, map); } return EVAL_BODY_INCLUDE; }  

    如果范圍屬性是 null,那么 map 將放入頁范圍。否則,參數將放入通過 scope 屬性傳遞的范圍名所對應的范圍中。

    到目前為止,我們已經有一個非常簡單的標簽,它有三個屬性:idscopetype。 我們將用給定的名字將 map 放到一個范圍中。但是,我們還有一件事沒做,就是聲明 scriptlet 變量。 為了做到這一點,需要向 TLD 再添加一項,這就是我們在下一小節中所要做的事。


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲狠狠综合久久| **aaaaa毛片免费| 亚洲日韩精品无码AV海量| 亚洲色精品aⅴ一区区三区| 青青青青青青久久久免费观看| 久久aⅴ免费观看| 久久久受www免费人成| 美女黄网站人色视频免费| 亚洲乱人伦精品图片| 亚洲电影国产一区| 中文字幕精品亚洲无线码二区 | 亚洲va久久久噜噜噜久久| 免费看国产曰批40分钟| 青青久在线视频免费观看| 最近中文字幕mv免费高清在线 | 亚洲人成影院在线无码观看| 成人免费a级毛片无码网站入口| 69pao强力打造免费高清| 久久美女网站免费| 黄色免费在线网站| 久久精品成人免费观看97| 成人精品综合免费视频| 青娱乐在线视频免费观看| 国产亚洲人成在线影院| 亚洲youwu永久无码精品| 亚洲欧美aⅴ在线资源| 亚洲色大成网站www| 亚洲精品中文字幕无乱码麻豆| 亚洲福利一区二区三区| 777亚洲精品乱码久久久久久 | 久久一区二区三区免费播放| 一级毛片免费观看不卡视频| 免费人成毛片动漫在线播放| 国内精品99亚洲免费高清| 韩日电影在线播放免费版| 国产精品免费AV片在线观看| 18禁在线无遮挡免费观看网站| 未满十八18禁止免费无码网站| 久久青草免费91线频观看不卡| 无码成A毛片免费| 成年免费大片黄在线观看岛国|