javaweb學習總結(二十四)——jsp傳統標籤開發

一、標籤技術的API

1.1、標籤技術的API類繼承關係

  

二、標籤API簡單介紹

2.1、JspTag接口

  JspTag接口是所有自定義標籤的父接口,它是JSP2.0中新定義的一個標記接口,沒有任何屬性和方法。JspTag接口有Tag和SimpleTag兩個直接子接口,JSP2.0以前的版本中只有Tag接口,所以把實現Tag接口的自定義標籤也叫做傳統標籤,把實現SimpleTag接口的自定義標籤叫做簡單標籤

2.2、Tag接口

  Tag接口是所有傳統標籤的父接口,其中定義了兩個重要方法(doStartTag、doEndTag)方法和四個常量(EVAL_BODY_INCLUDE、SKIP_BODY、EVAL_PAGE、SKIP_PAGE),這兩個方法和四個常量的作用如下:

  (1)WEB容器在解釋執行JSP頁面的過程中,遇到自定義標籤的開始標記就會去調用標籤處理器的doStartTag方法,doStartTag方法執行完後可以向WEB容器返回常量EVAL_BODY_INCLUDE或SKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就會接着執行自定義標籤的標籤體;如果doStartTag方法返回SKIP_BODY,WEB容器就會忽略自定義標籤的標籤體,直接解釋執行自定義標籤的結束標記。

  (2)WEB容器解釋執行到自定義標籤的結束標記時,就會調用標籤處理器的doEndTag方法,doEndTag方法執行完後可以向WEB容器返回常量EVAL_PAGE或SKIP_PAGE。如果doEndTag方法返回常量EVAL_PAGE,WEB容器就會接着執行JSP頁面中位於結束標記後面的JSP代碼;如果doEndTag方法返回SKIP_PAGE,WEB容器就會忽略JSP頁面中位於結束標記後面的所有內容。

  從doStartTag和doEndTag方法的作用和返回值的作用可以看出,開發自定義標籤時可以在doStartTag方法和doEndTag方法體內編寫合適的Java程序代碼來實現具體的功能,通過控制doStartTag方法和doEndTag方法的返回值,還可以告訴WEB容器是否執行自定義標籤中的標籤體內容和JSP頁面中位於自定義標籤的結束標記後面的內容。

2.3、IterationTag接口

  IterationTag接口繼承了Tag接口,並在Tag接口的基礎上增加了一個doAfterBody方法和一個EVAL_BODY_AGAIN常量。實現IterationTag接口的標籤除了可以完成Tag接口所能完成的功能外,還能夠通知WEB容器是否重複執行標籤體內容。對於實現了IterationTag接口的自定義標籤,WEB容器在執行完自定義標籤的標籤體後,將調用標籤處理器的doAfterBody方法,doAfterBody方法可以向WEB容器返回常量EVAL_BODY_AGAIN或SKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAIN,WEB容器就會把標籤體內容再重複執行一次,執行完後接着再調用doAfterBody方法,如此往復,直到doAfterBody方法返回常量SKIP_BODY,WEB容器纔會開始處理標籤的結束標記和調用doEndTag方法。

  可見,開發自定義標籤時,可以通過控制doAfterBody方法的返回值來告訴WEB容器是否重複執行標籤體內容,從而達到循環處理標籤體內容的效果。例如,可以通過一個實現IterationTag接口的標籤來迭代輸出一個集合中的所有元素,在標籤體部分指定元素的輸出格式。

  在JSP API中也提供了IterationTag接口的默認實現類TagSupport,我們在編寫自定義標籤的標籤處理器類時,可以繼承和擴展TagSupport類,這相比實現IterationTag接口將簡化開發工作。

2.4、BodyTag接口

  BodyTag接口繼承了IterationTag接口,並在IterationTag接口的基礎上增加了兩個方法(setBodyContent、doInitBody)和一個EVAL_BODY_BUFFERED常量。實現BodyTag接口的標籤除了可以完成IterationTag接口所能完成的功能,還可以對標籤體內容進行修改。對於實現了BodyTag接口的自定義標籤,標籤處理器的doStartTag方法不僅可以返回前面講解的常量EVAL_BODY_INCLUDE或SKIP_BODY,還可以返回常量EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFERED,WEB容器就會創建一個專用於捕獲標籤體運行結果的BodyContent對象,然後調用標籤處理器的setBodyContent方法將BodyContent對象的引用傳遞給標籤處理器,WEB容器接着將標籤體的執行結果寫入到BodyContent對象中。在標籤處理器的後續事件方法中,可以通過先前保存的BodyContent對象的引用來獲取標籤體的執行結果,然後調用BodyContent對象特有的方法對BodyContent對象中的內容(即標籤體的執行結果)進行修改和控制其輸出。

  在JSP API中也提供了BodyTag接口的實現類BodyTagSupport,我們在編寫能夠修改標籤體內容的自定義標籤的標籤處理器類時,可以繼承和擴展BodyTagSupport類,這相比實現BodyTag接口將簡化開發工作。

2.5、 SimpleTag接口

  SimpleTag接口是JSP2.0中新增的一個標籤接口。由於傳統標籤使用三個標籤接口來完成不同的功能,顯得過於繁瑣,不利於標籤技術的推廣,因此,SUN公司爲降低標籤技術的學習難度,在JSP 2.0中定義了一個更爲簡單、便於編寫和調用的SimpleTag接口。SimpleTag接口與傳統標籤接口最大的區別在於,SimpleTag接口只定義了一個用於處理標籤邏輯的doTag方法,該方法在WEB容器執行自定義標籤時調用,並且只被調用一次。那些使用傳統標籤接口所完成的功能,例如是否執行標籤體、迭代標籤體、對標籤體內容進行修改等功能都可以在doTag方法中完成。

  在JSP API中也提供了SimpleTag接口的實現類SimpleTagSupport,我們在編寫簡單標籤時,可以繼承和擴展SimpleTagSupport類,這相比實現SimpleTag接口將簡化開發工作。

2.6、傳統標籤接口中的各個方法可以返回的返回值說明

  下圖列舉了Tag接口、IterationTag接口和BodyTag接口中的主要方法及它們分別可以返回的返回值的說明。

  

三、開發傳統標籤實現頁面邏輯

  開發人員在編寫Jsp頁面時,經常還需要在頁面中引入一些邏輯,例如:

  • 控制jsp頁面某一部分內容是否執行。
  • 控制整個jsp頁面是否執行。
  • 控制jsp頁面內容重複執行。
  • 修改jsp頁面內容輸出。

  自定義標籤除了可以移除jsp頁面java代碼外,它也可以實現以上功能。

3.1、控制jsp頁面某一部分內容是否執行  

  編寫一個類實現tag接口,控制doStartTag()方法的返回值,如果這個方法返回EVAL_BODY_INCLUDE,則執行標籤體,如果返回SKIP_BODY,則不執行標籤體。

  SUN公司針對tag接口提供了一個默認的實現類TagSupport,TagSupport類中實現了tag接口的所有方法,因此我們可以編寫一個類繼承TagSupport類,然後再重寫doStartTag方法。

示例代碼如下:

TagDemo1.java

複製代碼
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.Tag;
 5 import javax.servlet.jsp.tagext.TagSupport;
 6 
 7 /**
 8  * @author gacl
 9  * TagSupport類實現了Tag接口,TagDemo1繼承TagSupport類
10  * 
11  */
12 public class TagDemo1 extends TagSupport {
13 
14     /* 重寫doStartTag方法,控制標籤體是否執行
15      * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
16      */
17     @Override
18     public int doStartTag() throws JspException {
19         //如果這個方法返回EVAL_BODY_INCLUDE,則執行標籤體,如果返回SKIP_BODY,則不執行標籤體
20         //return Tag.EVAL_BODY_INCLUDE;
21         return Tag.SKIP_BODY;
22     }
23 }
複製代碼

  在WEB-INF目錄下的tld文件中添加對該標籤處理類的描述,如下:

複製代碼
1 <tag>
2         <name>demo1</name>
3         <tag-class>me.gacl.web.tag.TagDemo1</tag-class>
4         <!--demo1標籤有標籤體,所以這裏的body-content設置爲JSP-->
5         <body-content>JSP</body-content>
6 </tag>
複製代碼

  在jsp頁面中導入並使用自定義標籤,如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp頁面中導入自定義標籤庫 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制標籤體是否執行</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp頁面中使用自定義標籤 demo1標籤是帶有標籤體的,標籤體的內容是"孤傲蒼狼"這幾個字符串--%>
12     <gacl:demo1>
13         孤傲蒼狼
14     </gacl:demo1>
15   </body>
16 </html>
複製代碼

  運行效果如下:

 

3.2、控制整個jsp頁面是否執行

  編寫一個類實現tag接口,控制doEndTag()方法的返回值,如果這個方法返回EVAL_PAGE,則執行標籤餘下的jsp頁面,如果返回SKIP_PAGE,則不執行餘下的jsp。

示例代碼如下:

TagDemo2.java

複製代碼
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.Tag;
 5 import javax.servlet.jsp.tagext.TagSupport;
 6 
 7 /**
 8  * @author gacl
 9  * TagSupport類實現了Tag接口,TagDemo2繼承TagSupport類
10  */
11 public class TagDemo2 extends TagSupport{
12 
13     /* 重寫doEndTag方法,控制jsp頁面是否執行
14      * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
15      */
16     @Override
17     public int doEndTag() throws JspException {
18         //如果這個方法返回EVAL_PAGE,則執行標籤餘下的jsp頁面,如果返回SKIP_PAGE,則不執行餘下的jsp
19         return Tag.SKIP_PAGE;
20         //return Tag.EVAL_PAGE;
21     }
22 
23     
24 }
複製代碼

  在WEB-INF目錄下的tld文件中添加對該標籤處理類的描述,如下:

複製代碼
1 <tag>
2         <name>demo2</name>
3         <tag-class>me.gacl.web.tag.TagDemo2</tag-class>
4         <!--demo2標籤沒有標籤體,所以這裏的body-content設置爲empty-->
5         <body-content>empty</body-content>
6 </tag>
複製代碼

  在jsp頁面中導入並使用自定義標籤,如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp頁面中導入自定義標籤庫 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制jsp頁面是否執行</title>
 8   </head>
 9   
10   <body>
11          <h1>jsp頁面的內容1</h1>
12          <%--在jsp頁面中使用自定義標籤 demo2標籤是不帶標籤體的--%>
13          <gacl:demo2/>
14          <h1>jsp頁面的內容2</h1>
15   </body>
16 </html>
複製代碼

  運行效果如下:

 

3.3、控制jsp頁面內容重複執行

  編寫一個類實現Iterationtag接口,控制doAfterBody()方法的返回值,如果這個方法返回EVAL_BODY_AGAIN, 則web服務器又執行一次標籤體,依次類推,一直執行到doAfterBody方法返回SKIP_BODY,則標籤體纔不會重複執行。

示例代碼如下:

TagDemo3.java

複製代碼
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.IterationTag;
 5 import javax.servlet.jsp.tagext.Tag;
 6 import javax.servlet.jsp.tagext.TagSupport;
 7 
 8 public class TagDemo3 extends TagSupport {
 9 
10     int x = 5;
11     @Override
12     public int doStartTag() throws JspException {
13         return Tag.EVAL_BODY_INCLUDE;
14     }
15     
16     /* 控制doAfterBody()方法的返回值,
17      * 如果這個方法返回EVAL_BODY_AGAIN, 則web服務器又執行一次標籤體,
18      * 依次類推,一直執行到doAfterBody方法返回SKIP_BODY,則標籤體纔不會重複執行。
19      * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()
20      */
21     @Override
22     public int doAfterBody() throws JspException {
23         x--;
24         if(x>0){
25             return IterationTag.EVAL_BODY_AGAIN;
26         }else{
27             return IterationTag.SKIP_BODY;
28         }
29     }
30 
31 }
複製代碼

  在WEB-INF目錄下的tld文件中添加對該標籤處理類的描述,如下:

複製代碼
1 <tag>
2         <name>demo3</name>
3         <tag-class>me.gacl.web.tag.TagDemo3</tag-class>
4         <!--demo3標籤有標籤體,所以這裏的body-content設置爲JSP-->
5         <body-content>JSP</body-content>
6 </tag>
複製代碼

  在jsp頁面中導入並使用自定義標籤,如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp頁面中導入自定義標籤庫 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制頁面內容重複執行5次</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp頁面中使用自定義標籤 demo3標籤--%>
12       <gacl:demo3>
13           <h3>jsp頁面的內容</h3>
14       </gacl:demo3>
15   </body>
16 </html>
複製代碼

  運行效果如下:

  

3.4、修改jsp頁面內容輸出

  編寫一個類實現BodyTag接口,控制doStartTag()方法返回EVAL_BODY_BUFFERED,則web服務器會創建BodyContent對象捕獲標籤體,然後在doEndTag()方法體內,得到代表標籤體的bodyContent對象,從而就可以對標籤體進行修改操作。

  SUN公司針對BodyTag接口提供了一個默認的實現類BodyTagSupport,BodyTagSupport類中實現了BodyTag接口的所有方法,因此我們可以編寫一個類繼承BodyTagSupport類,然後再根據需要重寫doStartTag方法和doEndTag()方法。

示例代碼如下:

TagDemo4.java

複製代碼
 1 package me.gacl.web.tag;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.jsp.JspException;
 6 import javax.servlet.jsp.tagext.BodyContent;
 7 import javax.servlet.jsp.tagext.BodyTag;
 8 import javax.servlet.jsp.tagext.BodyTagSupport;
 9 import javax.servlet.jsp.tagext.Tag;
10 
11 /**
12  * @author gacl
13  * BodyTagSupport類實現了BodyTag接口接口,TagDemo4繼承 BodyTagSupport類
14  */
15 public class TagDemo4 extends BodyTagSupport {
16 
17     /* 控制doStartTag()方法返回EVAL_BODY_BUFFERED
18      * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()
19      */
20     @Override
21     public int doStartTag() throws JspException {
22         return BodyTag.EVAL_BODY_BUFFERED;
23     }
24     
25     @Override
26     public int doEndTag() throws JspException {
27         
28         //this.getBodyContent()得到代表標籤體的bodyContent對象
29         BodyContent bodyContent = this.getBodyContent();
30         //拿到標籤體
31         String content = bodyContent.getString();
32         //修改標籤體裏面的內容,將標籤體的內容轉換成大寫
33         String result = content.toUpperCase();
34         try {
35             //輸出修改後的內容
36             this.pageContext.getOut().write(result);
37         } catch (IOException e) {
38             throw new RuntimeException(e);
39         }
40         
41         return Tag.EVAL_PAGE;
42     }
43 }
複製代碼

  在WEB-INF目錄下的tld文件中添加對該標籤處理類的描述,如下:

複製代碼
1 <tag>
2         <name>demo4</name>
3         <tag-class>me.gacl.web.tag.TagDemo4</tag-class>
4         <!--demo4標籤有標籤體,所以這裏的body-content設置爲JSP-->
5         <body-content>JSP</body-content>
6 </tag>
複製代碼

  在jsp頁面中導入並使用自定義標籤,如下:

複製代碼
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp頁面中導入自定義標籤庫 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>修改jsp頁面內容輸出</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp頁面中使用自定義標籤 demo4標籤--%>
12       <gacl:demo4>
13           <h3>xdp_gacl</h3>
14       </gacl:demo4>
15   </body>
16 </html>
複製代碼

  運行效果如下:

  

四、jsp傳統標籤開發總結

  在現在的jsp標籤開發中,很少直接使用傳統標籤來開發了,目前用得較多的都是簡單標籤,所以Jsp的傳統標籤開發瞭解一下即可,下一篇重點介紹jsp簡單標籤的開發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章