JSP标签执行顺序
首先来看一下简单标签接口的方法以及它的生命周期
一、SimpleTag接口的方法
1、doTag():void
2、getParent():JspTag
3、setJspBody(javax.servlet.jsp.tagext.JspFragment body):void
4、setJspContext(javax.servlet.jsp.JspContext pc):void
5、setParent(javax,servlet.jsp.tagext.JspTag tag):void
二、SimpleTag接口的声明周期
1、每次遇到Jsp标签容器构造一个SimpleTag实例,这个构造函数没有参数。
2、setJspContext()、setParent()只有当前的标签在另一个标签之内时才调用setParent()方法
3、设置属性,调用每一个属性的setter方法
4、setJspBody(javax.servlet.jsp.tagext.JspFragment body)
5、doTag()所有标签的逻辑迭代和Body计算都在这个方法中
6、return下面是对带体标签的介绍
三、带Body的自定以标签
1、必须实现Tag接口的doStartTag()和doEndTag()方法
2、可以实现IterationTag接口的doAffterBody()方法
3、可以实现BodyTag接口的doInitBody()和setBodyContent(javax.servlet.jsp.tagext.BodyContent bc)方法
4、doStartTag()可以返回的值:A、SKIP_BODY 不处理标签体B、EVAL_BODY_INCLUDE 计算的体的结果被包含在out(JspWriter)中输出C、EVAL_BODY_BUFFERED 一个BodyContent对象被创建
5、doEndTag()方法可以返回SKIP_PAGE或者EVAL_PAGE以确定是否继续计算其余的页面
6、doAffterBody可以返回EVAL_BODY_AGAIN、SKIP_BODY以确定是否再次计算标签体
四、BodyTag的处理过程
1、setPageContext(javax.servlet.jsp.PageContext pc):void
2、setParent(javax.servlet.jsp.tagext.Tag tag):void
3、doStartTag():int
4、setBodyContext(BodyContext bc):void
5、doInitBody():int
6、doAffterBody():int
7、doEndTag():int
8、release():void
JSP标签开发流程
一、概述
jsp(SUN企业级应用的首选)中有一块重要的技术:自定义标签(Custom Tag),最近这几天在学习Struts的时候发现Struts中使用了很多自定义标签,如html、bean等。所以我就做了个简单的试验,学习一下这种技术。
首先介绍一下这种技术吧!
1.优点:
取代了jsp(SUN企业级应用的首选)中的Java程序,并且可以重复使用,方便不熟悉Java编程的网页设计人员。
2.开发流程:
(1)编写jsp(SUN企业级应用的首选),在jsp(SUN企业级应用的首选)中使用自定义标签。
(2)在web.xml(标准化越来越近了)中指定jsp(SUN企业级应用的首选)中使用的标签的.tld(标签库描述文件)文件的位置。
(3).tld文件中指定标签使用的类。
3. 自定义标签的分类:
(1)简单标签:如< mytag:helloworld/>
(2)带属性标签:如<imytag:checkinput dbname = “<myBean.getDBName()>”/>
(3)带标签体的标签:在自定义标签的起始和结束标签之间的部分为标签体(Body)。Body的内容可以是jsp(SUN企业级应用的首选)中的标准标签,也可以是HTML、脚本语言或其他的自定义标签。
<mytag:checkinput dbname = “<myBean.getDBName()>”>
<mytag:log message=”Table Name”>
<mytag:checkinput />
(4)可以被Script使用的标签:定义了id和type属性的标签可以被标签后面的Scriptlet使用。
<mytag:connection id = “oraDB” type = “DataSource” name = “Oracle(大型网站数据库平台)”>
<%oraDB.getConnection(); %>
4.接口及其他
实际上,自定义标签的处理类实现了Tag Handler对象。jsp(SUN企业级应用的首选)技术在javax.servlet.jsp(SUN企业级应用的首选)。tagext中提供了多个Tag Handler接口,jsp(SUN企业级应用的首选)1.2中定义了Tag、BodyTag、IterationTag接口,在jsp(SUN企业级应用的首选)2.0中新增了SimpleTag接口。jsp(SUN企业级应用的首选)还提供了上述接口的实现类TagSupport、BodyTagSupport和SimpleTagSupport(SimpleTagSupport只在jsp(SUN企业级应用的首选)2.0中才有)。BodyTagSupport实现了BodyTag、Tag和IterationTag接口。
接口及其方法
Tag接口
方法
SimpleTag
dotage
Tag
doStartTag,doEndTag,release
IterationTag
doStartTag,doAfterTag,release
BodyTag
doStartTag,doEndTag,release,doInitBody,doAfterBody
下表引自Sun的jsp(SUN企业级应用的首选)在线教程。
Tag Handler Methods
Tag Handler Type
Methods
Simple
doStartTag, doEndTag, release
Attributes
doStartTag, doEndTag, set/getAttribute1...N, release
Body, Evaluation and No Interaction
doStartTag, doEndTag, release
Body, Iterative Evaluation
doStartTag, doAfterBody, doEndTag, release
Body, Interaction
doStartTag, doEndTag, release, doInitBody, doAfterBody, release
下表中的EVAL是evaluate的缩写,意思是:评价, 估计, 求……的值,在下列的返回值中的意思是执行。
返回值意义
SKIP_BODY表示不用处理标签体,直接调用doEndTag()方法。
SKIP_PAGE忽略标签后面的jsp(SUN企业级应用的首选)内容。
EVAL_PAGE处理标签后,继续处理jsp(SUN企业级应用的首选)后面的内容。
EVAL_BODY_BUFFERED表示需要处理标签体。
EVAL_BODY_INCLUDE表示需要处理标签体,但绕过setBodyContent()和doInitBody()方法
EVAL_BODY_AGAIN对标签体循环处理。
JSP标签开发实例
开发带属性的标签:helloTagHaveProp
本实例中开发的标签在实例108的helloTag标签上作出改进,开发目标是在helloTag标签上增加两个属性fontSize和fontColor,fontSize用于设置字体大小,fontColor用于设置文字的颜色。
(1)第一步:开发标签实现类。
helloTagHaveProp.java package hello; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; public class helloTagHaveProp extends TagSupport { private String fontSize="3";//字体大小,默认3号 private String fontColor="#000000";//字体颜色,默认黑色 //----标签开始时调用此方法------- public int doStartTag(){ try{ JspWriter out=pageContext.getOut(); out.print("标签开始了。<font color=\""+fontColor + "\" size=\""+fontSize+"\">hello!</font>"); }catch(Exception e){ System.out.println(e); } return EVAL_BODY_INCLUDE; } //----标签结束时调用此方法------- public int doEndTag(){ try{ JspWriter out=pageContext.getOut(); out.print("标签结束了。"); }catch(Exception e){ System.out.println(e); } return EVAL_PAGE; } public String getFontColor() { return fontColor; } public void setFontColor(String fontColor) { this.fontColor = fontColor; } public String getFontSize() { return fontSize; } public void setFontSize(String fontSize) { this.fontSize = fontSize; } } |
(2)第二步:编写标签描述tld文件。这里在myTag.tld文件中增加内容,在<taglib>与</taglib>之间增加的内容如下:
<!-- helloTagHaveProp--> <tag> <!-- 标签名称--> <name>helloTagHaveProp</name> <!-- 标签对应的处理类--> <tag-class>hello.helloTagHaveProp</tag-class> <!-- 标签体内容,没有标签体则设为empty--> <body-content>empty</body-content> <!-- 标签的属性声明--> <attribute> <name>fontSize</name> <required>false</required> </attribute> <attribute> <name>fontColor</name> <required>false</required> </attribute> </tag> |
其中,name为属性的名称,required设置此属性是否必须设置,如果为true则在JSP页面中使用此标签时,必须给标签的这个属性赋值。
(3)第三步:在Web应用的web.xml文件中声明标签库引用。本例与实例108使用同一个tld文件,故不必再修改。
(4)第四步:在JSP页面中声明并调用标签。
useHelloTagHaveProp.jsp <%@ taglib uri="/myTag" prefix="myTag" %> <%@ page contentType="text/html;charset=GB2312" %> <html> <head> <title>一个简单的自定义标签</title> </head> <body> 下面是应用这个简单的自定义标签的结果:<br> <myTag:helloTagHaveProp fontSize="5"/><br> <myTag:helloTagHaveProp fontSize="4" fontColor="red"/> </body> </html> |
程序的运行结果如图13-3所示。
三、 开发带标签体的标签
要开发带标签体的标签,可实现BodyTag接口,也可从BodyTag接口的实现类BodyTagSupport继承,为简化开发,推荐从BodyTagSupport类继承开发。
编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartTag(), setBodyContent(), doInitBody(), doAfterBody(), doEndTag(),他们执行顺序如下:doStartTag()→doInitBody()→setBodyContent()→doAfterBody()→doEndTag()doStartTag()方法可返回EVAL_BODY_INCLUDE或SKIP_BODY,如果返回EVAL_BODY_ INCLUDE则继续执行;如果返回SKIP_BODY则接下来的doInitBody(),setBodyContent(), doAfterBody()三个方法不会被执行,而直接执行doEndTag()方法。
setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,则在doInitBody()方法中完成。标签体内容执行完后,会调用doAfterBody()方法,此方法可返回EVAL_BODY_TAG, SKIP_BODY,
EVAL_PAGE或SKIP_PAGE.如果返回EVAL_BODY_TAG则会再次设置标签体内容,直到返回SKIP_BODY;如果返回EVAL_PAGE则标签体执行完后会继续执行JSP页面中接下来的部分;如果返回SKIP_PAGE,则JSP页面的后续内容将不再执行。
开发带标签体的标签:bodyTag1
本实例将要开发一个带标签体的标签bodyTag1,这个标签有一个属性countNum,用于设置输出标签体内容的次数,输出内容为当前的系统时间。
(1)第一步:开发标签实现类。
BodyTag1.java }catch(Exception e){ |
执行标签体并不会直接输出标签体中的内容,因此本实例在doEndTag()方法中一次性把执行的结果输出。
(2)第二步:编写标签描述tld文件。
因为本章所有实例共用一个Web应用,故本例在myTag.tld文件中增加内容。在<taglib>与</taglib>之间增加的内容如下:
<!-- bodyTag1--> <tag> <!-- 标签名称--> <name>bodyTag1</name> <!-- 标签对应的处理类--> <tag-class>body.bodyTag1</tag-class> <!-- 标签体内容,有标签体则设为jsp--> <body-content>jsp</body-content> <!-- 标签的属性声明--> <attribute> <name>countNum</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> |
对于属性countNum的声明中,<required>设置为true,表示此属性为必输项;<rtexprvalue>设置为true,表示标签体支持运行时的表达式取值,如果为false则表示标签体为一个静态文本,默认情况下设置为true.
(3)第三步:在Web应用的web.xml文件中声明标签库引用。
同样,本例与实例108使用同一个tld文件,不必再修改。
(4)第四步:在JSP页面中声明并调用标签。
UseBodyTag1.jsp <%@ taglib uri="/myTag" prefix="myTag" %> <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.Date" %> <html> <head> <title>开发带有标签体的标签</title> </head> <body> |
下面是应用这个带有属性的自定义标签的结果:
<br> <myTag:bodyTag1 countNum="6"> 现在的时间是:<%=new Date()%><br> </myTag:bodyTag1> </body> </html> |
该程序的运行结果如图13-4所示。
开发嵌套的标签:haveChildTag
实际工程中往往需要多个标签来配合完成一定的功能,嵌套的标签存在父子关系,其中,父为外层标签,子为内层标签。本实例将用两个简单的标签来演示,父标签则作出逻辑判断,如果isOutput属性为true,则输出实例108中的标签helloTag;如果为false,则不输出。
(1)第一步:开发标签实现类。
内层的标签helloTag在实例108中已有,此处不再列出。
haveChildTag.java package hello; import javax.servlet.jsp.tagext.BodyTagSupport; public class haveChildTag extends BodyTagSupport { private boolean isOutput;//是否输出子标签内容 //----标签开始时调用此方法------- public int doStartTag(){ if(isOutput) return EVAL_BODY_INCLUDE; else return SKIP_BODY; } //----标签结束时调用此方法------- public int doEndTag(){ try{ if(bodyContent!=null) bodyContent.writeOut(bodyContent.getEnclosingWriter()); }catch(Exception e){ System.out.println(e); } return EVAL_PAGE; } public boolean getIsOutput() { return isOutput; } public void setIsOutput(boolean isOutput) { this.isOutput = isOutput; } } |
(2)第二步:编写标签描述tld文件。
本例在myTag.tld文件中增加内容。在<taglib>与</taglib>之间增加的如下内容:
<!-- haveChildTag--> <tag> <!-- 标签名称--> <name>haveChildTag</name> <!-- 标签对应的处理类--> <tag-class>hello.haveChildTag</tag-class> <!-- 标签体内容,有标签体则设为jsp--> <body-content>jsp</body-content> <!-- 标签的属性声明--> <attribute> <name>isOutput</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> |
(3)第三步:在Web应用的web.xml文件中声明标签库引用。
同样,本例与本章前面的实例使用同一个tld文件,此处不必再修改。
(4)第四步:在JSP页面中声明并调用标签。
useHaveChildTag.jsp <%@ taglib uri="/myTag" prefix="myTag" %> <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.Date" %> <html> <head> <title>开发嵌套的标签</title> </head> <body> 输出子标签时的结果:<br> <myTag:haveChildTag isOutput="true"> <myTag:helloTag/> </myTag:haveChildTag><br> 不输出子标签时的结果:<br> <myTag:haveChildTag isOutput="false"> <myTag:helloTag/> </myTag:haveChildTag><br> </body> </html> |
该程序的运行结果如图13-5所示。
开发迭代的标签:iterateTag
对于集合对象的Iterator类对象,在JSP的Java代码中需要用while循环或for循环来输出,难于维护,且可复用性不好,程序员总是在大量地做这样的工作,这时可以考虑用迭代的标签来开发,需要输出数据时只须在JSP页面中声明标签即可。
开发迭代的标签,需要设计两个Java类:标签实现类和表示标签信息的类。本实例中标签实现类为iterateTag.java,表示标签信息的类为IterateTEI.java.开发迭代的标签可实现IterationTag接口,也可从TagSupport类或BodyTagSupport类继承,由于BodyTagSupport类继承自TagSupport类,而TagSupport类又实现了IterationTag接口,为简化开发,直接从BodyTagSupport类继承即可。
(1)第一步:开发标签实现类和表示标签信息的类。
iterateTag.java package body; import java.util.Collection; import java.util.Iterator; import javax.servlet.jsp.tagext.BodyTagSupport; public class iterateTag extends BodyTagSupport{ private String name;//在pageContext中标识的一个属性名 private Iterator it;//要迭代的对象 private String type;//it中对象的类型 public void setCollection(Collection collection){ if(collection.size()>0) it=collection.iterator(); } //----标签开始时调用此方法------- public int doStartTag(){ if(it==null) return SKIP_BODY; else return continueNext(it); } //----标签体执行完后调用此方法---- public int doAfterBody(){ return continueNext(it); } //----标签结束时调用此方法------- public int doEndTag(){ try{ if(bodyContent!=null) bodyContent.writeOut(bodyContent.getEnclosingWriter()); }catch(Exception e){ System.out.println(e); } return EVAL_PAGE; } //----迭代---- protected int continueNext(Iterator it){ if(it.hasNext()){ pageContext.setAttribute(name,it.next(),pageContext.PAGE_SCOPE); return EVAL_BODY_TAG; }else return SKIP_BODY; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } } |
在标签实现类中,有3个属性:name、type和it.其中,name代表在pageContext中标识一个属性的名字;type代表待迭代内容的数据类型;it为要迭代的内容。在doStartTag()方法中,如果it不为null,就开始迭代,迭代时调用continueNext()方法。
IterateTEI.java package body; import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.TagExtraInfo; import javax.servlet.jsp.tagext.VariableInfo; //----提供标签翻译时的一些相关信息---- public class IterateTEI extends TagExtraInfo { public IterateTEI() { super(); } public VariableInfo[] getVariableInfo(TagData data){ return new VariableInfo[]{ new VariableInfo(data.getAttributeString("name"), data.getAttributeString("type"), true,VariableInfo.NESTED) }; } } VariableInfo类中有几个常量,具体的含义为: NESTED:标签中的参数在标签开始到标签结束之间是有效的。 AT_BEGIN:标签中的参数在标签开始到使用它的JSP页面结束是有效的。 AT_END:标签中的参数在标签的结束到使用它的JSP页面结束是有效的。 |
(2)第二步:编写标签描述tld文件。本例在myTag.tld文件中增加内容。在<taglib>与</taglib>之间增加如下内容:
<!-- iterateTag--> <tag> <!-- 标签名称--> <name>iterateTag</name> <!-- 标签对应的处理类--> <tag-class>body.iterateTag</tag-class> <tei-class>body.IterateTEI</tei-class> <!-- 标签体内容,有标签体则设为jsp--> <body-content>jsp</body-content> <!-- 标签的属性声明--> <attribute> <name>collection</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>name</name> <required>true</required> </attribute> <attribute> <name>type</name> <required>true</required> </attribute> </tag> </taglib> |
(3)第三步:在Web应用的web.xml文件中声明标签库引用。同样,本例与本章前面的实例使用同一个tld文件,因此不必再修改。
(4)第四步:在JSP页面中声明并调用标签。
<%@ taglib uri="/myTag" prefix="myTag" %> <%@ page contentType="text/html;charset=GB2312" %> <%@ page import="java.util.ArrayList"%> <head> <title>开发迭代的标签</title> </head> <body> 开发一个迭代的标签,输出结果:<br> <%//----------设置一个ArrayList对象的初始值---------- ArrayList testCol=new ArrayList(); testCol.add("邓佳容"); testCol.add("黄婧"); testCol.add("邓子云"); request.setAttribute("testCol",testCol); %> <myTag:iterateTag name="testColOne" collection="<%=testCol%>" type="String"> 输出一个值:<%=testColOne.toString()%><br> </myTag:iterateTag> </body> </html> |