一、作用:
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。则webserver会创建BodyContent对象捕获标签体。开发者在doendtag方法体内,得到代表标签体的bodyContent对象,从而就能够对标签体进行改动。
。。。
。
。操作。
5、publicvoid release(),通常WEB容器运行完自己定义标签后。标签处理器会驻留在内存中,为其他请求server,直至停止web应用时。web容器才会调用release方法。
6、TagSupport类的doAfterBody()方法
l 假设这种方法返回EVAL_BODY_AGAIN, 则webserver又运行一次标签体。依次类推,一直运行到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, 则webserver又运行一次标签体,依次类推,一直运行到doAfterBody方法返回SKIP_BODY,则标签体才不会反复运行。
改动jsp页面内容输出。
控制doStartTag方法,返回EVAL_BODY_BUFFERED,则webserver会创建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。 则webserver又运行一次标签体,依次类推,一直运行到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。则webserver会创建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, 则webserver又运行一次标签体,依次类推,一直运行到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>
- 本文已收录于下面专栏:
浙公网安备 33010602011771号