目录
一,标签库描述文件(tld文件)
二,标签处理类
三,在JSP页面中使用自定义的标签
四,举个例子
通过Java的TagSupport类或者BodyTagSupport类,和配套的tld文件,可以定义自己的jsp标签。
TagSupport类和BodyTagSupport类在jsp-api.jar中,这个jar包在tomcat的lib目录下有,maven里面也有。
tld的全名:Tag Library Descriptor。
tld文件是一个XML文件,是自定义标签库的配置文件。
这个文件应该放在web项目的WEB-INF目录下,或其子目录下,如果放在其他位置,需要在web.xml文件中做配置。
下面是一个简单的标签库描述文件的例子:
myFirstTag.tld
1.0
1.2
testTagLib
/test-tags
"自定义标签"
TagA
com.mytest.TagA
jsp
这个一个标签
attributeA
true
true
属性A
TagB
com.mytest.TagB
jsp
这个一个标签
attributeA
true
true
属性A
文件的主体是
其中的
其中的
标签处理类是在描述文件中用
如果选择继承TagSupport类,可以重写以下方法:
public int doStartTag()
public int doEndTag()
public int doAfterBody()
如果选择继承BodyTagSupport类,可以额外重写以下方法:
public void setBodyContent(BodyContent b)
public void doInitBody()
下面分别介绍这几个方法:
doStartTag()
这是在java开始处理头标签时执行的方法,可以在这里构造将要输出到页面的代码,或者做其他的处理。
这个方法的返回值是int,有以下选择:
1,EVAL_BODY_INCLUDE。
这个静态变量在javax.servlet.jsp.tagext.Tag接口中,实际值是1。
这个返回值表示正常加载标签的body(也就是标签的innerHTML)。
2,SKIP_BODY。
这个静态变量在javax.servlet.jsp.tagext.Tag接口中,实际值是0。
这个返回值表示不会加载标签的body。一般情况下doStargTag()方法返回这个值后将执行doEndTag()方法。
3,EVAL_BODY_BUFFERED。
这个静态变量在javax.servlet.jsp.tagext.BodyTag接口中,实际值是2。
只有处理类继承了BodyTagSupport时可以使用(详见下面的类继承关系图)。
这个返回值用来在后面的代码中处理标签的body。当使用这个返回值时,Java会构造一个BodyContent对象,并把标签的body载入这个对象。
另外,BodyContent对象内部也有一个JspWriter,可以用BodyContent对对象的body进行处理。是否可以修改body是BodyTagSupport和TagSupport最大的区别。
注意:如果使用了这个返回值并重写了相关方法,需要在代码中显式写明body部分的加载,否则body只会写入BodyContent对象而不会加载到页面。
doEndTag()
这是在java开始处理尾标签时执行的方法,这个方法中也可以构造将要输出到页面的代码,或者其他处理。
这个方法的返回值是int,有以下选择:
1,EVAL_PAGE。
这个静态变量在javax.servlet.jsp.tagext.Tag接口中,实际值是6。
这个返回值表示继续加载此标签之后的页面代码。
2,SKIP_PAGE。
这个静态变量在javax.servlet.jsp.tagext.Tag接口中,实际值是5。
这个返回值表示不再继续加载此标签之后的页面代码,直接将jsp现有已经处理完的页面代码发送给客户端。
没有想到什么情况下用得着这个返回值。
doAfterBody()
这个方法在doStartTag()方法返回EVAL_BODY_INCLUDE并且加载完标签的body后加载。
这个方法的返回值是int,有以下选择:
1,EVAL_BODY_AGAIN。
这个静态变量在javax.servlet.jsp.tagext.IterationTag接口中,实际值是5。
这个返回值表示再次加载标签的body。
按照执行顺序,再次加载一次body之后会再次执行这个方法,注意不要写成死循环。
2,SKIP_BODY。
同doStartTag()方法的同名返回值。
java不会再加载标签的body,向后执行。一般情况下后面将执行doEndTag()方法。
setBodyContent(BodyContent b)
这个方法是在调用doStartTag()方法,并返回EVAL_BODY_BUFFERED之后调用的。BodyTagSupport子类专用。
Java构造了BodyContent对象之后调用这个方法把BodyContent对象传给处理类,BodyTagSupport类中这个方法里面只有一行:
this.bodyContent = b;
如果重写了这个方法,至少也要把这行加上,否则无法使用BodyContent对象。
该方法没有返回值。
doInitBody()
该方法在调用setBodyContent(BodyContent b)方法后执行,可以对body进行一些初始化工作。BodyTagSupport子类专用。
BodyTagSupport类中这个方法里面没有代码。
这个方法没有返回值。
上述类和接口的关系图大概是这样的:
当java处理标签时,根据返回值的不同,方法的调用顺序大概是这样的:
1,在JSP页面中,首先要引用标签库:
<%@ taglib prefix="t" uri="/test-tags"%>
prefix是标签前缀,和标签库中的
uri参数和标签库中的
2,引用了标签库之后,就可以使用自定义的标签了:
number2:
上面的例子就是有body的标签,body就是
number2:
这一部分,通过调整方法的返回值可以控制该部分是否显示。
1,首先是tld标签描述文件
myFirstTag.tld
1.0
1.2
testTagLib
/test-tags
"自定义标签"
TagA
com.mytest.TagA
jsp
这是一个标签
attributeA
true
true
属性A
TagB
com.mytest.TagB
jsp
这是一个标签
attributeA
true
true
属性A
在这个描述文件中定义了两个标签,TagA和TagB
2,标签TagA的处理类TagA.java
TagA.java
package com.mytest;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
public class TagA extends BodyTagSupport{
private static final long serialVersionUID = 1L;
protected String attributeA;
public String getAttributeA() {
return attributeA;
}
public void setAttributeA(String attributeA) {
this.attributeA = attributeA;
}
@Override
public int doStartTag(){
JspWriter w=this.pageContext.getOut();
StringBuffer sb = new StringBuffer();
sb.append("");
try {
w.print(sb.toString());
w.flush();
} catch (IOException e) {
e.printStackTrace();
}
if("extra".equals(attributeA)){
return EVAL_PAGE;
}else{
return SKIP_PAGE;
}
}
}
这个类重写了doStartTag(),doEndTag()和doAfterBody()等方法,其中doAfterBody()方法里面没写什么东西,和父类的原方法保持一致。
这个处理类的功能是把自定义的标签写成了一个form表单,并添加了名为number1的文本框,当属性attributeA等于extra时显示number2文本框,并且正常加载标签后面的网页内容,否则不会显示number2文本框,并且立即结束页面加载,发送给客户端。
3,JSP页面
testTagPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="testTagLib" uri="/test-tags"%>
TestTagPage
extra
number2:
number3:
no extra
number2:
number3:
这个页面显示出来是这样的:
分析一下:
当java第一次加载TagA标签时(分隔线上面部分),属性attributeA等于extra,
doStartTag()方法返回值是EVAL_BODY_INCLUDE,表示正常加载body部分的页面代码,
doEndTag()方法返回值是EVAL_PAGE,表示正常加载标签后面的内容,所以第二个TagA标签才得以加载。
当java第二次加载TagA标签时(分隔线下面部分),属性attributeA等于noextra,
doStartTag()方法返回值是SKIP_BODY,表示不会加载body部分的页面代码,
doEndTag()方法返回值是SKIP_PAGE,表示不会加载标签后面的内容,所以第二个TagA标签后面的number3标签和