JSP自定義標簽——傳統標簽


  同JSP標簽一樣,自定義標簽主要用於移除JSP頁面中的Java代碼,可以看到我們在JSP中其實是禁止使用Java腳本的,任何要想通過Java代碼實現的功能都必須以標簽形式來處理,可以使用JSP標簽,JSTL標簽,EL函數,或者自定義標簽。

  自定義標簽分為傳統標簽和簡單標簽,簡單標簽是Sun公司為減低自定義標簽技術的學習難度而定義的,對於簡單標簽請看下一篇博客。本文先來學習傳統自定義標簽。

  使用傳統自定義標簽需要滿足以下兩個步驟:

  ① 編寫一個實現Tag接口(實際上我們更常的是繼承Tag接口的實現類從而免於覆寫所有的方法)的Java類,這個Java類也稱為標簽處理器類。

  ② 編寫標簽的TLD文件,用於指定標簽的URI和對標簽的聲明描述,這一點和EL函數時一樣的,TLD文件必須放置在web應用下的【WEB-INF】文件中,可以是除【classes】和【lib】目錄以外的任何子目錄中。TLD文件的模板可以從【Tomcat】--->【webapps】--->【examples】--->【WEB-INF】--->【jsp2】中有一個“jsp2-example-taglib.tld”文件復制首尾和其中的<Tag>標簽。

  注:在TLD文件中我們使用<tag>標簽來對每一個自定義標簽的Java類進行描述,其中每個<tag>標簽下還需要指定<body-content>的值,這個是描述標簽體的類型:

  對於傳統標簽使用:“EMPTY”(代表標簽沒有標簽體)或“JSP”(代表標簽有標簽體)。

 

  以上的步驟整體類似於我們自定義EL函數,而不同的是這里的Java類需要繼承特定的JSP的API中提供的類並覆蓋其中特定的方法。

 

  我們先看一看Tag類的API,注意,這是JSP技術,請看JSP的API:

  

  

  從上面可以看到Tag是一個接口,如果我們直接繼承Tag接口的話,那就得覆寫這六個方法,那就顯得十分麻煩了,況且有些方法是屬於標簽的生命周期方法,是由JSP引擎調用的,因此我們只需要繼承Tag接口的實現子類即可,通常我們使用“TagSupport”類或者“BodyTagSupport”類,能有更多的功能。

  在Tag接口中,除了getParent方法以外,其他都是生命周期方法。在瀏覽器在解析一個JSP頁面時,遇到某個自定義標簽后就會開始執行該標簽的生命周期方法。自定義標簽的生命周期順序為:① 創建自定義標簽的實例對象 ---> ② setPageContext方法 ---> ③ setParent方法---> ④ doStart方法 ---> ⑤ doEnd方法 ---> ⑥ release方法(通常在服務器關閉時才調用)。

  下面簡單的介紹下這幾個生命周期方法:

  setPageContext方法(重要),JSP引擎對標簽進行實例化對象后,會先調用setPageContext方法,將JSP頁面的pageContext對象傳入這個標簽處理器類,我們在JSP的pageContext隱式對象一文中說過,只要擁有了pageContext對象,那么就可以獲取其他八大隱式對象從而操作web中的需求了。

  setParent方法,在setPageContext方法執行完之后,將調用setParent方法,這個方法將會把這個自定義標簽的父類標簽(如果有)傳遞給該標簽處理器類,如果沒有父類標簽,那么setParent方法的參數即為null。注意,這里說的標簽的父標簽也是指自定義標簽,如果該自定義標簽的只是嵌入在普通的HTML標簽的話那么就是無父類標簽,執行的只是setParent(null)方法。

  doStartTag方法,當JSP引擎接連調用setPageContext方法和setParent方法完成標簽的配置之后,當瀏覽器解析標簽的開始標簽時,就會調用doStartTag方法。通常我們在使用標簽處理某個功能時,就將該功能在doStartTag方法中覆寫。另外,依據doStartTag方法的返回值是“EVAL_BODY_INCLUDE”(執行)還是“SKIP_BODY”(不執行)決定是否執行標簽體中的內容。可以說這是我們要使用標簽來封裝Java代碼最重要的一個方法。

  doEndTag方法,當瀏覽器在JSP頁面中解析到該標簽的結束標簽時,就會調用doEndTag方法。另外,依據doEndTag方法的返回值是“EVAL_PAGE”(執行)還是“SKIP_PAGE” (不執行)決定是否執行結束標簽之后余下的JSP頁面內容。

  release方法,通常JSP調用完doEndTag方法后,並不會立即執行release方法,因為為了服務器的性能,通常就會將標簽處理器類的對象駐留於內存中,以便下次能更快速地調用,這一點和Servlet是一樣的。一般在停止該web應用或服務器停止時才會調用標簽處理器的release方法,釋放標簽中的資源。

 

  通常我們使用的是一個Java類繼承TagSupport類或者BodyTagSupport類,對於處理標簽,依然也是覆寫doStartTag方法。同時注意到TagSupport類中,一個屬性即為pageContext,注意這是字段,同時能給子類調用(protected修飾),而我們基本在覆寫doStartTag方法中要隨處用到這個字段:

  

 

例1:使用自定義標簽來顯示來訪者IP

  創建一個Java類繼承TagSupport類,覆寫doStartTag方法,這里因為標簽沒有標簽體,可以暫時不用管doStartTag方法的返回值:

 1 package com.fjdingsd.tag;
 2 public class GuestIpTag extends TagSupport {
 3     @Override
 4     public int doStartTag() throws JspException {
 5         
 6         HttpServletRequest request = (HttpServletRequest) this.pageContext.getRequest();
 7         String ip = request.getRemoteAddr();
 8         JspWriter out = this.pageContext.getOut();
 9         try {
10             out.write(ip);
11         } catch (IOException e) {
12             throw new RuntimeException(e);
13         }
14         return super.doStartTag();
15     }
16 }
View Code

接着在web應用的【WEB-INF】中創建TLD文件,設置好uri和標簽的名稱、類、以及標簽體類型:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 
 3 <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
 6     version="2.0">
 7     <description>A tag library exercising SimpleTag handlers.</description>
 8     <tlib-version>1.0</tlib-version>
 9     <short-name>SimpleTagLibrary</short-name>
10     <uri>selftag</uri>
11     
12     <tag>
13         <name>guestip</name>
14         <tag-class>com.fjdingsd.tag.GuestIpTag</tag-class>
15         <body-content>empty</body-content>
16     </tag>
17 </taglib>
View Code

最后就可以在JSP頁面中使用自定義標簽了,當然別忘了使用taglib指令先導入我們的標簽所在的uri:

    <%@ taglib uri="selftag" prefix="selftag" %>

在JSP頁面的主體中使用我們設計好的自定義標簽:

    您的ip地址為:<selftag:guestip/>

瀏覽器中觀察:

  

 

例2:控制標簽的標簽體內容是否輸出顯示

         如果要想控制標簽體的內容是否輸出顯示,只需要修改doStartTag方法的返回值即可:

 1 package com.fjdingsd.tag;
 2 public class ShowTagBodyOrNot extends TagSupport {
 3     @Override
 4     public int doStartTag() throws JspException {
 5         HttpSession session = this.pageContext.getSession();
 6         User user = (User) session.getAttribute("user");
 7         if(user==null) {
 8             return TagSupport.SKIP_BODY;  //隱藏標簽體內容
 9         }else{
10             return TagSupport.EVAL_BODY_INCLUDE;  //顯示標簽體內容
11         }
12     }
13 }
View Code

在TLD文件中定義(這里忽略文件首尾其他定義):

1 <tag>
2         <name>showbody</name>
3         <tag-class>com.fjdingsd.tag.ShowTagBodyOrNot</tag-class>
4         <body-content>JSP</body-content>
5 </tag>
View Code

在JSP頁面中導入taglib指令后並在JSP頁面主體部分使用自定義標簽:

1     <selftag:showbody>
2             只有登錄用戶才能顯示……
3     </selftag:showbody>
View Code

  當然這個例子當我沒有在session域中存入User對象時,是不會在頁面上顯示這個標簽的標簽體內容的,這里只是用來強調在doStartTag方法的返回值“EVAL_BODY_INCLUDE”與“SKIP_BODY”的區別。

 

例3:控制標簽之后余下的JSP頁面是否輸出顯示

  如果要想標簽之后余下的JSP頁面是否輸出顯示,只需要修改doEndTag方法的返回值即可:

 1 package com.fjdingsd.tag;
 2 public class ShowJSPOrNot extends TagSupport {
 3     //注意,TagSupport的doStartTag方法默認返回值為SKIP_BODY,也就是不執行標簽體內容
 4     @Override
 5     public int doEndTag() throws JspException {
 6         HttpSession session = this.pageContext.getSession();
 7         User user = (User) session.getAttribute("user");
 8         if(user==null) {
 9             return TagSupport.SKIP_PAGE;  隱藏結束標簽后余下JSP頁面        }else{
10             return TagSupport.EVAL_PAGE;  //顯示結束標簽后余下JSP頁面
11         }
12     }
13 }
View Code

在TLD文件中定義(這里忽略文件首尾其他定義):

1 <tag>
2         <name>showpage</name>
3         <tag-class>com.fjdingsd.tag.ShowJSPOrNot</tag-class>
4         <body-content>empty</body-content>
5 </tag>
View Code

在JSP頁面中導入taglib指令后並在JSP頁面主體部分使用自定義標簽:

 1 <selftag:showpage/>
 2 
 3 <!DOCTYPE HTML>
 4 <html>
 5       <head>   
 6             <title>My JSP 'demo1.jsp' starting page</title>
 7       </head>
 8   
 9       <body>
10             。。。
11     <body>
12 </html>        
View Code

  這里我把自定義標簽置於JSP頁面最開始的地方,可以看到如果沒有在session域中存入User對象的話,那么這個JSP在被訪問后是不會看到任何東西的,查看網頁源碼也是沒有任何代碼。當然這個例子只是用來強調在doEndTag方法的返回值 “EVAL_PAGE”和 “SKIP_PAGE”的區別。

  使用傳統的自定義標簽還可以擴展一些其他的功能,比如控制標簽體的內容重復執行,修改標簽體內容再輸出等等,這兩個功能涉及到使用Tag不同實現類的使用,將在下一篇博客中進行講解。

 

 

 

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM