返回值????????????????????????????????意義
SKIP_BODY?????????????????????????表示不用處理標(biāo)簽體,直接調(diào)用doEndTag()方法。
SKIP_PAGE??????????????????????????忽略標(biāo)簽后面的JSP內(nèi)容。
EVAL_PAGE?????????????????????????處理標(biāo)簽后,繼續(xù)處理JSP后面的內(nèi)容。?
EVAL_BODY_BUFFERED?????????表示需要處理標(biāo)簽體。
EVAL_BODY_INCLUDE???????????表示需要處理標(biāo)簽體,但繞過(guò)setBodyContent()和doInitBody()方法
EVAL_BODY_AGAIN??????????????對(duì)標(biāo)簽體循環(huán)處理。?
標(biāo)簽庫(kù)Taglib
標(biāo)簽被定義和分布在一個(gè)稱為標(biāo)簽庫(kù)的結(jié)構(gòu)中,一個(gè)標(biāo)簽庫(kù)是由元信息和類(lèi)組成的集合:
1.標(biāo)簽處理器(JAVA):實(shí)現(xiàn)定制標(biāo)簽功能的Java類(lèi)。
2.標(biāo)簽附加信息(TEI):向JSP容器提供編輯以確認(rèn)標(biāo)簽屬性和創(chuàng)建變量的類(lèi)。
3.標(biāo)簽庫(kù)描述器(TLD):描述單個(gè)標(biāo)簽和整個(gè)標(biāo)簽庫(kù)屬性的XML文檔。
標(biāo)簽處理器(JAVA)和標(biāo)簽附加信息(TEI)需要定位在 JSP容器類(lèi) 載入器 可以找到的地方。標(biāo)簽庫(kù)描述器(TLD)可在URL指定的符意位置。
一、標(biāo)簽實(shí)現(xiàn)
1. 開(kāi)發(fā)步驟
a.定義標(biāo)簽的名字、屬性、聲明的變量和標(biāo)簽體的內(nèi)容。
b.編寫(xiě)標(biāo)簽庫(kù)描述器TLD。
c.編寫(xiě)標(biāo)簽處理器。
d.在JSP頁(yè)面中使用標(biāo)簽。
2. JSP頁(yè)面在JSP容器中的轉(zhuǎn)換步驟:
JSP頁(yè)面存在三種形式:
a.指令元素、和向JSP容器提供轉(zhuǎn)換時(shí)信息。
b.HTML行在_jspService()方法中依順序轉(zhuǎn)換到out.print()語(yǔ)名中。
c.腳本元素的聲明被原封不動(dòng)地復(fù)制到_jspService()方法外的源碼中。
d.腳本元素的表達(dá)式在_jspService()方法中依順序轉(zhuǎn)換到out.print()語(yǔ)名中。
e.腳本元素的Scriptlet被原封不動(dòng)地復(fù)制到_jspService()方法中。
f.行為元素被轉(zhuǎn)換為執(zhí)行其功能的運(yùn)行時(shí)邏輯代碼。
g.定制標(biāo)簽被擴(kuò)展到調(diào)用其相應(yīng)標(biāo)簽處理器中方法的Java語(yǔ)句中。
3.標(biāo)簽在JSP容器中的轉(zhuǎn)換步驟:
a.JSP容器使用taglib指令元素定位標(biāo)簽庫(kù)描述器,將頁(yè)面中用到的定制標(biāo)簽和TLD相匹配。
b.讀取標(biāo)簽庫(kù)描述器的標(biāo)簽列表和每一標(biāo)簽相關(guān)的類(lèi)名字。
c.在頁(yè)面中遇到一個(gè)標(biāo)簽時(shí),查找與具有指定名字的標(biāo)簽前綴相關(guān)的一個(gè)標(biāo)簽庫(kù)。
d.容器使用在TLD中找到的標(biāo)簽結(jié)構(gòu)信息生成一系列完成標(biāo)簽功能的Java語(yǔ)句。
二、標(biāo)簽庫(kù)描述器(TLD)
標(biāo)簽庫(kù)描述器是一個(gè)描述 整個(gè)標(biāo)簽庫(kù)標(biāo)記信息 和 庫(kù)中每個(gè)標(biāo)簽處理器 及 其屬性 的XML文檔。
標(biāo)簽庫(kù)描述器的DTD由一個(gè)簡(jiǎn)單的元素組成,此元素包含下列一些子元素。
1 : 整個(gè)標(biāo)簽庫(kù)標(biāo)記信息
<
tlib
-
version
>
1.0
</
tlib
-
version
>
標(biāo)簽庫(kù)版本號(hào)。是一個(gè)點(diǎn)式十進(jìn)制數(shù),最多為4組小數(shù)點(diǎn)分隔的數(shù)字組成。
??
<
jsp
-
version
>
1.2
</
jsp
-
version
>
標(biāo)簽庫(kù)所需的JSP規(guī)范最低版本。例如JSP1.1
??
<
short
-
name
>
wentao
</
short
-
name
>
標(biāo)簽庫(kù)的縮寫(xiě)名。JSP可以使用該名字作為庫(kù)中標(biāo)簽的缺省前綴。
<
uri
>
http:
//
www.wentao.com/taglibs/wentao</uri>
標(biāo)簽庫(kù)唯一URI的元素。典型URL位置來(lái)自可下載taglib的位置。
<
description
>
wentao Tage Liberary.
</
description
>
標(biāo)簽庫(kù)描述信息。
2 : 每個(gè)標(biāo)簽處理器及其屬性 (以displaytag-11.tld為例)
????
<
tag
>
????????
<
name
>
table
</
name
>
????????
<
tagclass
>
org.displaytag.tags.TableTag
</
tagclass
>
????????
<
teiclass
>
org.displaytag.tags.TableTagExtraInfo
</
teiclass
>
????????
<
bodycontent
>
JSP
</
bodycontent
>
????????
<
info
>
my?name?is?liuwentao
</
info
>
????????
<
attribute
>
????????????
<
name
>
list
</
name
>
????????????
<
required
>
false
</
required
>
????????????
<
rtexprvalue
>
true
</
rtexprvalue
>
????????
</
attribute
>
????
.

????
</
tag
>
tag在TLD中加入標(biāo)簽,描述組成庫(kù)的每個(gè)標(biāo)簽。
????????
<
name
>
table
</
name
>
name與標(biāo)簽庫(kù)的名字前綴一起使用的標(biāo)簽的名字,是JSP容器唯一的標(biāo)簽標(biāo)識(shí) <wentao:table/>。
<
tagclass
>
org.displaytag.tags.TableTag
</
tagclass
>
tagclass實(shí)現(xiàn)標(biāo)簽的標(biāo)簽處理器類(lèi)的全名。
<
teiclass
>
org.displaytag.tags.TableTagExtraInfo
</
teiclass
>
teiclass標(biāo)簽附加信息(TEI)類(lèi)的全名。TEI類(lèi)給出關(guān)于標(biāo)簽處理器創(chuàng)建變量及對(duì)標(biāo)簽屬性性執(zhí)行的任意有效性驗(yàn)證的信息。
????????
<
bodycontent
>
JSP
</
bodycontent
>
bodycontent描述標(biāo)簽處理器如何使用標(biāo)簽體的內(nèi)容。有三種取值:
empty:表示標(biāo)簽體必須為空;
JSP:表示腳本元素和模板及其它標(biāo)簽一樣被評(píng)估。
tagdependent:體內(nèi)容被原封不動(dòng)寫(xiě)入BodyContent,其它腳本元素以源碼形式出現(xiàn),而不被JSP容器解釋。
?
????????
<
info
>
my?name?is?liuwentao
</
info
>
info標(biāo)簽的人工可讀描述性信息。
?????<attribute>
??????????? <name>list</name>
??????????? <required>false</required>
??????????? <rtexprvalue>true</rtexprvalue>
??????? </attribute>
attribute使用標(biāo)簽時(shí)被編碼的屬性信息。用于定義標(biāo)簽的屬性。
3?:屬性:
???????????? <name>list</name>
屬性的名字。
??????????? <required>false</required>
true|false:屬性在標(biāo)簽用到的位置是否要被編碼。
??????????? <rtexprvalue>true</rtexprvalue>
true|false:屬性值能否用表達(dá)式指定。
三、標(biāo)簽處理器
標(biāo)簽處理器是通過(guò)實(shí)現(xiàn)JSP容器調(diào)用的一系列預(yù)定義方法執(zhí)行定制標(biāo)簽行為的一個(gè)Java類(lèi)。
標(biāo)簽處理器實(shí)現(xiàn)了標(biāo)簽的行為,標(biāo)簽處理器是Java類(lèi)。
1. 標(biāo)簽處理器的工作方式
a.導(dǎo)入javax.servlet.jsp和javax.servlet.jsp.tagext包。
b.實(shí)現(xiàn)javax.servlet.jsp.tagext包中的Tag接口或BodyTag接口。BodyTag是Tag的子接口。
c.繼承TagSupport類(lèi)或BodyTagSuppoert類(lèi)。它們是上述接口的缺省實(shí)現(xiàn)。
d.重載public int doStartTag() throws JspException方法。
2.標(biāo)簽處理器的接口與實(shí)現(xiàn)
javax.servlet.jsp.tagext.Tag是實(shí)現(xiàn)標(biāo)簽的最基本的接口。
javax.servlet.jsp.tagext.TagSupport是實(shí)現(xiàn)Tag接口的具體類(lèi)。
通常情況下繼承tagSupport類(lèi)而不直接實(shí)現(xiàn)Tag接口通常是有益的。除了對(duì)所有必需方法提供了缺省實(shí)現(xiàn)外、還保存了pageContext對(duì)象及對(duì)嵌套標(biāo)簽的支持。
Tag接口包含4個(gè)常量
,表示doStartTag()和doEndTag()方法可能的返回碼。
?????????//?表示需要處理標(biāo)簽體。?
????????int?EVAL_BODY_INCLUDE?=?1;
EVAL_BODY_INCLUDE 當(dāng)doStartTag()返回時(shí),指明servlet應(yīng)對(duì) 標(biāo)簽體 進(jìn)行評(píng)估。
?????//?處理標(biāo)簽后,繼續(xù)處理JSP后面的內(nèi)容。
????int?EVAL_PAGE?=?6;
EVAL_PAGE當(dāng)doEndTag()返回時(shí),指明頁(yè)面其余部分應(yīng)被評(píng)估。
???? //表示不用處理標(biāo)簽體,直接調(diào)用doEndTag()方法。
????int?SKIP_BODY?=?0;
SKIP_BODY當(dāng)doStartTag()返回時(shí),指明servlet應(yīng)忽視標(biāo)簽體。
?????//忽略標(biāo)簽后面的JSP內(nèi)容。
????int?SKIP_PAGE?=?5;
SKIP_PAGE當(dāng)doEndTag()返回時(shí),指明頁(yè)面其余部分就被跳過(guò)。
注 :body 這2個(gè)是 doStartTag()方法里面調(diào)用的。
????????? page 這2個(gè)是? doEndTag()方法里面調(diào)用的。
Tag接口的方法
1 :生成的servlet在請(qǐng)求處理器執(zhí)行其它任務(wù)前首先調(diào)用此方法
?
public
?
void
?setPageContext(javax.servlet.jsp.PageContext?pageContext)?
,實(shí)現(xiàn)類(lèi)應(yīng)保存上下文對(duì)象以便它可以在標(biāo)簽生命期中使用,從頁(yè)面上下文中標(biāo)簽處理器可以訪問(wèn)所有JSP隱含對(duì)象。
2 :使用一個(gè)標(biāo)答可以找到操作棧中它上面的標(biāo)簽
public
?
void
?setParent(javax.servlet.jsp.tagext.Tag?tag)
。在setPageContext后立即調(diào)用
?
public
?javax.servlet.jsp.tagext.Tag?getParent()
返回父標(biāo)簽。
3 :在設(shè)置了頁(yè)面上下文、父標(biāo)簽和開(kāi)始標(biāo)記中編碼的屬性后調(diào)用
????
public
?
int
?doStartTag()?
throws
?javax.servlet.jsp.JspException?
。返回碼表明JSP實(shí)現(xiàn)servlet是否就評(píng)估標(biāo)簽體。
4 :當(dāng)遇到結(jié)否標(biāo)記時(shí)調(diào)用
????
public
?
int
?doEndTag()?
throws
?javax.servlet.jsp.JspException
。返回碼表明JSP是否就繼紐頁(yè)面的其余部份。
5 :確保在頁(yè)面退出前被調(diào)用
????public?void?release()
,釋放資源并重置標(biāo)簽處理器狀態(tài)。
TagSupport類(lèi)的方法
1 :為所需的父標(biāo)簽處理器查找運(yùn)行時(shí)標(biāo)簽棧。一個(gè)標(biāo)簽處理器可以提供其范圍內(nèi)子標(biāo)簽調(diào)用的方法 :
public?static?final?javax.servlet.jsp.tagext.Tag?findAncestorWithClass(javax.servlet.jsp.tagext.Tag?tag,?java.lang.Class?aClass)
2 :保存和檢索在id屬性中指定的名字 :
????public?void?setId(java.lang.String?string)?
3 :在本地哈希表中設(shè)置指定名字的值 :
public?void?setValue(java.lang.String?string,?java.lang.Object?object)
4 :從本地哈希表中獲取指定名稱的值 :
public?java.lang.Object?getValue(java.lang.String?string)
5 :從本地哈希表中刪除指定名稱的值 :
public?void?removeValue(java.lang.String?string)
6 :返回哈希表中關(guān)鍵字的一個(gè)枚舉 :
public?java.util.Enumeration?getValues()
?
3. 標(biāo)簽處理器的生命期
以
???前面的內(nèi)容?
<
br
>
???
<
mytag:helloworld
></
mytag:helloworld
>
???后面的內(nèi)容
為例 :

a.生成servlet需要?jiǎng)?chuàng)建標(biāo)簽處理器類(lèi)的一個(gè)實(shí)例。實(shí)現(xiàn)方式通常是調(diào)用JSP容器的工廠類(lèi)的一個(gè)方法,
工廠類(lèi) 包含一個(gè)標(biāo)簽處理器實(shí)例池 以使其可重用 不再處于激活狀態(tài)的對(duì)象。
b.初始化標(biāo)簽處理器,使servlet獲知其存在性。servlet通過(guò)調(diào)用標(biāo)簽處理器的兩個(gè)方法實(shí)現(xiàn)此過(guò)程:
?? public?void?setPageContext(javax.servlet.jsp.PageContext?pageContext)

public?void?setParent(javax.servlet.jsp.tagext.Tag?tag)
c.如果標(biāo)簽具有屬性,屬性的取值通過(guò)處理器提供setter方法傳入到對(duì)象。屬性setter方法是一個(gè)標(biāo)簽支持屬性所需的唯一方法。
d.頁(yè)面的上下文和父標(biāo)簽已被調(diào)置,并已具備屬性。此時(shí)調(diào)用標(biāo)簽處理器的doStartTag()方法,該方法可以讀取這些變量并執(zhí)行實(shí)現(xiàn)標(biāo)答功能所需的計(jì)算和操作。doStartTag()方法必須返回一個(gè)整型數(shù)。返回EVAL_BODY_INCLUDE則正常處理標(biāo)簽體,返回SKIP_BODY則忽略標(biāo)簽體
e.標(biāo)簽體被評(píng)估或忽視后調(diào)用標(biāo)簽處理器的doEndTag()方法,返回EVAL_PAGE則頁(yè)面的其余部分被評(píng)估,返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。
4.體標(biāo)簽處理器的接口與實(shí)現(xiàn)
javax.servlet.jsp.tagext.BodyTag是Tag的子接口。
javax.servlet.jsp.tagext.BodyTagSupport是實(shí)現(xiàn)BodyTag類(lèi)。
BodyTagSupport 有一個(gè)這樣的方法 :
?public?void?setBodyContent(javax.servlet.jsp.tagext.BodyContent?bodyContent)?
BodyContent是javax.servlet.jsp.JspWriter的子類(lèi),但與其父類(lèi)有所區(qū)別。
public?abstract?
class
?BodyContent?extends?javax.servlet.jsp.JspWriter
BodyContent對(duì)象的內(nèi)容不自動(dòng)寫(xiě)了入servlet的輸出流,而是積累在一字符串緩存中。當(dāng)標(biāo)簽體完成后 其對(duì)象 仍可在doEndTag()方法中可以應(yīng)用,由getString()或getReader()方法操作。并在必要時(shí)修改及寫(xiě)入恢復(fù)的JspWriter輸出流。
BodyContent類(lèi)的方法
??public?void?flush()?throws?java.io.IOException
復(fù)寫(xiě)JspWrite.flush()方法以便它總是產(chǎn)生溢出。
public?void?clearBody()
重置BodyContent緩存為空。
????public?abstract?java.io.Reader?getReader();
返回Reader讀取體內(nèi)容。
????public?abstract?java.lang.String?getString();
返回包含體內(nèi)容的一個(gè)字符串。
????public?abstract?void?writeOut(java.io.Writer?writer)?throws?java.io.IOException;
將體內(nèi)容寫(xiě)入指定輸出。
?public?javax.servlet.jsp.JspWriter?getEnclosingWriter()
返回棧中下一個(gè)更高的寫(xiě)入者對(duì)象(可能是另一個(gè)BodyContent對(duì)象)。
BodyTag接口定義了一個(gè)新的整型常量
EVAL_BODY_TAG當(dāng)doStartTag()返回時(shí),使得新的BodyContent對(duì)象被創(chuàng)建并與此標(biāo)簽處理器相關(guān)聯(lián)。當(dāng)doAfterBody()返回時(shí),使得JSPservlet在修改完此標(biāo)簽控制的任意變量后再次評(píng)估體。
BodyTag接口的方法
void?setBodyContent(javax.servlet.jsp.tagext.BodyContent?bodyContent);
在當(dāng)前JspWriter已被寫(xiě)入,一個(gè)新的BodyContent在被創(chuàng)建后由Jspservlet調(diào)用,它發(fā)生在doStartTag()之后。
?void?doInitBody()?throws?javax.servlet.jsp.JspException;
setBodyContent()之后,體被評(píng)估前調(diào)用的生命期方法。如果多次評(píng)估體,此方法只調(diào)用一次。
?public?int?doAfterBody()?throws?javax.servlet.jsp.JspException?
體被評(píng)估后,BodyContent寫(xiě)入者仍處于激活狀態(tài)時(shí)調(diào)用的生命期方法。此方法必須返回EVAL_BODY_TAG或SKIP_BODY,若返回EVAL_BODY_TAG時(shí)體再次被評(píng)估。
BodyTagSupport類(lèi)的方法
??public?int?doStartTag()?throws?javax.servlet.jsp.JspException?
復(fù)寫(xiě)TagSupport中的doStartTag()方法。
?public?int?doEndTag()?throws?javax.servlet.jsp.JspException
調(diào)用TagSupport中的doEndTag()方法,返回結(jié)果。
public?void?setBodyContent(javax.servlet.jsp.tagext.BodyContent?bodyContent)
在一保護(hù)成員變量bodyContent中保存新的體內(nèi)容對(duì)象,子類(lèi)可直接訪問(wèn)此對(duì)象。
public?void?doInitBody()?throws?javax.servlet.jsp.JspException?
缺省什么都不做。被需要執(zhí)行初始化的子類(lèi)所復(fù)寫(xiě)。
public?int?doAfterBody()?throws?javax.servlet.jsp.JspException
每次體被評(píng)估后由JSPservlet調(diào)用,體內(nèi)容對(duì)象仍處于激活狀態(tài)。返回SKEP_BODY或EVAL_BODY_TAG則體再次被評(píng)估
?public?void?release()?
設(shè)置bodyContent對(duì)象為null,然后調(diào)用super.release()。
public?javax.servlet.jsp.tagext.BodyContent?getBodyContent()
返回bodyContent變量。子類(lèi)已經(jīng)可以訪問(wèn)保護(hù)變量,但此方法允許無(wú)關(guān)的標(biāo)簽處理類(lèi)對(duì)此體內(nèi)容發(fā)送輸出。
public?javax.servlet.jsp.JspWriter?getPreviousOut()?
在bodyContent變量上調(diào)用getEnclosingWriter()并返回結(jié)果的簡(jiǎn)便方法。
5.體標(biāo)簽處理器的生命期
a.生成servlet需要?jiǎng)?chuàng)建標(biāo)簽處理器類(lèi)的一個(gè)實(shí)例。實(shí)現(xiàn)方式通常是調(diào)用JSP容器的工廠類(lèi)的一個(gè)方法,工廠類(lèi)包含一個(gè)標(biāo)簽處理器實(shí)例池以使其可重用不再處于激活狀態(tài)的對(duì)象。
b.初始化標(biāo)簽處理器,使servlet獲知其存在性。servlet通過(guò)調(diào)用標(biāo)簽處理器的兩個(gè)方法實(shí)現(xiàn)此過(guò)程:setPageContext(PageContextctx)和setParent(Tagparent)。
c.如果標(biāo)簽具有屬性,屬性的取值通過(guò)處理器提供setter方法傳入到對(duì)象。屬性setter方法是一個(gè)標(biāo)簽支持屬性所需的唯一方法。
d.頁(yè)面的上下文和父標(biāo)簽已被調(diào)置,并已具備屬性。調(diào)用標(biāo)簽處理器的doStartTag()方法,該方法可以讀取這些變量并執(zhí)行實(shí)現(xiàn)標(biāo)答功能所需的計(jì)算和操作。
doStartTag()方法必須返回一個(gè)整型數(shù)。
返回EVAL_BODY_TAG則正常處理標(biāo)簽體(跳到e);
返回SKIP_BODY則從初始JSP頁(yè)面中直到此標(biāo)簽結(jié)束標(biāo)記處的內(nèi)容均被忽略。(跳到f)
e.如果返回EVAL_BODY_TAG時(shí),則正常處理標(biāo)簽體。
e1.在棧中保存當(dāng)前的JspWriter對(duì)象,創(chuàng)建新的BodyContent對(duì)象,并將其置為JSP頁(yè)面的out對(duì)象保存在上下文范圍內(nèi)名為name的屬性中。并調(diào)用它的setBodyContent()方法。
e2.調(diào)用doInitBody()方法進(jìn)行初始化。
e3.處理標(biāo)簽體。將輸出寫(xiě)入BodyContent對(duì)象中,此過(guò)程依賴于TLD的標(biāo)簽元素,有三種可能取值。
e4.調(diào)用doAfterBody()方法,將體內(nèi)體內(nèi)容寫(xiě)入JspWriter,可如下實(shí)現(xiàn):
JspWriterout
=
bodyContent.getEnclosingWriter();
out.println(bodyContent.getString());
//
bodyContent.writeOut(out);
bodyContent.clear();
e5.doAfterBody()方法返回兩種可能:
返回EVAL_BODY_TAG時(shí),再對(duì)標(biāo)簽體進(jìn)行評(píng)估,這是數(shù)組和枚舉被循環(huán)處理的典型情況。
返回SKIP_PAGE時(shí),繼續(xù)頁(yè)面的其余部份。
e6.體內(nèi)容完成,因此創(chuàng)建它的過(guò)程被反向:
調(diào)用pageContent.popBody()方法檢索前面的JspWriter對(duì)象。
將寫(xiě)入者設(shè)置回out隱含對(duì)象。
f.標(biāo)簽體被評(píng)估或忽視后調(diào)用doEndTag()方法,允許標(biāo)簽處理器像輸出流發(fā)回內(nèi)容。
返回EVAL_PAGE則頁(yè)面的其余部分被評(píng)估;
返回SKIP_PAGE則servlet代碼立即從_jspService()中返回。
g.此時(shí)體的內(nèi)容在受保護(hù)的bodyContent對(duì)象中仍然可用。
可以將它寫(xiě)入servlet輸出流中:
JspWriterout=pageContext.getOut();
out.println(bodyContent.getString());
或者
bodyContent.WriteOut(pageContext.getOut());
6.標(biāo)簽附加信息類(lèi)
四、標(biāo)簽指令
taglib指令元素的目的是指定TLD的位置,設(shè)置在頁(yè)面上與標(biāo)簽區(qū)分開(kāi)來(lái)的一個(gè)短別名。
語(yǔ)法:
<%
@taglib?uri
=
"
/helloworld
"
?prefix
=
"
mytag
"
%>
屬性:prefix:用于標(biāo)識(shí)標(biāo)簽庫(kù)的唯一標(biāo)識(shí)。uri:標(biāo)簽庫(kù)本身的URI。
uri不必指向一個(gè)實(shí)際文件,它是JSP容器可以在web.xml中查找實(shí)際文件位置的唯一標(biāo)識(shí)符。