更新時(shí)間:2021年11月22日11時(shí)07分 來(lái)源:傳智教育 瀏覽次數(shù):
在實(shí)現(xiàn)自定義標(biāo)簽時(shí),有時(shí)需要對(duì)標(biāo)簽體的內(nèi)容進(jìn)行處理以后再向?yàn)g覽器輸出,比如將小寫(xiě)英文字母轉(zhuǎn)化為大寫(xiě),將HTML標(biāo)簽進(jìn)行轉(zhuǎn)義等。為了實(shí)現(xiàn)這樣的功能,JSP規(guī)范中它義了一個(gè)BodyTag接口,它繼承自IterationTag接口,并在IterationTag接口基礎(chǔ)上新增了兩個(gè)方法和一個(gè)靜態(tài)常量,具體如下。
1. EVAL_BODY_BUFFERED常量
如果標(biāo)簽處理器類(lèi)實(shí)現(xiàn)了BodyTag接口,它的doStartTag()方法除了可以返回SKIP_BODY和EVAL_BODY_INCLUDE常量之外,還可以返回EVAL_BODY_BUFFERED常量。當(dāng)doStartTag()方法返回EVAL_BODY_BUFFERED常量時(shí),JSP容器將會(huì)創(chuàng)建個(gè)javax.servlet.jsp.tagext.BodyContent對(duì)象,使用該對(duì)象來(lái)執(zhí)行標(biāo)簽體。關(guān)于BodyContent類(lèi)的用法,將在下面進(jìn)行詳細(xì)的講解。
2. setBodyContent(BodyContent b)方法
當(dāng)且僅當(dāng)doStartTag()方法返回EVAL_BODY_BUFFERED常量時(shí),JSP容器才會(huì)調(diào)用setBodyContent()方法,通過(guò)該方法將BodyContent對(duì)象傳遞給標(biāo)簽處理器類(lèi)使用。
3. dolnitBody()方法
JSP容器在調(diào)用setBodyContent()方法后會(huì)調(diào)用doInitBody()方法來(lái)完成些初始化工作,該方法的調(diào)用在標(biāo)簽體執(zhí)行之前。
其中,最重要的是setBodyContent()方法。為了幫助大家更好地理解BodyTag接口處理標(biāo)簽內(nèi)容的方式,有必要對(duì)BodyContent類(lèi)進(jìn)行詳細(xì)講解。
BodyContent類(lèi)是JspWriter類(lèi)的子類(lèi),它在JspWriter的基礎(chǔ)上增加了一個(gè)用于存儲(chǔ)數(shù)據(jù)的緩沖區(qū)(確切地說(shuō)緩沖區(qū)是在BodyContent的子類(lèi)org.apache.jasper.runtime.BodyContentImple中定義的),當(dāng)調(diào)用BodyContent對(duì)象的方法寫(xiě)數(shù)據(jù)時(shí),數(shù)據(jù)將被寫(xiě)人到BodyContent內(nèi)部的緩沖區(qū)中。
明白了BodyContent類(lèi)的這個(gè)特點(diǎn),就不難理解JSP容器是如何利用BodyContent對(duì)象來(lái)處理標(biāo)簽體內(nèi)容了。當(dāng)標(biāo)簽處理器類(lèi)的doStartTag()方法返回EVAL_BODY_BUFFERED常量時(shí),JSP容器會(huì)創(chuàng)建一個(gè)BodyContent對(duì)象,然后調(diào)用該對(duì)象的write()方法將標(biāo)簽體的內(nèi)容寫(xiě)人BodyContent對(duì)象的緩沖區(qū)中,開(kāi)發(fā)者只要能夠訪問(wèn)BodyContent緩沖區(qū)的內(nèi)容,就能對(duì)標(biāo)簽體的內(nèi)容進(jìn)行處理。在BodyContent類(lèi)中定義了一些用于訪問(wèn)緩沖區(qū)內(nèi)容的方法,具體如下表所示。
BodyContent類(lèi)的常用方法 |
|
方法聲明 |
功能描述 |
String getString() | 以字符串的形式返回BodyContent對(duì)象緩沖區(qū)中保存的數(shù)據(jù) |
Reader getReader() | 返回一個(gè)關(guān)聯(lián)BodyContent對(duì)象緩沖區(qū)中數(shù)據(jù)的Reader對(duì) 象,通過(guò)Reader對(duì)象可以讀取緩沖區(qū)中的數(shù)據(jù) |
void clearBody() | 用于清空BodyContent對(duì)象緩沖區(qū)中的內(nèi)容 |
JspWriter getEnclosingWriter() | 用于返回BodyContent對(duì)象中關(guān)聯(lián)的JspWriter對(duì)象。當(dāng)JSP容器創(chuàng)建BodyContent對(duì)象后,PageContext對(duì)象中的"out"屬性不再指向JSP的隱式對(duì)象,而是指向新創(chuàng)建的BodyContent對(duì)象。同時(shí),在BodyContent對(duì)象中會(huì)用一個(gè)JspWriter類(lèi)型的成員變量enclosingWriter記住原來(lái)的隱式對(duì)象,getEnclosingWriter()方 法返回的就是原始的JSP隱式對(duì)象 |
writerOut(Writer out) | 用于將BodyContent對(duì)象中的內(nèi)容寫(xiě)人到指定的輸出流 |
在上表列舉的所有方法中,其中g(shù)etEnclosingWriter()方法最難理解,但是,只需要記住該方法的返回值為out即可。
除了BodyContent類(lèi)外,在BodyTag接口還會(huì)涉及很多常量和方法,為了讓大家更好地掌握標(biāo)簽處理器的執(zhí)行流程,接下來(lái)通過(guò)一張圖來(lái)描述,具體如下圖所示。
標(biāo)簽處理器的執(zhí)行流程
上圖中清楚地描述了JSP容器執(zhí)行標(biāo)簽處理器的過(guò)程。其中,release()方法之所以使用用虛線,是因?yàn)檫@個(gè)方法不會(huì)在標(biāo)簽處理器每次執(zhí)行都被JSP容器調(diào)用,只有當(dāng)標(biāo)簽處理器對(duì)象作為垃圾被回收之前它才會(huì)被調(diào)用。傳統(tǒng)標(biāo)簽的處理器是單例的,只會(huì)被創(chuàng)建和銷(xiāo)毀一次。
接下來(lái),通過(guò)實(shí)現(xiàn)自定義標(biāo)簽,學(xué)習(xí)如何使用BodyTag接口將標(biāo)簽體中的小寫(xiě)英文字母轉(zhuǎn)換為大寫(xiě),具體步驟如下。
(1)編寫(xiě)標(biāo)簽處理器類(lèi)ToUpperCase.java。
JSP規(guī)范中定義了一個(gè)類(lèi)BodyTagSupport實(shí)現(xiàn)了BodyTag接口,為了簡(jiǎn)化程序的編寫(xiě),標(biāo)簽處理器類(lèi)ToUpperCase.java只需要繼承BodyTagSupport類(lèi)即可。ToUpperCase.java類(lèi)的實(shí)現(xiàn)代碼如下例所示。
package cn.itcast.chapter09.classisctag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; public class ToUpperCase extends BodyTagSupport { //定義doEndTag()方法 public int doEndTag() throws JspException { //獲取級(jí)沖區(qū)中數(shù)據(jù) String content = getBodyContent().getString(); //將數(shù)據(jù)轉(zhuǎn)為大寫(xiě) content = content.toUpperCase(); try{ //輸出數(shù)據(jù)內(nèi)容(兩種方式均可) //pageContext.getout().write(content); bodyContent.getEnclosingWriter().write(content); } catch(IOException e){ e.printStackTrace(); return super.doEndTag(); } }
由于BodyTagSupport類(lèi)中的doStartTag()方法默認(rèn)返回EVAL_BODY_BUFFERED常量,JSP容器會(huì)在執(zhí)行標(biāo)簽體之前創(chuàng)建BodyContent對(duì)象,然后將標(biāo)簽體內(nèi)容通過(guò)setBodyContent()方法設(shè)置給BodyContent對(duì)象。因此在上面案例中的doEndTag()方法中可以直接使用getBodyContent()方法的getString()方法獲得寫(xiě)人到BodyContent緩沖區(qū)中的內(nèi)容,然后將其轉(zhuǎn)換為大寫(xiě),通過(guò)調(diào)用getEnclosingWriter()方法獲取到out對(duì)象,將內(nèi)容輸出到瀏覽器中。
注意:不能直接使用doStartTag()方法的原因是,執(zhí)行doStartTag()方法時(shí),BodyContent對(duì)象中還沒(méi)有緩存標(biāo)簽體的內(nèi)容,因此通過(guò)getBodyContent()方法還無(wú)法獲得標(biāo)簽的內(nèi)容。
(2)注冊(cè)標(biāo)簽處理器類(lèi)。
在mytag.tld文件中增加一個(gè)Tag元素,對(duì)標(biāo)簽處理器類(lèi)進(jìn)行注冊(cè),注冊(cè)信息如下所示。
<tag> <name>toUpperCase</name> <tag-class> cn.itcast.chapter09.classisctag.ToUpperCase</tag-class> <body-content>JSP</body-content> </tag>
(3)編寫(xiě)JSP頁(yè)面toUpperCase.jsp
在JSP頁(yè)面中使用標(biāo)簽,在標(biāo)簽體中寫(xiě)人26個(gè)小寫(xiě)的英文字母,如下例所示。
<%@page language="java" pageEncoding="GBK"%> <%@taglib uri= "http://m.8y3kgpwe.cn" prefix="itcast"%> <html> <head> <title>HelloWorld Tag</title> </head> <body> <itcast: toUpperCase> abcde fghij klmnopqrstuvwxyz </itcast:toUpperCase> </body> </html>
(4)啟動(dòng)Tomcat服務(wù)器,在瀏覽器地址欄中輸人URL地址“http://localhost:8080/chapter09/toUpperCase.jsp”訪問(wèn)toUpperCase.jsp頁(yè)面,從運(yùn)行結(jié)果可以看出,自定義標(biāo)簽成功地將標(biāo)簽體中的小寫(xiě)英文字母轉(zhuǎn)換為大寫(xiě)。
猜你喜歡
北京校區(qū)