自定義標(biāo)簽必須實現(xiàn)下面三個接口中的一個:Tag、IterationTag、BodyTag
1.Tag
如果要實現(xiàn)這個接口,可以通過擴展TagSupport這個類,來寫自己需要的方法,而不需要把Tag接口中的所有方法實現(xiàn)。
Tag接口的方法:doStartTag()、doEndTag()、getParent()、setParent()、release()、setPageContext()
在Tag類代碼中不能像jsp一樣,直接使用out隱含對象,他有一個對象可以使用pageContext,通過它的getOut()方法可以得到out對象。在標(biāo)簽內(nèi)部,訪問任何的隱含對象,都是通過調(diào)用pageContext的set方法。
2.IterationTag
IterationTag接口與Tag接口類似,用于當(dāng)一個自定義標(biāo)簽需要重復(fù)計算它的代碼體的情況下。它擴展Tag接口并實現(xiàn)了一個新的方法doAfterBody()來實現(xiàn)循環(huán),這個方法只有從doStartTag()返回EVAL_BODY_INCLUDE時才被調(diào)用。在執(zhí)行doAfterBody()方法時,如果返回的是EVAL_BODY_AGAIN,那么將再次執(zhí)行doAfterBody()方法,直到doAfterBody()返回的是SKIP_BODY或者EVAL_BODY_INCLUDE.
3.BodyTag
BodyTag接口擴展了IterationTag并提供了對代碼體內(nèi)容進行操作的功能。就是在計算代碼體的時候可以對已經(jīng)形成的代碼體進行修改。BodyContent對象就是用來保存對自定義標(biāo)簽體計算的結(jié)果。它有一個新方法doInitBody(),這個方法只有在doStartTag()方法返回EVAL_BODY_BUFFERED時才調(diào)用,此時它將創(chuàng)建一個BodyContent對象保存結(jié)果。
擴展自定義標(biāo)簽:
添加屬性
首先要在tld文件中加入一個屬性元素,然后在java文件中需要定義這個屬性以及它的的setter方法。屬性元素有四個子元素分別是、、、,這里表示的是屬性是否接受scriptlet表達式的計算結(jié)果,默認(rèn)情況下為false,即只能接受靜態(tài)值。
添加變量
可以在tld文件中給自定義標(biāo)簽加入一個元素,它的子元素包括表示保存變量的名字,表示變量的java類型,用boolean表示這個變量是否為新的,表示變量的使用范圍(AT_BEGIN表示從起始標(biāo)簽起,AT_END表示從終止標(biāo)簽后,NESTED表示起始標(biāo)簽和終止標(biāo)簽之間)。定義了變量之后,需要在java文件中把這個變量用pageContext.setAttribute("",object);這里key值應(yīng)該就是變量對外的名字。
使用TagExtraInfo(TEI)類
這個對象中有兩類對象可以使用,TagData(保存標(biāo)簽屬性的信息)、VariableInfo(描述代碼變量)
一段TagExtraInfo類代碼實例:
public VariableInfo[] getVariableInfo(TagData data) {
String variableName = data.getAttributeString("name");
VariableInfo vi =
new VariableInfo(variableName,"String []", true, VariableInfo.AT_END);
VariableInfo[] tagVariables = new VariableInfo[1];
tagVariables[0] = vi;
return tagVariables;
}
可以通過TagData類的getAttributeString方法得到某個屬性的值,還有另外一個方法getAttribute也是得到某個屬性的值不過返回的是一個對象。而getVariableInfo方法必須返回一個VariableInfo數(shù)組。除此之外,還需要在tld中的元素定義后加入一個元素,說明TEI類的全稱。
pageContext對象中含有的方法包括:getOut();getPage();getRequest();getResponse();getServletConfig();getServletContext();getSession() Tag接口中的返回常數(shù)意義:
EVAL_BODY_INCLUDE:告訴服務(wù)器正文的內(nèi)容,并把這些內(nèi)容送入輸出流
SKIP_BODY:告訴服務(wù)器不要處理正文內(nèi)容
EVAL_PAGE:讓服務(wù)器繼續(xù)執(zhí)行頁面
SKIP_PAGE:讓服務(wù)器不要處理剩余的頁面
EVAL_BODY_AGAIN:讓服務(wù)器繼續(xù)處理正文內(nèi)容,只有doAfterBody方法可以返回
EVAL_BODY_BUFFERED:BodyTag接口的字段,在doStartTag()返回
EVAL_BODY_INCLUDE、SKIP_BODY一般由doStartTag()返回,而EVAL_PAPGE、SKIP_PAGE由doEndTag()返回。
在調(diào)用doStartTag()方法之前其實標(biāo)記還調(diào)用了其他兩個方法:setPageContext()和setParent();所以在后面的方法中可以使用pageContext和parent對象,如果需要的話。
讓自定義標(biāo)簽在頁面中創(chuàng)建對象時必須使用一個標(biāo)準(zhǔn)的JSP對象TagExtraInfo類,它可以創(chuàng)建腳本變量還可以在編譯的時候?qū)?biāo)簽進行檢驗,TEI類僅可以生成由setAttribute方法存儲在PageContext對象中的變量,而并不是單獨生成變量。
通過TEI類定義腳本變量可以讓使用者自己定義在頁面中使用對象的名稱。
除了使用TEI類方法之外,還可以簡單的在TLD中定義一個對象來使用自定義對象,用法如下:
name
String []
true
AT_END
對于variable的子元素,指的是創(chuàng)建的變量名稱從屬性name中來取得,當(dāng)然也可以通過元素來限制變量的名稱。注意這兩個元素是互斥的。
一個擴展BodyTagSupport的自定義標(biāo)記的生命周期如下:
1.創(chuàng)建標(biāo)記
2.調(diào)用Setter方法
3.調(diào)用doStartTag()方法
4.調(diào)用setBodyContent()方法
5.調(diào)用InitBody()方法
6.處理標(biāo)記的Body
7.doAfterBody();根據(jù)返回值,如果為EVAL_BODY_AGAIN,繼續(xù)執(zhí)行6,如果不是,執(zhí)行8
8.調(diào)用doEndTag()方法
9.判斷標(biāo)記是否需要重用,如果要,執(zhí)行4;否則執(zhí)行release()方法。
TagSupport類的方法findAncestorWithClass()方法可以用來查找指定的父類,它有兩個參數(shù)一個為本身的類名,還有一個就是要查找的父類的名稱,如果沒有返回null;例如ParentTag parent = (ParentTag) this.findAncestorWithClass(this,ParentTag.class);
自定義標(biāo)記的驗證方法:JSP1.1 TEI類可以在編譯時刻檢驗自己的標(biāo)記,這個類中有一個isValid()方法,如果TLD中為這個標(biāo)記定義了這個TEI類,那么網(wǎng)頁在編譯的時候?qū){(diào)用這個方法,并且會傳入一個包含屬性具體內(nèi)容的參數(shù)TagData.(在JSP1.2中同樣有效)
JSP1.2 JSP1.2中引入一個新的標(biāo)記檢驗方法,定義了一個新類TagLibraryValidator,并且可以由此派生出檢驗標(biāo)志的類,大多數(shù)情況下僅使用這個類的validate()方法,它有三個參數(shù):prefix(在taglib指令中定義的前綴);uri(TLD文件中的URI);page(JSP頁的PageData XML版本),validate()方法返回值為null時表示驗證成功,否則返回的String類型將是一個錯誤信息。
當(dāng)validator在TLD文件中定義時,它應(yīng)該放在元素定義的外面,因為它是用來處理驗證標(biāo)記庫中的所有標(biāo)記的。
.
比較JSP1.2和JSP1.1中的方法:TagLibraryValidator比TEI類更全面,可以用來檢測整個網(wǎng)頁,而不僅僅是標(biāo)記本身,可以用來處理標(biāo)記間的合作,并且這種方法可以用來通知程序員錯誤出在哪里,但是同時它的方法也比TEI類的方法復(fù)雜多了,因為它需要遍歷整個XML版本的JSP(完成getAttributeValue方法)。
JSP1.2中的TryCatchFinally接口:這個接口主要是用于當(dāng)自定義標(biāo)記出現(xiàn)異常時釋放自定義標(biāo)記中的資源使用的,它定義了兩個方法:public void doCatch(Throwable t);(當(dāng)doStartTag,doInitBody,doAfterBody,doEndTag方法出現(xiàn)異常時會調(diào)用這個方法)
piblic void doFinally();(當(dāng)doEndTag被調(diào)用后,無論是否出現(xiàn)異常都會調(diào)用這個方法,就像程序中的finally塊,可以用來釋放資源)
在JSP1.2中,可以通過在tld文件中加入一個元素 來指定自己的在taglib指令中使用的名稱,然后把這個tld文件與Manifest.mf一起放在META-INF目錄中,那么在頁面中就可以非常方便地導(dǎo)入這些tld.
編寫自定義標(biāo)記的原則:
1.使用腳本變量(允許設(shè)計者為腳本變量起名、將腳本變量的數(shù)量減到最小、使用一個組合腳本對象和存取函數(shù)即使用JavaBean)
2.當(dāng)設(shè)計相互協(xié)作的標(biāo)記時應(yīng)該盡量避免創(chuàng)建一套新的語言,應(yīng)當(dāng)盡量使用腳本變量3.編寫代碼而不是內(nèi)容,不要在自定義標(biāo)記中產(chǎn)生HTML,這樣會失去通用性。
1.Tag
如果要實現(xiàn)這個接口,可以通過擴展TagSupport這個類,來寫自己需要的方法,而不需要把Tag接口中的所有方法實現(xiàn)。
Tag接口的方法:doStartTag()、doEndTag()、getParent()、setParent()、release()、setPageContext()
在Tag類代碼中不能像jsp一樣,直接使用out隱含對象,他有一個對象可以使用pageContext,通過它的getOut()方法可以得到out對象。在標(biāo)簽內(nèi)部,訪問任何的隱含對象,都是通過調(diào)用pageContext的set方法。
2.IterationTag
IterationTag接口與Tag接口類似,用于當(dāng)一個自定義標(biāo)簽需要重復(fù)計算它的代碼體的情況下。它擴展Tag接口并實現(xiàn)了一個新的方法doAfterBody()來實現(xiàn)循環(huán),這個方法只有從doStartTag()返回EVAL_BODY_INCLUDE時才被調(diào)用。在執(zhí)行doAfterBody()方法時,如果返回的是EVAL_BODY_AGAIN,那么將再次執(zhí)行doAfterBody()方法,直到doAfterBody()返回的是SKIP_BODY或者EVAL_BODY_INCLUDE.
3.BodyTag
BodyTag接口擴展了IterationTag并提供了對代碼體內(nèi)容進行操作的功能。就是在計算代碼體的時候可以對已經(jīng)形成的代碼體進行修改。BodyContent對象就是用來保存對自定義標(biāo)簽體計算的結(jié)果。它有一個新方法doInitBody(),這個方法只有在doStartTag()方法返回EVAL_BODY_BUFFERED時才調(diào)用,此時它將創(chuàng)建一個BodyContent對象保存結(jié)果。
擴展自定義標(biāo)簽:
添加屬性
首先要在tld文件中加入一個屬性元素,然后在java文件中需要定義這個屬性以及它的的setter方法。屬性元素有四個子元素分別是
添加變量
可以在tld文件中給自定義標(biāo)簽加入一個
使用TagExtraInfo(TEI)類
這個對象中有兩類對象可以使用,TagData(保存標(biāo)簽屬性的信息)、VariableInfo(描述代碼變量)
一段TagExtraInfo類代碼實例:
public VariableInfo[] getVariableInfo(TagData data) {
String variableName = data.getAttributeString("name");
VariableInfo vi =
new VariableInfo(variableName,"String []", true, VariableInfo.AT_END);
VariableInfo[] tagVariables = new VariableInfo[1];
tagVariables[0] = vi;
return tagVariables;
}
可以通過TagData類的getAttributeString方法得到某個屬性的值,還有另外一個方法getAttribute也是得到某個屬性的值不過返回的是一個對象。而getVariableInfo方法必須返回一個VariableInfo數(shù)組。除此之外,還需要在tld中的元素定義
pageContext對象中含有的方法包括:getOut();getPage();getRequest();getResponse();getServletConfig();getServletContext();getSession() Tag接口中的返回常數(shù)意義:
EVAL_BODY_INCLUDE:告訴服務(wù)器正文的內(nèi)容,并把這些內(nèi)容送入輸出流
SKIP_BODY:告訴服務(wù)器不要處理正文內(nèi)容
EVAL_PAGE:讓服務(wù)器繼續(xù)執(zhí)行頁面
SKIP_PAGE:讓服務(wù)器不要處理剩余的頁面
EVAL_BODY_AGAIN:讓服務(wù)器繼續(xù)處理正文內(nèi)容,只有doAfterBody方法可以返回
EVAL_BODY_BUFFERED:BodyTag接口的字段,在doStartTag()返回
EVAL_BODY_INCLUDE、SKIP_BODY一般由doStartTag()返回,而EVAL_PAPGE、SKIP_PAGE由doEndTag()返回。
在調(diào)用doStartTag()方法之前其實標(biāo)記還調(diào)用了其他兩個方法:setPageContext()和setParent();所以在后面的方法中可以使用pageContext和parent對象,如果需要的話。
讓自定義標(biāo)簽在頁面中創(chuàng)建對象時必須使用一個標(biāo)準(zhǔn)的JSP對象TagExtraInfo類,它可以創(chuàng)建腳本變量還可以在編譯的時候?qū)?biāo)簽進行檢驗,TEI類僅可以生成由setAttribute方法存儲在PageContext對象中的變量,而并不是單獨生成變量。
通過TEI類定義腳本變量可以讓使用者自己定義在頁面中使用對象的名稱。
除了使用TEI類方法之外,還可以簡單的在TLD中定義一個
對于variable的子元素,
一個擴展BodyTagSupport的自定義標(biāo)記的生命周期如下:
1.創(chuàng)建標(biāo)記
2.調(diào)用Setter方法
3.調(diào)用doStartTag()方法
4.調(diào)用setBodyContent()方法
5.調(diào)用InitBody()方法
6.處理標(biāo)記的Body
7.doAfterBody();根據(jù)返回值,如果為EVAL_BODY_AGAIN,繼續(xù)執(zhí)行6,如果不是,執(zhí)行8
8.調(diào)用doEndTag()方法
9.判斷標(biāo)記是否需要重用,如果要,執(zhí)行4;否則執(zhí)行release()方法。
TagSupport類的方法findAncestorWithClass()方法可以用來查找指定的父類,它有兩個參數(shù)一個為本身的類名,還有一個就是要查找的父類的名稱,如果沒有返回null;例如ParentTag parent = (ParentTag) this.findAncestorWithClass(this,ParentTag.class);
自定義標(biāo)記的驗證方法:JSP1.1 TEI類可以在編譯時刻檢驗自己的標(biāo)記,這個類中有一個isValid()方法,如果TLD中為這個標(biāo)記定義了這個TEI類,那么網(wǎng)頁在編譯的時候?qū){(diào)用這個方法,并且會傳入一個包含屬性具體內(nèi)容的參數(shù)TagData.(在JSP1.2中同樣有效)
JSP1.2 JSP1.2中引入一個新的標(biāo)記檢驗方法,定義了一個新類TagLibraryValidator,并且可以由此派生出檢驗標(biāo)志的類,大多數(shù)情況下僅使用這個類的validate()方法,它有三個參數(shù):prefix(在taglib指令中定義的前綴);uri(TLD文件中的URI);page(JSP頁的PageData XML版本),validate()方法返回值為null時表示驗證成功,否則返回的String類型將是一個錯誤信息。
當(dāng)validator在TLD文件中定義時,它應(yīng)該放在
比較JSP1.2和JSP1.1中的方法:TagLibraryValidator比TEI類更全面,可以用來檢測整個網(wǎng)頁,而不僅僅是標(biāo)記本身,可以用來處理標(biāo)記間的合作,并且這種方法可以用來通知程序員錯誤出在哪里,但是同時它的方法也比TEI類的方法復(fù)雜多了,因為它需要遍歷整個XML版本的JSP(完成getAttributeValue方法)。
JSP1.2中的TryCatchFinally接口:這個接口主要是用于當(dāng)自定義標(biāo)記出現(xiàn)異常時釋放自定義標(biāo)記中的資源使用的,它定義了兩個方法:public void doCatch(Throwable t);(當(dāng)doStartTag,doInitBody,doAfterBody,doEndTag方法出現(xiàn)異常時會調(diào)用這個方法)
piblic void doFinally();(當(dāng)doEndTag被調(diào)用后,無論是否出現(xiàn)異常都會調(diào)用這個方法,就像程序中的finally塊,可以用來釋放資源)
在JSP1.2中,可以通過在tld文件中加入一個元素
編寫自定義標(biāo)記的原則:
1.使用腳本變量(允許設(shè)計者為腳本變量起名、將腳本變量的數(shù)量減到最小、使用一個組合腳本對象和存取函數(shù)即使用JavaBean)
2.當(dāng)設(shè)計相互協(xié)作的標(biāo)記時應(yīng)該盡量避免創(chuàng)建一套新的語言,應(yīng)當(dāng)盡量使用腳本變量3.編寫代碼而不是內(nèi)容,不要在自定義標(biāo)記中產(chǎn)生HTML,這樣會失去通用性。