在JSP2.0 中,對(duì)于自定義的標(biāo)簽有兩種實(shí)現(xiàn)方法,實(shí)現(xiàn)接口或者繼承現(xiàn)有的類
如下圖,標(biāo)注藍(lán)色的是接口,其它是標(biāo)簽類(SimpleTagSupport只在JSP2.0中才有)
在以上接口和類中,定義了一些靜態(tài)常量,如下:
Tag 中定義:
SKIP_BODY = 0; // 不處理標(biāo)簽體,直接調(diào)用doEndTag()方法
EVAL_BODY_INCLUDE = 1; // 解析標(biāo)簽體,但繞過 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_AGAIN和EVAL_BODY_BUFFERED:
在doAferBody中返回SKIP_BODY,表示終止標(biāo)記正文處理;若返回的是 EVAL_BODY_BUFFERED ,將會(huì)再一次調(diào)用doAferBody方法,重新處理標(biāo)記正文,直到返回SKIP_BODY為止。 // ①
下面是自定義tag的執(zhí)行過程(由上至下),對(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)簽一些初始化工作,無返回值 |
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)簽的開發(fā)包括:
1. 開發(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)容 直接被寫入BodyContent,由自定義標(biāo)簽類來進(jìn)行處理,而不被JSP容器解釋,
如下:
<test:myList>
select name,age from users
</test:myList>
JSP : 接受所有JSP語法,如定制的或內(nèi)部的tag、scripts、靜態(tài)HTML、腳本元素、JSP指令和動(dòng)作。如:
<my:test>
<%=request.getProtocol()%> // ②
</my:test>
具體可參考后面附源碼。
empty : 空標(biāo)記,即起始標(biāo)記和結(jié)束標(biāo)記之間沒有內(nèi)容。
下面幾種寫法都是有效的,
<test:mytag />
<test:mytag uname="Tom" />
<test:mytag></test:mytag>
scriptless : 接受文本、EL和JSP動(dòng)作。如上述②使用<body-content> scriptless </body-content> 則報(bào)錯(cuò),具體可參考后面附源碼。
rtexprvalue:
由請(qǐng)求時(shí)表達(dá)式來指定屬性的值,默認(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 代替,反之則不可。
聯(lián)系客服