標籤:
javaweb學習總結(二十四)——jsp傳統標籤開發一、標籤技術的API1.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 @Override18 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 @Override17 public int doEndTag() throws JspException {18 //如果這個方法返回EVAL_PAGE,則執列標籤餘下的jsp頁面,如果返回SKIP_PAGE,則不執行餘下的jsp19 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 @Override12 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 @Override22 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 gacl13 * BodyTagSupport類實現了BodyTag介面介面,TagDemo4繼承 BodyTagSupport類14 */15 public class TagDemo4 extends BodyTagSupport {16 17 /* 控制doStartTag()方法返回EVAL_BODY_BUFFERED18 * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()19 */20 @Override21 public int doStartTag() throws JspException {22 return BodyTag.EVAL_BODY_BUFFERED;23 }24 25 @Override26 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簡單標籤的開發
javaweb學習總結(二十四)——jsp傳統標籤開發