编写自定义标签

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
class
DoContent 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
class
DoPage 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
class
DoIteration 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
class
DoChangeContent 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
class
ViewIpTag 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
void
setPageContext(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
class
DoIteration 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
class
SkipContent 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
class
IterationDemo 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
class
ChangeContent 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
class
SkipPage 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
class
HtmlFilter 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("&lt;");

break;

case
‘>‘:

result.append("&gt;");

break;

case
‘&‘:

result.append("&amp;");

break;

case
‘"‘:

result.append("&quot;");

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
class
Referer 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>

时间: 2024-11-05 14:44:58

编写自定义标签的相关文章

如何编写自定义标签?具体流程与分析(自定义标签快速入门)

1.自定义标签简介 自定义标签主要用于移除Jsp页面中的java代码 使用自定义标签移除jsp页面中的java代码,只需要完成以下两个步骤: 1.编写一个实现Tag接口的Java类(标签处理器类) 2.在WEB-INF中编写标签库描述符(tld)文件,在tld文件中对标签处理器类描述成一个标签 (参考tomcat中的examples 项目中jsp部分) 2.自定义标签的执行流程的分析 JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法.

Java编写自定义标签

在开发项目过程中,我们经常有这样的体会:同一个控件我们可能多处使用,同时我们需要在基础的样式上加上自己的样式和操作的js代码:遇到这种情况,如果每个地方都copy代码的话那么,后期如果要做修改,那么维护的工作量是巨大的,无疑是个灾难.基于这种情况,我们可以考虑使用自定义标签,实现代码的复用,后期的易维护. 先看一张关系图: 上图是我们开发自定义标签常用的接口,我们使用最快捷简便的方式,继承TagSupport类,只需重写doStartTag和doEndtag方法. 制作步骤: 一.编写java文

django “如何”系列4:如何编写自定义模板标签和过滤器

django的模板系统自带了一系列的内建标签和过滤器,一般情况下可以满足你的要求,如果觉得需更精准的模板标签或者过滤器,你可以自己编写模板标签和过滤器,然后使用{% load %}标签使用他们. 代码布局 自定义标签和过滤器必须依赖于一个django app,也就是说,自定义标签和过滤器是绑定app的.该app应该包含一个templatetags目录,这个目录一个和model.py,views.py在同一个层级,记得在该目录下建立一个__init__.py文件一遍django知道这是一个pyth

JSTL自定义标签(三)

上篇讲解的是JSTL常用的核心标签,本篇介绍JSTL自定义标签的使用.还记得在学js的时候,我们学习了JQuery框架,同时学习了构造自己的js库,再去调用自己的js库,这就如同根据自己的需要些一个内聚性强的函数一样,我们创建一个函数后,再去调用这个函数.在学习J2ee规范JSTL标签这一节的时候,同样我们可以根据自己的需要构造自己的标签库,再去使用自己定义的这个标签. JSTL自带的标签功能时非常强大的,但是不能完全满足我们的需要,开发标签首先是需要开发标签对应的功能类,就和写函数一样,这个函

学会怎样使用Jsp 内置标签、jstl标签库及自定义标签

学习jsp不得不学习jsp标签,一般来说,对于一个jsp开发者,可以理解为jsp页面中出现的java代码越少,对jsp的掌握就越好,而替换掉java代码的重要方式就是使用jsp标签. jsp标签的分类: 1)内置标签(动作标签): 不需要在jsp页面导入标签 2)jstl标签: 需要在jsp页面中导入标签 3)自定义标签 : 开发者自行定义,需要在jsp页面导入标签 1.内置标签(动作标签): <jsp:forward />转发标签: 语法:<jsp:forward page="

EL函数以及自定义标签的应用

一.EL函数(调用普通类的静态方法) 编写步骤(自定义EL函数的编写步骤即自定义标签的编写步骤): ①编写一个普通的java类,提供一个静态方法,功能自定,例如下: package cn.wzbrilliant.el; public class ElFunction { public static String toUpperCase(String str){ return str.toUpperCase(); } } ②在JavaWeb应用的WEB-INF目录下建立一个扩展名是tld(tagl

【JSP】自定义标签开放入门

JSP 自定义标签 自定义标签是用户定义的JSP语言元素.当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被 称为tag handler的对象的操作,即当servlet执行时Web container调用那些操作. JSP标签扩展可以让你创建新的标签并且可以直接插入到一个JSP页面. JSP 2.0规范中引入Simple Tag Handlers来编写这些自定义标记. 你可以继承SimpleTagSupport类并重写的doTag()方法来开发一个最简单的自定义标签 开发步

Java之自定义标签一

在JSP页面中,通常为了处理某些业务逻辑需要编写大量的Java代码,在一定程度上使得页面变得更加的复杂,并且不直观,也不利于前端人员对jsp页面的修改,通过自定义标签可以实现负责的.可重复利用的功能,并且简化了jsp页面,方便了后期的维护和修改. 一.实现自定义标签的步骤 1.首先编写自定义标签处理类:继承或实现相应的接口 2.编写标签描述文件:存放到网站的web-info目录中 3.在页面中引入标签文件 二.自定义标签实现类和接口的描述 JspTag:标记接口,实现了该接口的类可以处理标签 T

EL表达式 JSTL的标签库 EL的函数 自定义EL函数 自定义标签 JSP的开发模式 注册登陆案例

EL表达式 JSTL的标签库 EL的函数 自定义EL函数 自定义标签 JSP的开发模式 注册登陆案例 EL表达式 1.获取域对象中的值 2.EL表达式支持运算 ${ num1 + num2 } EL获取常用的WEB对象 1.pageScope 获取page域对象的值 2.requestScope 获取request域对象的值 3.sessionScope 获取session域对象的值 4.applicationScope 获取application域对象的值 * 例子:向某个域中来存入值 req