版權(quán)所有:(xiaodaoxiaodao)藍(lán)小刀 ?? xiaodaoxiaodao@gmail.com

http://www.tkk7.com/xiaodaoxiaodao/articles/103438.html ? ? ?

轉(zhuǎn)載請(qǐng)注明來(lái)源/作者

?

JSP tag 學(xué)習(xí)

?

JSP2.0 中,對(duì)于自定義的標(biāo)簽有兩種實(shí)現(xiàn)方法,實(shí)現(xiàn)接口或者繼承現(xiàn)有的類

如下圖,標(biāo)注藍(lán)色的是接口,其它是標(biāo)簽類(SimpleTagSupport只在JSP2.0中才有)

?

tag2.JPG?

在以上接口和類中,定義了一些靜態(tài)常量,如下:

Tag 中定義:

SKIP_BODY = 0;????????? // 不處理標(biāo)簽體,直接調(diào)用doEndTag()方法

EVAL_BODY_INCLUDE = 1;?? // 解析標(biāo)簽體,但繞過(guò) doInitBody () setBodyContent () 方法

SKIP_PAGE = 5;????????? // 不解析標(biāo)簽后面的JSP內(nèi)容

EVAL_PAGE = 6;????????? // 解析標(biāo)簽后,繼續(xù)解析標(biāo)簽后面的JSP內(nèi)容

?

IterationTag 中定義:

EVAL_BODY_AGAIN = 2;

?

BodyTag 中定義:

EVAL_BODY_TAG = 2; ???????? // deprecated

EVAL_BODY_BUFFERED = 2;??? //

?

特別的,對(duì)于EVAL_BODY_AGAINEVAL_BODY_BUFFERED

doAferBody中返回SKIP_BODY,表示終止標(biāo)記正文處理;若返回的是 EVAL_BODY_BUFFERED ,將會(huì)再一次調(diào)用doAferBody方法,重新處理標(biāo)記正文,直到返回SKIP_BODY為止。? //

?

TagSupport 默認(rèn)doStartTag()/doAfterBody()返回SKIP_BODY

BodyTagSupport 默認(rèn)doStartTag()返回EVAL_BODY_BUFFERED / doInitBody()什么也不做 /doAfterBody()返回SKIP_BODY

下面是自定義tag的執(zhí)行過(guò)程(由上至下),對(duì)于以上各常量的實(shí)際運(yùn)用為:

注意其中的 doInitBody/setBodyContent 方法在自定義標(biāo)簽實(shí)現(xiàn)了 BodyTag 接口或繼承BodyTagSupport才可以使用

Tag 方法

可返回的靜態(tài)常量

doStartTag

SKIP_BODY EVAL_BODY_INCLUDE

EVAL_BODY_AGAIN/EVAL_BODY_BUFFERED

doInitBody

做標(biāo)簽一些初始化工作,無(wú)返回值

setBodyContent

doInitBody 之后執(zhí)行,使用setBodyContent得到JSP頁(yè)面中標(biāo)簽體之間內(nèi)容

doAfterBody

最終必須返回SKIP_BODY ,否則可能導(dǎo)致OutOfMemoryError,可參考上面

doEndTag

SKIP_PAGE/EVAL_PAGE

?

示例代碼如下:

public int doAfterBody() throws JspException {

? try {

?? this.pageContext.getOut().write("<br>");

? } catch (IOException e) {

????? e.printStackTrace();

? }

? if(cou>1){

?? cou--;

?? return this.EVAL_BODY_AGAIN;

? }else{

?? return this.SKIP_BODY;?? // 最終必須返回SKIP_BODY

? }

?}

?

自定義標(biāo)簽的開(kāi)發(fā)包括:

1.? 開(kāi)發(fā)標(biāo)簽的處理程序(java類)

2.? .tld 文件中指定標(biāo)簽使用的類

3.? web.xml中指定JSP中使.tld(標(biāo)簽庫(kù)描述文件)文件的位置。

?

.tld文件中

<tag>

??? <name>out</name>

??? <tag-class>org.apache.taglibs.standard.tag.el.core.OutTag</tag-class>

<body-content>JSP</body-content>

<attribute>

??????? <name>value</name>

??????? <required>true</required>

??????? <rtexprvalue>false</rtexprvalue>

?</attribute>

? </tag>

?

body-content

根據(jù)web-jsptaglibrary_2_0.xsd(位于servlet-api.jar包($TOMCAT_HOME\common\lib)中的\javax\servlet\resources下,其中web.xml驗(yàn)證時(shí)所需要的xsd文件都位于此resources目錄下), body-content 的值有下面4種:

<xsd:enumeration value="tagdependent"/>

??? <xsd:enumeration value="JSP"/>

??? <xsd:enumeration value="empty"/>

??? <xsd:enumeration value="scriptless"/>

?

?

tagdependent 標(biāo)簽體內(nèi)容 直接被寫(xiě)入BodyContent,由自定義標(biāo)簽類來(lái)進(jìn)行處理,而不被JSP容器解釋

如下:

<test:myList>

select name,age from users

</test:myList>

?

JSP 接受所有JSP語(yǔ)法,如定制的或內(nèi)部的tagscripts、靜態(tài)HTML、腳本元素、JSP指令和動(dòng)作。如:

<my:test>

??? <%=request.getProtocol()%>????? //

</my:test>

具體可參考后面附源碼。

?

empty 空標(biāo)記,即起始標(biāo)記和結(jié)束標(biāo)記之間沒(méi)有內(nèi)容。

下面幾種寫(xiě)法都是有效的,

<test:mytag />

<test:mytag uname="Tom" />

<test:mytag></test:mytag>

?

scriptless 接受文本、ELJSP動(dòng)作。如上述使用<body-content> scriptless </body-content> 報(bào)錯(cuò),具體可參考后面附源碼。

?

rtexprvalue:

由請(qǐng)求時(shí)表達(dá)式來(lái)指定屬性的值,默認(rèn)為false,如下必須設(shè)置為true

<test:welcome uname="<%=request.getParameter("username") %>" />

?

?

body-content JSP/scriptless 時(shí)標(biāo)簽體可以接受的代碼(jasper-compiler.jar $TOMCAT_HOME\common\lib)中 \org\apache\jasper\compiler\Parser.java中):

JSP:

private void parseElements(Node parent)

??????? throws JasperException

??? {

??????? if( scriptlessCount > 0 ) {

??????????? // vc: ScriptlessBody

??????????? // We must follow the ScriptlessBody production if one of

??????????? // our parents is ScriptlessBody.

??????????? parseElementsScriptless( parent );

??????????? return;

??????? }

???????

??????? start = reader.mark();

??????? if (reader.matches("<%--")) {

??????????? parseComment(parent);

??????? } else if (reader.matches("<%@")) {

??????????? parseDirective(parent);

??????? } else if (reader.matches("<jsp:directive.")) {

??????????? parseXMLDirective(parent);

??????? } else if (reader.matches("<%!")) {

??????????? parseDeclaration(parent);

??????? } else if (reader.matches("<jsp:declaration")) {

??????????? parseXMLDeclaration(parent);

??????? } else if (reader.matches("<%=")) {

??????????? parseExpression(parent);

??????? } else if (reader.matches("<jsp:expression")) {

??????????? parseXMLExpression(parent);

??????? } else if (reader.matches("<%")) {

??????????? parseScriptlet(parent);

??????? } else if (reader.matches("<jsp:scriptlet")) {

??????????? parseXMLScriptlet(parent);

??????? } else if (reader.matches("<jsp:text")) {

??????????? parseXMLTemplateText(parent);

??????? } else if (reader.matches("${")) {

??????????? parseELExpression(parent);

??????? } else if (reader.matches("<jsp:")) {

??????????? parseStandardAction(parent);

??????? } else if (!parseCustomTag(parent)) {

??????????? checkUnbalancedEndTag();

??????????? parseTemplateText(parent);

??????? }

}

Scriptless:

private void parseElementsScriptless(Node parent)

??????? throws JasperException

??? {

??????? // Keep track of how many scriptless nodes we've encountered

??????? // so we know whether our child nodes are forced scriptless

??????? scriptlessCount++;

???????

??????? start = reader.mark();

??????? if (reader.matches("<%--")) {

??????????? parseComment(parent);

??????? } else if (reader.matches("<%@")) {

??????????? parseDirective(parent);

??????? } else if (reader.matches("<jsp:directive.")) {

??????????? parseXMLDirective(parent);

??????? } else if (reader.matches("<%!")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??????? } else if (reader.matches("<jsp:declaration")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??????? } else if (reader.matches("<%=")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??? ????} else if (reader.matches("<jsp:expression")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??????? } else if (reader.matches("<%")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??????? } else if (reader.matches("<jsp:scriptlet")) {

??????????? err.jspError( reader.mark(), "jsp.error.no.scriptlets" );

??????? } else if (reader.matches("<jsp:text")) {

??????????? parseXMLTemplateText(parent);

??????? } else if (reader.matches("${")) {

??????????? parseELExpression(parent);

??????? } else if (reader.matches("<jsp:")) {

??????????? parseStandardAction(parent);

??????? } else if (!parseCustomTag(parent)) {

??????????? checkUnbalancedEndTag();

??????????? parseTemplateText(parent);

??????? }

???????

????? ??scriptlessCount--;

}

?

由上面可以看出,局限性比較小,在body-content可以使用 Scriptless 的地方都可以用 JSP 代替,反之則不可。

?

版權(quán)所有:(xiaodaoxiaodao)藍(lán)小刀 ?? xiaodaoxiaodao@gmail.com