1.8 编写自定义标签
一、作用:
自定义标签主要用于移除Jsp页面中的java代码。
? 控制jsp页面某一部分内容是否执行。
? 控制整个jsp页面是否执行。
? 控制jsp页面内容重复执行。
? 修改j页面内容输出。
二、标签体系:传统标签和简单标签:
1. JspTag接口
JspTag接口是所有自定义标签的父接口,它是JSP2.0中新定义的一个标记接口,没有任何属性和方法。JspTag接口有Tag和SimpleTag两个直接子接口,JSP2.0以前的版本中只有Tag接口,所以把实现Tag接口的自定义标签也叫做传统标签,把实现SimpleTag接口的自定义标签叫做简单标签。本书中如果没有特别说明,自定义标签泛指传统标签。
2. Tag接口
图6.5中的Tag接口是所有传统标签的父接口,其中定义了两个重要方法(doStartTag、doEndTag)方法和四个常量(EVAL_BODY_INCLUDE、SKIP_BODY、EVAL_PAGE、SKIP_PAGE),这两个方法和四个常量的作用如下:
(1)WEB容器在解释执行JSP页面的过程中,遇到自定义标签的开始标记就会去调用标签处理器的doStartTag方法,doStartTag方法执行完后可以向WEB容器返回常量EVAL_BODY_INCLUDE或SKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODY,WEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。
(2)WEB容器解释执行到自定义标签的结束标记时,就会调用标签处理器的doEndTag方法,doEndTag方法执行完后可以向WEB容器返回常量EVAL_PAGE或SKIP_PAGE。如果doEndTag方法返回常量EVAL_PAGE,WEB容器就会接着执行JSP页面中位于结束标记后面的JSP代码;如果doEndTag方法返回SKIP_PAGE,WEB容器就会忽略JSP页面中位于结束标记后面的所有内容。
从doStartTag和doEndTag方法的作用和返回值的作用可以看出,开发自定义标签时可以在doStartTag方法和doEndTag方法体内编写合适的Java程序代码来实现具体的功能,通过控制doStartTag方法和doEndTag方法的返回值,还可以告诉WEB容器是否执行自定义标签中的标签体内容和JSP页面中位于自定义标签的结束标记后面的内容。
2. IterationTag接口
IterationTag接口继承了Tag接口,并在Tag接口的基础上增加了一个doAfterBody方法和一个EVAL_BODY_AGAIN常量。实现IterationTag接口的标签除了可以完成Tag接口所能完成的功能外,还能够通知WEB容器是否重复执行标签体内容。对于实现了IterationTag接口的自定义标签,WEB容器在执行完自定义标签的标签体后,将调用标签处理器的doAfterBody方法,doAfterBody方法可以向WEB容器返回常量EVAL_BODY_AGAIN或SKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAIN,WEB容器就会把标签体内容再重复执行一次,执行完后接着再调用doAfterBody方法,如此往复,直到doAfterBody方法返回常量SKIP_BODY,WEB容器才会开始处理标签的结束标记和调用doEndTag方法。
可见,开发自定义标签时,可以通过控制doAfterBody方法的返回值来告诉WEB容器是否重复执行标签体内容,从而达到循环处理标签体内容的效果。例如,可以通过一个实现IterationTag接口的标签来迭代输出一个集合中的所有元素,在标签体部分指定元素的输出格式。
在JSP API中也提供了IterationTag接口的默认实现类TagSupport,读者在编写自定义标签的标签处理器类时,可以继承和扩展TagSupport类,这相比实现IterationTag接口将简化开发工作。
3. BodyTag接口
BodyTag接口继承了IterationTag接口,并在IterationTag接口的基础上增加了两个方法(setBodyContent、doInitBody)和一个EVAL_BODY_BUFFERED常量。实现BodyTag接口的标签除了可以完成IterationTag接口所能完成的功能,还可以对标签体内容进行修改。对于实现了BodyTag接口的自定义标签,标签处理器的doStartTag方法不仅可以返回前面讲解的常量EVAL_BODY_INCLUDE或SKIP_BODY,还可以返回常量EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFERED,WEB容器就会创建一个专用于捕获标签体运行结果的BodyContent对象,然后调用标签处理器的setBodyContent方法将BodyContent对象的引用传递给标签处理器,WEB容器接着将标签体的执行结果写入到BodyContent对象中。在标签处理器的后续事件方法中,可以通过先前保存的BodyContent对象的引用来获取标签体的执行结果,然后调用BodyContent对象特有的方法对BodyContent对象中的内容(即标签体的执行结果)进行修改和控制其输出。
在JSP API中也提供了BodyTag接口的实现类BodyTagSupport,读者在编写能够修改标签体内容的自定义标签的标签处理器类时,可以继承和扩展BodyTagSupport类,这相比实现BodyTag接口将简化开发工作。
4. SimpleTag接口
SimpleTag接口是JSP2.0中新增的一个标签接口。由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,因此,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口。SimpleTag接口与传统标签接口最大的区别在于,SimpleTag接口只定义了一个用于处理标签逻辑的doTag方法,该方法在WEB容器执行自定义标签时调用,并且只被调用一次。那些使用传统标签接口所完成的功能,例如是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。关于SimpleTag接口的详细介绍本书将在第7章详细讲解。
在JSP API中也提供了SimpleTag接口的实现类SimpleTagSupport,读者在编写简单标签时,可以继承和扩展SimpleTagSupport类,这相比实现SimpleTag接口将简化开发工作。
为方便读者日后查询传统标签接口中的各个方法可以返回的返回值,笔者在表6.1列举了Tag接口、IterationTag接口和BodyTag接口中的主要方法及它们分别可以返回的返回值的说明。
表6.1
三、传统标签Tag
1、Tag接口的执行流程:
JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。
1、publicvoid setPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。
2、publicvoid setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。
3、public intdoStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。
l 如果这个方法返回this.EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体
l 如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp
4、public intdoEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。
l 控制doStartTag方法,返回EVAL_BODY_BUFFERED,则web服务器会创建BodyContent对象捕获标签体,开发人员在doendtag方法体内,得到代表标签体的bodyContent对象,从而就可以对标签体进行修改。。。。。。操作。
5、publicvoid release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。
6、TagSupport类的doAfterBody()方法
l 如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。
2、自定义标签进行控制标签是否执行的原理
1. 编写一个类实现tag接口(继承TagSupport类),
控制jsp页面某一部分内容是否执行。
控制dostarttag方法的返回值,如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体
控制整个jsp页面是否执行。
控制doendtag方法的返回值,如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp
控制jsp页面内容重复执行。
的返回值EVAL_BODY_INCLUDE,控制doAfterBody方法的返回值,如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。
修改jsp页面内容输出。
控制doStartTag方法,返回EVAL_BODY_BUFFERED,则web服务器会创建BodyContent对象捕获标签体,开发人员在doendtag方法体内,得到代表标签体的bodyContent对象,从而就可以对标签体进行修改。。。。。。操作。
3、自定义传统标签例子(没有带属性):
一:控制jsp页面某一部分内容是否执行。
思路:编写一个类实现tag接口(继承TagSupport类),控制dostarttag方法的返回值,如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体
1:java类
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
//控制jsp页面某一部分内容是否执行。重写doStarTag()方法
public
classDoContent extends TagSupport
{
@Override
public
int doStartTag() throws JspException
{
// returnTagSupport.SKIP_BODY;//跳过
return TagSupport.EVAL_BODY_INCLUDE;//执行
}
}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>doContent</name>
<tag-class>cn.zhong.web.tag.DoContent</tag-class>
<body-content>JSP</body-content>
</tag>
</taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="zhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<zhong:doContent> <!--
控制jsp页面某一部分内容是否执行。 -->
测试是否要显示的内容
</zhong:doContent>
</body>
</html>
二:控制整个jsp页面是否执行。
思路:编写一个类实现tag接口(继承TagSupport类),控制doendtag方法的返回值,如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp
1:java类
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
//控制整个jsp页面是否执行。重写doEndTag()方法
public
classDoPage extendsTagSupport
{
public
int doEndTag() throws
JspException
{
return
TagSupport.EVAL_PAGE;//执行
// returnTagSupport.SKIP_PAGE;//跳过
}
}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>doPage</name>
<!-- 为标签处理器类配一个标签名 -->
<tag-class>cn.zhong.web.tag.DoPage</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="zhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<zhong:doPage/><!-- 控制下面整个jsp页面是否执行。 -->
<html>
<head>
<title>www.zhong.com</title>
</head>
<body></body>
</html>
三:控制jsp页面内容重复执行。
思路:编写一个类实现Iterationtag接口(继承TagSupport类),控制dostarttag方法的返回值EVAL_BODY_INCLUDE,控制doAfterBody方法的返回值,如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。
1:java类
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
//控制jsp页面内容重复执行。
public
classDoIteration extends TagSupport
{
int
x=5; //默认重复的次数
public
int doStartTag() throws JspException {
return TagSupport.EVAL_BODY_INCLUDE;
}
public
int doAfterBody() throws JspException
{
x--;
if(x>0){
return TagSupport.EVAL_BODY_AGAIN;
}else{
return TagSupport.SKIP_BODY;
}
}
}}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>DoIteration</name>
<tag-class>cn.zhong.web.tag.DoIteration</tag-class>
<body-content>JSP</body-content>
</tag></taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="zhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<%--
控制jsp页面内容重复执行。 --%>
<zhong:DoIteration>
sdadfdsf
</zhong:DoIteration>
</body>
</html>
四:修改jsp页面内容输出。
思路:编写一个类实现BodyTag接口(继承BodyTagSupport类),控制doStartTag方法,返回EVAL_BODY_BUFFERED,则web服务器会创建BodyContent对象捕获标签体,开发人员在doendtag方法体内,得到代表标签体的bodyContent对象,从而就可以对标签体进行修改。。。。。。操作。
1:java类
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
//修改jsp页面内容输出(将字母转成大写)。
public
classDoChangeContent extends
BodyTagSupport{
public
int doStartTag() throws JspException{
return BodyTagSupport.EVAL_BODY_BUFFERED;
}
public
int doEndTag() throws JspException{
Stringvalue=this.getBodyContent().getString();//获得标签里面的内容
value=value.toUpperCase();//转成大写
try{
pageContext.getOut().write(value);//调用jsp输出流写出内容
}catch(IOException e){
e.printStackTrace();
}
return BodyTagSupport.EVAL_PAGE;
}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>DoChangeContent</name>
<tag-class>cn.zhong.web.tag.DoChangeContent</tag-class>
<body-content>JSP</body-content>
</tag></taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="zhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<zhong:DoChangeContent>
<!-- 修改jsp页面内容输出。 -->
abcd
</zhong:DoChangeContent>
</body>
</html>
五:显示本机ip的标签
思路:编写实现Tag接口的标签,获得本机的ip, 向浏览器输出ip
1:java类
public
classViewIpTag implementsTag {
private PageContext
pageContext;
public
int doEndTag() throws JspException {
return 0;
}
public
int doStartTag() throws JspException {
Stringip = pageContext.getRequest().getRemoteAddr();//获得ip
JspWriterout = pageContext.getOut();//获得输出流
try {
out.write(ip);//向浏览器输出ip
}catch(IOException e) {
e.printStackTrace();
}
return 0;
}
@Override
public Tag getParent() {
return
null;
}
@Override
public
void release() {
}
@Override
public
voidsetPageContext(PageContext arg0) {
this.pageContext = arg0;
}
@Override
public
void setParent(Tag arg0) {
}
}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>DoChangeContent</name>
<tag-class>cn.zhong.web.tag.DoChangeContent</tag-class>
<body-content>JSP</body-content>
</tag></taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="zhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
你的ip是:
<zhong:viewIP/>
</body>
</html>
3、自定义传统标签例子(带自定义属性):
思路:编写一个类实现Iterationtag接口(继承TagSupport类),控制dostarttag方法的返回值EVAL_BODY_INCLUDE,控制doAfterBody方法的返回值,如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。
1:java类
//控制jsp页面内容重复执行,获得页面传过来的属性count,进行重复count次输出,如果页面赶写var属性,就将当前对象存入域里面
public
classDoIteration extends TagSupport {
private
int count;
// jsp页面填写的参数,要生成set,get方法
private
int index;//
记录当前的次数要生成set,get方法
private String
var;// jsp页面填写的参数,以这个将数据存入某个域中 ,要生成set,get方法
public
int doStartTag() throws JspException {
index = 1;//
重新初始化,要不刷新时,不会从1开始
if (var !=
null && !var.equals("")) {
this.pageContext.setAttribute(var,
this);
}
return TagSupport.EVAL_BODY_INCLUDE;
}
public
int doAfterBody() throws JspException {
index++;
if (var !=
null && !var.equals("")) {
this.pageContext.setAttribute(var,
this);
}
count--;
if (count > 0) {
return TagSupport.EVAL_BODY_AGAIN;
}else{
return TagSupport.SKIP_BODY;
}
}
public
int getCount() {
return
count;
}
…三个属性的set,get方法省略
}
2:在web-inf/目录下新建tld文件zhong.tld
在tld文件中对标签处理器进行描述
<?xml
version="1.0"encoding="UTF-8"?>
<!DOCTYPE
taglib PUBLIC
"-//SunMicrosystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/zhong</uri>
<tag>
<name>DoIterationAttr</name>
<tag-class>cn.zhong.web.tag.attribute.DoIteration</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>count</name><!--
用于指定属性的名称-->
<required>true</required><!--
这个参数是否是必须的 -->
<rtexprvalue>true</rtexprvalue>
<!—是否支持动态表达式-->
<type>int</type>
<!-- 参数的类型:如果是对象类型:要这样写java.lang.Object -->
<description>
<!-- 用于指定属性的描述信息。 -->
这个参数指定了循环的次数
</description>
</attribute>
<attribute>
<name>var</name>
<required>false</required>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
3:在jsp页面使用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/zhong"prefix="z"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<z:DoIterationAttr
count="5"
var="a">
输出第${a.index}次数
</z:DoIterationAttr>
<br/>
<z:DoIterationAttr
count="5"
>
输出次数
</z:DoIterationAttr></body>
</html>
四、简单标签SimpleTag
由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。实现SimpleTag接口的标签通常称为简单标签。简单标签共定义了5个方法:
? setJspContext方法
? setParent和getParent方法
? setJspBody方法
? doTag方法
1、SimpleTag接口方法的执行顺序
l 当web容器开始执行标签时,会调用如下方法完成标签的初始化
? WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
? WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
? 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
? 如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
l 执行标签时:
容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。
2、SimpleTag方法
l setJspContext方法
用于把JSP页面的pageContext对象传递给标签处理器对象
l setParent方法
用于把父标签处理器对象传递给当前标签处理器对象
l getParent方法
用于获得当前标签的父标签处理器对象
l setJspBody方法
用于把代表标签体的JspFragment对象传递给标签处理器对象
l doTag方法
用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量
3、JspFragment类(在简单标签中调用this.getJspBody()获得这个对象)
l javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
l WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:
l getJspContext方法
? 用于返回代表调用页面的JspContext对象.
l publicabstract void invoke(java.io.Writer out)
? 用于执行JspFragment对象所代表的JSP代码片段
? 参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)
?
l JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
? 在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
? 在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
? 若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
// invoke(传入一个流);if is null,默认打给浏览器
?
4、自定义简单标签的例子:
一:控制jsp页面某一部分内容是否执行。
思路.在dotag方法里面不调用jspFrament.invoke方法即可
1:java类
//控制jsp页面某一部分内容是否执行。
public
classSkipContent extends SimpleTagSupport {
public
void doTag() throws JspException,IOException {
//this.getJspBody().invoke(null); 注掉了,就不会输出标签里面的内容了
// invoke(传入一个流);if is null,默认打给浏览器
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>SkipContent</name>
<tag-class>cn.zhong.web.simpletag.SkipContent</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
3:jsp里面调用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="simplezhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<simplezhong:SkipContent><!--
控件标签体中的内容是否输出 -->
<table>
<tr>
<td>addsfdas</td>
</tr>
</table>
</simplezhong:SkipContent>
</body>
</html>
二:控制jsp页面内容重复执行(自定义参数)。
思路.在dotag方法重复调用jspFrament.invoke方法即可
1:java类
//控制jsp页面内容重复执行。
public
classIterationDemo extends SimpleTagSupport {
private
int count;//接收页面传来的次数
public
void doTag() throws JspException,IOException {
for (int i = 0; i <
count; i++) {
this.getJspBody().invoke(null);
}
}
public
int getCount() {
return
count;
}
public
void setCount(int count) {
this.count = count;
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>IterationDemo</name>
<tag-class>cn.zhong.web.simpletag.IterationDemo</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>count</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>int</type>
</attribute>
</tag></taglib>
3:jsp里面调用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="simplezhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<simplezhong:IterationDemo
count="20"><!--
重复输出内容-->
ddsds<br/>
</simplezhong:IterationDemo>
</body>
</html>
三:修改jsp页面内容输出
思路.在dotag方法调用jspFrament.invoke方法时,让执行结果写一个自定义的缓冲中即可,然后开发人员可以取出缓冲的数据修改输 出
1:java类
//修改jsp页面内容输出
public
classChangeContent extends SimpleTagSupport {
@Override
public
void doTag() throws JspException,IOException {
JspFragmentfra = this.getJspBody();
StringWritersw = newStringWriter();
fra.invoke(sw);
Stringvalue = sw.getBuffer().toString();
value= value.toUpperCase();
this.getJspContext().getOut().write(value);
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>ChangeContent</name>
<tag-class>cn.zhong.web.simpletag.ChangeContent</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
3:jsp里面调用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="simplezhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<simplezhong:ChangeContent><!--
修改jsp页面内容输出 -->
ddsds
</simplezhong:ChangeContent>
</body>
</html>
四:根据用户否登录、控制整个jsp页面是否显示。
思路.在dotag方法抛SKIPPageException即可,jsp收到这个异常,将忽略标签余下jsp页面的执行
1:java类
//控制整个jsp页面是否执行。
public
classSkipPage extendsSimpleTagSupport {
private Object
loginUser;//从页面用el表达式从session域入传入登录的用户
public
void doTag() throws JspException,IOException {
if (loginUser ==
null) {//如果用户为空,即没有登录
this.getJspContext().getOut().write("<h1>你还没有登录,请登录后再访问<h1>");
throw
new SkipPageException();
}
}
public Object getLoginUser() {
return
loginUser;
}
public
void setLoginUser(ObjectloginUser) {
this.loginUser = loginUser;
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>SkipPage</name>
<tag-class>cn.zhong.web.simpletag.SkipPage</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>loginUser</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue><!--
一定要支持表达式:要不不能用el表达式从域中取出登录的用户 -->
<type>java.lang.Object</type>
</attribute>
</tag>
</taglib>
3:jsp里面调用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="simplezhong"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<%
Integerinteger = newInteger(12);
request.getSession().setAttribute("user", integer);
%>
<simplezhong:SkipPage
loginUser="${user}"></simplezhong:SkipPage>
<!—根据是否登录控制以下全部jsp是否出现 -->
<body>
登录后能显示的内容
</body>
</html>
五、自定义标签实际中的实用
1、自定义标签开发转义标签(原样显示html)
1、java类
//转义标签
public
classHtmlFilter extendsSimpleTagSupport {
@Override
public
void doTag() throws JspException,IOException {
StringWritersw = newStringWriter();
this.getJspBody().invoke(sw);
// 得到标签体:<a
href="">点点</a>
Stringcontent = sw.getBuffer().toString();
content= filter(content);
// 输出转义内容
this.getJspContext().getOut().write(content);
}
// 转义方法
private String filter(Stringmessage) {
if (message ==
null)
return (null);
char content[] =
new char[message.length()];
message.getChars(0,message.length(), content, 0);
StringBufferresult = newStringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case
‘<‘:
result.append("<");
break;
case
‘>‘:
result.append(">");
break;
case
‘&‘:
result.append("&");
break;
case
‘"‘:
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>htmlFilter</name>
<tag-class>cn.zhong.web.tagexample.HtmlFilter</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
3、jsp上应用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="z"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
<z:htmlFilter>
<a
href="${pageContext.request.contextPath}/doReferer.jsp">这就是超链接的写法</a>
</z:htmlFilter>
</body>
</html>
2、自定义标签开“防盗链”标签(其它网站不能引用我网站的超链接)
1、java类
//开发防盗链标签
public
classReferer extendsSimpleTagSupport {
private String
site;// 来的路径
private String
page;// 如果发现盗链后,跳转到的页面
@Override
public
void doTag() throws JspException,IOException {
PageContextcontext = (PageContext) this.getJspContext();
HttpServletRequestrequest = (HttpServletRequest) context.getRequest();
Stringpath = request.getHeader("referer");
if (path ==
null || !path.startsWith(site)) {
HttpServletResponseresponse = (HttpServletResponse) context
.getResponse();
Stringwebroot = request.getContextPath();
//day11_example
if (page.startsWith(webroot)) {
response.sendRedirect(page);
}else{
response.sendRedirect(webroot+
page);
}
// 重定向后,控制保护的页面不要执行
throw
new SkipPageException();
}
}
public
void setSite(String site) {
this.site = site;
}
public
void setPage(String page) {
this.page = page;
}
}
2:在web-inf/目录下新建tld文件simplezhong.tld
<?xml
version="1.0"encoding="UTF-8"?>
<taglib
version="2.0"xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simplezhong</uri>
<tag>
<name>referer</name>
<tag-class>cn.zhong.web.tagexample.Referer</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>site</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>page</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag></taglib>
3、jsp上应用
<%@
page language="java"import="java.util.*"
pageEncoding="UTF-8"%>
<%@taglib
uri="/simplezhong"prefix="z"%>
<!DOCTYPE
HTML PUBLIC
"-//W3C//DTDHTML 4.01 Transitional//EN">
<z:referersite="http://www.zhong.com:8080/" page="/index.jsp"/>
//如果不是从site这个网站跳转过来的,将转到page="/index.jsp"页面
<html>
<head>
<title>www.zhong.com</title>
</head>
<body>
不是盗链能显示的内容
</body>
</html>