同JSP標籤同樣,自定義標籤主要用於移除JSP頁面中的Java代碼,能夠看到咱們在JSP中實際上是禁止使用Java腳本的,任何要想經過Java代碼實現的功能都必須以標籤形式來處理,可使用JSP標籤,JSTL標籤,EL函數,或者自定義標籤。html
自定義標籤分爲傳統標籤和簡單標籤,簡單標籤是Sun公司爲減低自定義標籤技術的學習難度而定義的,對於簡單標籤請看下一篇博客。本文先來學習傳統自定義標籤。java
使用傳統自定義標籤須要知足如下兩個步驟:web
① 編寫一個實現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>的值,這個是描述標籤體的類型:session
對於傳統標籤使用:「EMPTY」(表明標籤沒有標籤體)或「JSP」(表明標籤有標籤體)。app
以上的步驟總體相似於咱們自定義EL函數,而不一樣的是這裏的Java類須要繼承特定的JSP的API中提供的類並覆蓋其中特定的方法。webapp
咱們先看一看Tag類的API,注意,這是JSP技術,請看JSP的API:jsp
從上面能夠看到Tag是一個接口,若是咱們直接繼承Tag接口的話,那就得覆寫這六個方法,那就顯得十分麻煩了,何況有些方法是屬於標籤的生命週期方法,是由JSP引擎調用的,所以咱們只須要繼承Tag接口的實現子類便可,一般咱們使用「TagSupport」類或者「BodyTagSupport」類,能有更多的功能。ide
在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 }
接着在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>
最後就能夠在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 }
在TLD文件中定義(這裏忽略文件首尾其餘定義):
1 <tag> 2 <name>showbody</name> 3 <tag-class>com.fjdingsd.tag.ShowTagBodyOrNot</tag-class> 4 <body-content>JSP</body-content> 5 </tag>
在JSP頁面中導入taglib指令後並在JSP頁面主體部分使用自定義標籤:
1 <selftag:showbody> 2 只有登陸用戶才能顯示…… 3 </selftag:showbody>
固然這個例子當我沒有在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 }
在TLD文件中定義(這裏忽略文件首尾其餘定義):
1 <tag> 2 <name>showpage</name> 3 <tag-class>com.fjdingsd.tag.ShowJSPOrNot</tag-class> 4 <body-content>empty</body-content> 5 </tag>
在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>
這裏我把自定義標籤置於JSP頁面最開始的地方,能夠看到若是沒有在session域中存入User對象的話,那麼這個JSP在被訪問後是不會看到任何東西的,查看網頁源碼也是沒有任何代碼。固然這個例子只是用來強調在doEndTag方法的返回值 「EVAL_PAGE」和 「SKIP_PAGE」的區別。
使用傳統的自定義標籤還能夠擴展一些其餘的功能,好比控制標籤體的內容重複執行,修改標籤體內容再輸出等等,這兩個功能涉及到使用Tag不一樣實現類的使用,將在下一篇博客中進行講解。