JSP自定义标签库 开发技术详解 学习笔记
本文查阅方法:
1、查阅目录 —— 查阅本文目录,确定想要查阅的目录标题
2、快捷“查找” —— 在当前浏览器页面,按键 “Ctrl+F” 按键组合,开启浏览器的查找功能,
在查找搜索框中 输入需要查阅的 目录标题,便可以直接到达 标题内容 的位置。
3、学习小结 —— 文中的学习小结内容,是笔者在学习之后总结出的,开发时可直接参考其进行应用开发的内容, 进一步加快了本文的查阅 速度。(水平有限,仅供参考。)
本文目录
学习笔记
1、自定义标签简介
2、Tag接口的执行流程
3、自定义标签调用图解
4、自定义标签体系树状图
5、自定义标签体系中五个接口的 介绍
6、TLD标签描述文件 模版
7、自定义标签——传统标签Tag接口 Demo样例
(1)控制jsp页面某一部分内容是否执行。(权限控制)
(2) 控制整个jsp页面是否执行。(权限控制)
(3) 控制jsp页面内容重复执行。
(4) 修改jsp页面内容输出。
(5)其他案例:使用标签输出客户机IP。
8、简单标签(SimpleTag接口)介绍
9、SimpleTag接口中的 方法介绍
10、SimpleTag接口方法的执行顺序
11、JspFragment类详解
12、invoke方法详解
13、自定义标签——简单标签SimpleTag接口 Demo样例
(1)控制jsp页面某一部分内容是否执行。
(2)控制整个jsp页面是否执行 。(权限控制)
(3)控制jsp页面内容重复执行。
(4)修改jsp页面内容输出。
14、开发带属性的标签
15、在TLD中描述标签属性 attribute
16、开发带属性的标签Demo样例
17、自定义标签案例Demo(SimpleTag 接口及其实现类 SimpleTagSupport )
(1)开发防盗链标签——是否执行余下JSP
(2)开发<c:if>标签——是否执行标签
(3)开发<c:if><c:else>标签——演示父标签操作
(4)开发迭代标签——重复执行标签体
(5)开发html转义标签——修改标签体
学习笔记
(1)自定义标签的流程
(a)创建Java类,继承 SimpleTagSupport类。若有属性,则为其设定setter()方法。
(b)复写toTag()方法。并在方法内进行针对JSP页面的逻辑控制编码。
(c)在TLD文件中注册 Tag标签。
(d)在JSP页面中使用<%@tag uri="" prefix=""%> 指令 引入自定义标签。
(e)在目标位置调用自定义标签。
(2)TLD文件模版
tld文件模版:my.tld :
<?xml version="1.0" encoding="UTF-8" ?>
<taglib 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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>A tag library exercising SimpleTag handlers.</description>
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/my</uri> //注:该部分uri可以自定义修改。
//自定义标签 描述部分
<tag>
<name>demo1</name>
<tag-class>cn.sina.web.tag.TagDemo1</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>site</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue> //支持EL表达式
</attribute>
</tag>
//自定义标签函数 描述部分
<function>
<name>add</name>
<function-class>cn.sina.demo.MyEL</function-class>
<function-signature>java.lang.String add( java.lang.String,java.lang.String )</function-signature>
</function>
</taglib>
(3)Demo样例:开发防盗链标签——是否执行余下JSP
标签处理器类:
public class RefererTag extends SimpleTagSupport {
private String site; //重定向的页面: 定义JSP页面端,自定义标签的属性
private String page; //重定向的站点名称:定义JSP页面端,自定义标签的属性
public void setSite(String site) {
this.site = site;
}
public void setPage(String page) {
this.page = page;
}
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) this.getJspContext();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
//1.得到来访问者referer
String referer = request.getHeader("referer");
//2.判断来访者的页面是不是要防盗链的网站
if(referer==null || !referer.startsWith(site)){
if(page.startsWith(request.getContextPath())){
response.sendRedirect(page);
}else if(page.startsWith("/")){
response.sendRedirect(request.getContextPath() + page);
}else{
response.sendRedirect(request.getContextPath() + "/" + page);
}
throw new SkipPageException();
}
}
}
TLD文件:
<tag>
<name>referer</name>
<tag-class>cn.sina .web.tag.example.RefererTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>site</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue> //支持EL表达式
</attribute>
<attribute>
<name>page</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="e" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<e:referer site="http://localhost" page="index.jsp"/>
<html>
<head>
<title>My JSP '1.jsp' starting page</title>
</head>
<body>
采访凤姐xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx采访凤姐!!!
</body>
</html>
1、自定义标签简介
自定义标签主要用于移除Jsp页面中的java代码。
使用自定义标签移除jsp页面中的java代码,只需要完成以下两个步骤:
(1)编写一个实现Tag接口的Java类(标签处理器类)。
(2)编写标签库描述符(tld)文件,在tld文件中对标签处理器类描述成一个标签。
2、Tag接口的执行流程
JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。
(1)public void setPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。
(2) public void setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。
(3) public int doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。
(4) public int doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。
(5) public void release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务,直至停止web应用时,web容器才会调用release方法。
3、自定义标签调用图解
4、自定义标签体系树状图
5、自定义标签体系中五个接口的 介绍
(1) JspTag接口
JspTag接口是所有自定义标签的父接口,它是JSP2.0中新定义的一个标记接口,没有任何属性和方法。JspTag接口有Tag和SimpleTag两个直接子接口,JSP2.0以前的版本中只有Tag接口,所以把实现Tag接口的自定义标签也叫做传统标签,把实现SimpleTag接口的自定义标签叫做简单标签。本文中如果没有特别说明,自定义标签泛指传统标签。
(2) Tag接口
上图中的Tag接口是所有传统标签的父接口,其中定义了两个重要方法(doStartTag、doEndTag)方法和四个常量(EVAL_BODY_INCLUDE、SKIP_BODY、EVAL_PAGE、SKIP_PAGE),这两个方法和四个常量的作用如下:
(a)WEB容器在解释执行JSP页面的过程中,遇到自定义标签的开始标记就会去调用标签处理器的doStartTag方法,doStartTag方法执行完后可以向WEB容器返回常量EVAL_BODY_INCLUDE或SKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODY,WEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。
(b)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页面中位于自定义标签的结束标记后面的内容。
(3) 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接口将简化开发工作。
(4) 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接口将简化开发工作。
(5) SimpleTag接口
SimpleTag接口是JSP2.0中新增的一个标签接口。由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,因此,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口。SimpleTag接口与传统标签接口最大的区别在于,SimpleTag接口只定义了一个用于处理标签逻辑的doTag方法,该方法在WEB容器执行自定义标签时调用,并且只被调用一次。那些使用传统标签接口所完成的功能,例如是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。
在JSP API中也提供了SimpleTag接口的实现类SimpleTagSupport,读者在编写简单标签时,可以继承和扩展SimpleTagSupport类,这相比实现SimpleTag接口将简化开发工作。
为方便读者日后查询传统标签接口中的各个方法可以返回的返回值,在下表中列举了Tag接口、IterationTag接口和BodyTag接口中的主要方法及它们分别可以返回的返回值的说明。
6、TLD标签描述文件 模版
tld文件模版:my.tld :
<?xml version="1.0" encoding="UTF-8" ?>
<taglib 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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>A tag library exercising SimpleTag handlers.</description>
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/my</uri> //注:该部分uri可以自定义修改。
//自定义标签 描述部分
<tag>
<name>demo1</name>
<tag-class>cn.sina.web.tag.TagDemo1</tag-class>
<body-content>JSP</body-content>
</tag>
//自定义标签函数 描述部分
<function>
<name>add</name>
<function-class>cn.sina.demo.MyEL</function-class>
<function-signature>java.lang.String add( java.lang.String,java.lang.String )</function-signature>
</function>
</taglib>
7、自定义标签——传统标签接口 Demo样例
开发人员在编写Jsp页面时,经常还需要在页面中引入一些逻辑,例如:
(1)控制jsp页面某一部分内容是否执行。(权限控制)
Demo样例:
标签处理器类:
public class TagDemo1 extends TagSupport {
@Override
public int doStartTag() throws JspException {
return Tag.SKIP_BODY;
}
}
TLD文件:
<tag>
<name>demo1</name>
<tag-class>cn.sina .web.tag.TagDemo1</tag-class>
<body-content>JSP</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.sina .cn" prefix="sina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用标签控制页面内容(标签体)是否输出</title>
</head>
<body>
<sina :demo1>
aaaaa
</sina :demo1>
</body>
</html>
(2) 控制整个jsp页面是否执行。(权限控制)
Demo样例:
标签处理器类:
public class TagDemo2 extends TagSupport {
@Override
public int doEndTag() throws JspException {
return Tag.EVAL_PAGE;
}
}
TLD文件:
<tag>
<name>demo2</name>
<tag-class>cn.sina .web.tag.TagDemo2</tag-class>
<body-content>empty</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.sina .cn" prefix="sina " %>
<sina :demo2/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用标签控制整个jsp是否输出</title>
</head>
<body>
This is my JSP page. <br>
</body>
</html>
(3) 控制jsp页面内容重复执行。
Demo样例:
标签处理器类:
//控制标签体执行5次
public class TagDemo3 extends TagSupport {
int x = 5;
@Override
public int doStartTag() throws JspException {
return Tag.EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
x--;
if(x>0){
return IterationTag.EVAL_BODY_AGAIN;
}else{
return IterationTag.SKIP_BODY;
}
}
}
TLD文件:
<tag>
<name>demo3</name>
<tag-class>cn.sina .web.tag.TagDemo3</tag-class>
<body-content>JSP</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.sina .cn" prefix="sina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用标签控制标签体重复执行</title>
</head>
<body>
<sina :demo3>
This is my JSP page. <br>
</sina :demo3>
</body>
</html>
(4) 修改jsp页面内容输出。
Demo样例:
标签处理器类:
//修改标签体(把标签体改为大写)
public class TagDemo4 extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
// TODO Auto-generated method stub
return BodyTag.EVAL_BODY_BUFFERED;
}
@Override
public int doEndTag() throws JspException {
BodyContent bc = this.getBodyContent(); //得到标签体
String content = bc.getString();
content = content.toUpperCase();
try {
this.pageContext.getOut().write(content);
} catch (IOException e) {
throw new RuntimeException(e);
}
return Tag.EVAL_PAGE;
}
}
TLD文件:
<tag>
<name>demo4</name>
<tag-class>cn.sina sina .web.tag.TagDemo4</tag-class>
<body-content>JSP</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.sina .cn" prefix="sina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用标签修改jsp页面内容</title>
</head>
<body>
<sina :demo4>
aaaaaa
</sina :demo4>
</body>
</html>
(5)其他案例:使用标签输出客户机IP。
Demo样例:
标签处理器类:
public class ViewIPTag extends TagSupport {
@Override
public int doStartTag() throws JspException {
HttpServletRequest request = (HttpServletRequest) this.pageContext.getRequest();
JspWriter out = this.pageContext.getOut();
String ip = request.getRemoteAddr();
try {
out.print(ip);
}catch (IOException e) {
throw new RuntimeException(e);
}
return super.doStartTag();
}
}
TLD文件:
<tag>
<name>viewIP</name>
<tag-class>cn.sina .web.tag.ViewIPTag</tag-class>
<body-content>empty</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.sina .cn" prefix="sina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '1.jsp' starting page</title>
</head>
<body>
您的ip是:<sina :viewIP/>
</body>
</html>
自定义标签除了可以移除jsp页面java代码外,它也可以实现以上功能。
tld文件中的四种标签体类型:
EMPTY : 没有标签体 (传统标签和简单标签 通用)
JSP : 标签体为JSP片段 (传统标签Tag接口中使用)
scriptless : 没有脚本代码 (简单标签SimpleTag接口中使用)
tagdepentend :
8、简单标签(SimpleTag接口)介绍
由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。实现SimpleTag接口的标签通常称为简单标签。简单标签共定义了5个方法:
setJspContext方法
setParent和getParent方法
setJspBody方法
doTag方法
9、SimpleTag接口中的 方法介绍
(1)setJspContext方法
用于把JSP页面的pageContext对象传递给标签处理器对象
(2) setParent方法
用于把父标签处理器对象传递给当前标签处理器对象
(3) getParent方法
用于获得当前标签的父标签处理器对象
(4) setJspBody方法
用于把代表标签体的JspFragment对象传递给标签处理器对象
(5) doTag方法
用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。
在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。
10、SimpleTag接口方法的执行顺序
当web容器开始执行标签时,会调用如下方法完成标签的初始化
(1)WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
(2) WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
(3) 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
(4) 如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
(5) 执行标签时,容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。
11、JspFragment类详解
javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:
(1) getJspContext方法
用于返回代表调用页面的JspContext对象.
(2) public abstract void invoke(java.io.Writer out)
用于执行JspFragment对象所代表的JSP代码片段
备注:参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)
12、invoke方法详解
JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
(1) 在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
(2) 在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
(3) 若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
13、自定义标签——SimpleTag接口 Demo样例
(1)控制jsp页面某一部分内容是否执行。
Demo样例:
标签处理器类:
//控制标签体是否执行
public class SimpleTagDemo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jf = this.getJspBody();
//jf.invoke(this.getJspContext().getOut());
}
}
TLD文件:
<tag>
<name>demo1</name>
<tag-class>cn.sina .web.simpletag.SimpleTagDemo1</tag-class>
<body-content>scriptless</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/simpletag" prefix="ssina" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用简单标签控制是否执行标签体</title>
</head>
<body>
<ssina :demo1>
aaaaa
</ssina :demo1>
</body>
</html>
(2)控制整个jsp页面是否执行 。(权限控制)
Demo样例:
标签处理器类:
//控制标签余下的jsp不执行
public class SimpleTagDemo4 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
throw new SkipPageException();
}
}
TLD文件:
<tag>
<name>demo4</name>
<tag-class>cn.sina .web.simpletag.SimpleTagDemo4</tag-class>
<body-content>empty</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/simpletag" prefix="ssina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<ssina :demo4/>
<html>
<head>
<title>控制整个jsp页面是否执行 </title>
</head>
<body>
ssss
</body>
</html>
(3)控制jsp页面内容重复执行。
Demo样例:
标签处理器类:
//控制jsp页面内容重复执行
public class SimpleTagDemo2 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jf = this.getJspBody();
for(int i=0;i<5;i++){
jf.invoke(null);
//jf.invoke(this.getJspContext().getOut());
}
}
}
TLD文件:
<tag>
<name>demo2</name>
<tag-class>cn.sina .web.simpletag.SimpleTagDemo2</tag-class>
<body-content>scriptless</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/simpletag" prefix="ssina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>迭代标签体</title>
</head>
<body>
<ssina :demo2>
This is my JSP page. <br>
</ssina :demo2>
</body>
</html>
(4)修改jsp页面内容输出。
Demo样例:
标签处理器类:
//修改标签体
public class SimpleTagDemo3 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jf = this.getJspBody();
StringWriter sw = new StringWriter();
jf.invoke(sw);
String content = sw.toString();
content = content.toUpperCase();
this.getJspContext().getOut().write(content);
}
}
TLD文件:
<tag>
<name>demo3</name>
<tag-class>cn.sina .web.simpletag.SimpleTagDemo3</tag-class>
<body-content>scriptless</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/simpletag" prefix="ssina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>修改标签体</title>
</head>
<body>
<ssina :demo3>
aaaaaaa
</ssina :demo3>
</body>
</html>
14、开发带属性的标签
自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。
要想让一个自定义标签具有属性,通常需要完成两个任务:
(1)在标签处理器中编写每个属性对应的setter方法
(2)在TLD文件中描术标签的属性
为自定义标签 定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义标签时传递进来的属性值。 例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。
在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。
15、在TLD中描述标签属性 attribute
<tag>元素的<attribute>子元素用于描述自定义标签的一个属性,自定义标签所具有的每个属性都要对应一个<attribute>元素 。
<attribute>
<description>description</description>
<name>aaaa</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>ObjectType</type>
</attribute>
各属性详解
16、开发带属性的标签Demo样例
Demo样例:
标签处理器类:
public class SimpleTagDemo5 extends SimpleTagSupport {
private int count;
private Date date;
public void setCount(int count) {
this.count = count;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public void doTag() throws JspException, IOException {
JspFragment jf = this.getJspBody();
this.getJspContext().getOut().write(date.toLocaleString() + "<br/>");
for(int i=0;i<count;i++){
jf.invoke(null);
}
}
}
TLD文件:
<tag>
<name>demo5</name>
<tag-class>cn.sina .web.simpletag.SimpleTagDemo5</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>count</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>date</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/simpletag" prefix="ssina " %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>开发带属性的标签</title>
</head>
<body>
<ssina :demo5 count="3" date="<%=new Date() %>">
aaaaaa
</ssina :demo5>
</body>
</html>
17、自定义标签案例Demo(SimpleTag 接口及其实现类 SimpleTagSupport )
(1)开发防盗链标签——是否执行余下JSP
Demo样例:
标签处理器类:
public class RefererTag extends SimpleTagSupport {
private String site; //重定向的页面: 定义JSP页面端,自定义标签的属性
private String page; //重定向的站点名称:定义JSP页面端,自定义标签的属性
public void setSite(String site) {
this.site = site;
}
public void setPage(String page) {
this.page = page;
}
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) this.getJspContext();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
//1.得到来访问者referer
String referer = request.getHeader("referer");
//2.判断来访者的页面是不是要防盗链的网站
if(referer==null || !referer.startsWith(site)){
if(page.startsWith(request.getContextPath())){
response.sendRedirect(page);
}else if(page.startsWith("/")){
response.sendRedirect(request.getContextPath() + page);
}else{
response.sendRedirect(request.getContextPath() + "/" + page);
}
throw new SkipPageException();
}
}
}
TLD文件:
<tag>
<name>referer</name>
<tag-class>cn.sina .web.tag.example.RefererTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>site</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue> //支持EL表达式
</attribute>
<attribute>
<name>page</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="e" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<e:referer site="http://localhost" page="index.jsp"/>
<html>
<head>
<title>My JSP '1.jsp' starting page</title>
</head>
<body>
凤姐xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx凤姐!!!
</body>
</html>
(2)开发<c:if>标签——是否执行标签
Demo样例:
标签处理器类:
public class IfTag extends SimpleTagSupport {
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
if(test){
this.getJspBody().invoke(null);
}
}
}
TLD文件:
<tag>
<name>if</name>
<tag-class>cn.sina .web.tag.example.IfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '2.jsp' starting page</title>
</head>
<body>
<%
session.setAttribute("user","aaa");
%>
<c:if test="${user==null }">
aaaaa
</c:if>
<c:if test="${user!=null }">
bbbbb
</c:if>
</body>
</html>
(3)开发<c:if><c:else>标签——演示父标签操作
Demo样例:
标签处理器类:
//标签<c:choose> 的处理器类
public class ChooseTag extends SimpleTagSupport {
private boolean isDo;
public boolean isDo() { //get
return isDo;
}
public void setDo(boolean isDo) { //set
this.isDo = isDo;
}
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
}
}
//标签<c:when test="${user==null }"> 的处理器类
public class WhenTag extends SimpleTagSupport {
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent = (ChooseTag) this.getParent();
if(test && !parent.isDo()){
this.getJspBody().invoke(null);
parent.setDo(true);
}
}
}
//标签<c:otherwise> 的处理器类
public class OtherWiseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent = (ChooseTag) this.getParent();
if(!parent.isDo()){
this.getJspBody().invoke(null);
parent.setDo(true);
}
}
}
TLD文件:
<tag>
<name>choose</name>
<tag-class>cn.sina .web.tag.example.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>when</name>
<tag-class>cn.sina .web.tag.example.WhenTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>otherwise</name>
<tag-class>cn.sina .web.tag.example.OtherWiseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '3.jsp' starting page</title>
</head>
<body>
<c:choose>
<c:when test="${user==null }">
aaaa
</c:when>
<c:otherwise>
bbbb
</c:otherwise>
</c:choose>
</body>
</html>
(4)开发迭代标签——重复执行标签体
Demo样例:
标签处理器类:
public class ForeachTag2 extends SimpleTagSupport {
private String var;
private Object items;
private Collection collection;
public void setItems(Object items) { //int[]
this.items = items; //int[]
if(items instanceof Collection){ //list set
collection = (Collection) items;
}
if(items instanceof Map){
Map map = (Map) items;
collection = map.entrySet(); //set
}
if(items.getClass().isArray()){
this.collection = new ArrayList();
int length = Array.getLength(items);
for(int i=0;i<length;i++){
Object value = Array.get(items, i);
this.collection.add(value);
}
}
/*
if(items instanceof Object[]){ //int[]
Object obj[] = (Object[]) items;
collection = Arrays.asList(obj);
}
if(items instanceof int[]){
int arr[] = (int[]) items;
this.collection = new ArrayList();
for(int i : arr){
this.collection.add(i);
}
}
*/
}
public void setVar(String var) {
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
Iterator it = this.collection.iterator();
while(it.hasNext()){
Object value = it.next();
this.getJspContext().setAttribute(var, value);
this.getJspBody().invoke(null);
}
}
}
TLD文件:
<tag>
<name>foreach2</name>
<tag-class>cn.sina .web.tag.example.ForeachTag2</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '4.jsp' starting page</title>
</head>
<body>
<%
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("dddd");
request.setAttribute("list",list);
%>
<c:foreach2 var="str" items="${list }">
${str }
</c:foreach2>
<br/>------------------------------------<br/>
<%
Map map = new HashMap();
map.put("aa","111");
map.put("bb","222");
map.put("cc","333");
map.put("dd","444");
request.setAttribute("map",map);
%>
<c:foreach2 var="entry" items="${map}" >
${entry.key } = ${entry.value }
</c:foreach2>
<br/>------------------------------------<br/>
<%
Integer num[] = {1,2,3,4};
request.setAttribute("num",num);
%>
<c:foreach2 var="i" items="${num}" >
${i}
</c:foreach2>
<br/>------------------------------------<br/>
<%
int arr[] = {1,2,3,4};
request.setAttribute("arr",arr);
%>
<c:foreach2 var="i" items="${arr}" >
${i}
</c:foreach2>
<br/>------------------------------------<br/>
<%
boolean b[] = {true,false,true};
request.setAttribute("b",b);
%>
<c:foreach2 var="i" items="${b}" >
${i}
</c:foreach2>
</body>
</html>
(5)开发html转义标签——修改标签体
Demo样例:
标签处理器类:
public class HtmlFilterTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
StringWriter sw = new StringWriter();
JspFragment jf = this.getJspBody();
jf.invoke(sw);
String content = sw.getBuffer().toString(); //<a href="">点点</a>
content = filter(content);
this.getJspContext().getOut().write(content);
}
public String filter(String message) {
if (message == null)
return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(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());
}
}
TLD文件:
<tag>
<name>htmlfilter</name>
<tag-class>cn.sina .web.tag.example.HtmlFilterTag</tag-class>
<body-content>scriptless</body-content>
</tag>
JSP页面调用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/example" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP '6.jsp' starting page</title>
</head>
<body>
<c:htmlfilter>
<a href="">点点</a>
</c:htmlfilter>
</body>
</html>
敬请评论
(1)若您觉得本文较好 —— 请留言评论相告其他 IT童鞋们 本文的有用之处,以坚定他们阅读本文的信心。
(2)若您觉得本文不好 —— 请留言评论相告笔者本文需要改进之处,以便共同为我们大家整理更加好用的笔记。