自定义标签的功能拓展:
开发人员在编写JSP页面时,经常还需要在页面中引入一些逻辑,例如:
1.控制jsp页面某一部分内容是否执行。
2.控制整个jsp页面是否执行。
3.控制jap页面内容重复执行。
4.修改jsp页面内容输出。
自定义标签除了可以移除jsp页面代码外,它也可以实现以上功能。
上面4句话对应什么意思呢?我们使用实例说明一下(一下使用的是struts和jstl标签做例子):
1.控制jsp页面某一部分内容是否执行。
例如在页面中,我们希望有一些页面代码只有有权限的人才可以看得到,我们就可以使用自定义标签来完成这个操作:
<s:if test="user!=null">
欢迎您!<s:property value="user,name"/>
</s:if>
2.控制整个jsp页面是否执行。
我们可以根据用户是不是有权限,来确定是否将整个页面给用户看
<s:if test="#session.SYS_USER!=null">
<html>
<head></head>
<body>
页面主代码......
</body>
</html>
</s:if>
3.控制jap页面内容重复执行。
比如让一段内容输出5遍:
<c:forEach var="i" begin="1" end="5">
Item <c:out value="${i}"/><p>
</c:forEach>
结果
Item 1
Item 2
Item 3
Item 4
Item 5
4.修改jsp页面内容输出。
可以根据session是否有登录信息,而修改相应的登录信息:
<h2>登录状态:</h2>
<s:if test="#session.SYS_USER!=null">
您已登录!
</s:if><s:else>
您未登录!
</s:else>
我们下面就使用自定义标签来实现这四个功能。
1.使用标签控制页面内容是否输出实例
首先我们要开发“heddin”标签,然后让这个HelloWorld在jsp页面中不显示。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://blog.csdn.net/acmman" prefix="zyg" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用标签控制页面内容是否输出</title>
</head>
<body>
<zyg:heddin>
HelloWorld!
</zyg:heddin>
</body>
</html>
首先说一下Tag接口的doStartTag()方法,它有一个int的返回值,如果想要处理标签体中的数据,就返回int型的“EVAL_BODY_INCLUDE”,如果不想处理,就返回“SKIP_BODY”。
(注意:Tag接口中定义了四个常量,分别是“EVAL_BODY_INCLUDE”、“EVAL_PAGE”、“SKIP_BODY”、“SKIP_PAGE”)
我们接下来为“heddin”标签写一个标签处理器类:
我们重写doStartTag()方法,返回“EVAL_BODY_INCLUDE”参数:
package org.zyg.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
public class HeddinTag extends TagSupport {
@Override
public int doStartTag() throws JspException {
return Tag.EVAL_BODY_INCLUDE;
}
}
然后在zyg.tld中注册这个标签处理器类:
<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/j2ee http://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>zyg</short-name>
<uri>http://blog.csdn.net/acmman</uri><!-- 标签绑定的uri,用于引入 -->
<tag>
<name>viewIP</name><!-- 标签名 -->
<tag-class>org.zyg.web.tag.ViewIPTag</tag-class>
<body-content>empty</body-content><!-- 有无标签体(单标签还是成对标签) -->
</tag>
<tag>
<name>heddin</name><!-- 标签名 -->
<tag-class>org.zyg.web.tag.HeddinTag</tag-class>
<body-content>JSP</body-content><!-- 有无标签体(单标签还是成对标签) -->
</tag>
</taglib>
我们将web重启,然后测试一下:
发现我们是能够看到“HelloWorld”的,然后我们将标签处理库类的返回值换成“SKIP_BODY”:
@Override
public int doStartTag() throws JspException {
return Tag.SKIP_BODY;
}
再重启Web应用,发现已经看不到HelloWorld了。
以上就是使用标签控制页面内容是否输出的实现。
2.控制整个jsp是否输出实例
我们先来了解一下doEndTag()方法,这个方法也有一个返回值,是int类型,这个返回值控制的是“是否显示余下的jsp内容”,其中如果返回值是“EVAL_PAGE”,就执行余下的jsp内容,如果返回值是“SKIP_PAGE”,那么就不再执行余下的jsp代码。
于是我们先编辑一个jsp界面,然后加上我们的自定义标签<zyg:heddinPage/>:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://blog.csdn.net/acmman" prefix="zyg" %>
<zyg:heddinPage/>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>控制整个jsp是否输出</title>
</head>
<body>
这是我们的jsp整个页面
</body>
</html>
然后创建一个自定义标签库类:
重写Tag的doEngTag()方法,给它一个“SKIP_PAGE”的返回值:
package org.zyg.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
public class HeddinPageTag extends TagSupport {
@Override
public int doEndTag() throws JspException {
return Tag.SKIP_PAGE;
}
}
然后在zyg.tld中注册这个标签:
<tag>
<name>heddinPage</name><!-- 标签名 -->
<tag-class>org.zyg.web.tag.HeddinPageTag</tag-class>
<body-content>empty</body-content><!-- 有无标签体(单标签还是成对标签) -->
</tag>
然后重启Web项目,访问该页面:
我们右键点击查看源码,发现源码中也是空空如也:
我们将<zyg:heddinPage/>移到中间:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://blog.csdn.net/acmman" prefix="zyg" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>控制整个jsp是否输出</title>
</head>
<zyg:heddinPage/>
<body>
这是我们的jsp整个页面
</body>
</html>
再次访问页面,我们看到下面的代码是没有的:
说明我们的jsp显示控制是有效的。
想放行的话,就将doEndTag()的返回值置为“EVAL_PAGE”即可,这里不再演示。
3.控制jap页面内容重复执行实例。
我们想让页面中的“哈哈哈,猴赛雷o(^▽^)o”重复执行5次:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://blog.csdn.net/acmman" prefix="zyg" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>控制jsp页面内容重复执行</title>
</head>
<body>
<zyg:repeat>
哈哈哈,猴赛雷o(^▽^)o <br/>
</zyg:repeat>
</body>
</html>
我们来写<zyg:repeat>这个自定义标签。
这个功能仅仅依靠Tag接口是不可能完成的,所以sun公司又对Tag进行了拓展:
想要迭代就需要其中的IterationTag接口,它在Tag的基础上扩充了一个常量EVAL_BODY_AGAIN和一个方法doAfterBody()。
我们使用IterationTag接口的EVAL_BODY_AGAIN常量和doAfterBody()方法既可以控制jsp页面中内容的重复。
doAfterBody()方法是在“标签体执行”动作之后,以及“结束标签”动作之前执行。如果这个方法返回“EVAL_BODY_AGAIN”常量,这个时候就会再把标签体执行一次,然后继续递归执行doAfterBody()方法。以此类推,只要这个方法返回“EVAL_BODY_AGAIN”常量它都会循环执行标签体内容,直到doAfterBody()方法返回“SKIP_BODY”常量之后才结束循环。
我们下面开始开发这个标签类,因为TagSupport类同时也实现了IterationTag接口,所以我们还是继承TagSupport类:
我们在类中重写doStartTag()方法和doAfterBody()方法:
package org.zyg.web.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
//控制标签体执行5次
public class RepeatTag 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;
}
}
}
首先让doStartTag()方法返回EVAL_BODY_INCLUDE变量放行,然后在doAfterBody()方法中执行循环操作。
然后我们在zyg.tld中注册这个标签:
<tag>
<name>repeat</name><!-- 标签名 -->
<tag-class>org.zyg.web.tag.RepeatTag</tag-class>
<body-content>JSP</body-content><!-- 有无标签体(单标签还是成对标签) -->
</tag>
然后重新发布一下Web工程,访问页面之后显示:
这就是用自定义标签控制jap页面内容重复执行。
4.用标签修改jsp页面内容实例
开发新的标签将下面的小写字母变为大写:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib uri="http://blog.csdn.net/acmman" prefix="zyg" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>修改jsp页面内容</title>
</head>
<body>
<zyg:upper>
abcdefg
</zyg:upper>
</body>
</html>
这个时候我们需要BodyTag接口(它实现了Tag和IterTag接口),它是专门管理jsp修改功能的,多了两个量“EVAL_BODY_BUFFERED”和“EVAL_BODY_TAG(过时的)”,和两个方法setBodyContent()和doInitBody()。
首先让doStartTag()方法返回“EVAL_BODY_BUFFERED”,服务器拿到标签体之后,会将标签体使用setBodyContent()方法传给标签处理器类。我们就可以在doEndTag()方法中拿到标签中的内容,修改之后再输出。
我们先来创建这个标签类:
重写doStartTag()方法和doEndTag()方法:
package org.zyg.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;
//修改标签体(把标签体改为大写)
public class UpperTag extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
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;
}
}
然后在zyg.tld文件中注册一下这个标签:
<tag>
<name>upper</name><!-- 标签名 -->
<tag-class>org.zyg.web.tag.UpperTag</tag-class>
<body-content>JSP</body-content><!-- 有无标签体(单标签还是成对标签) -->
</tag>
然后我们重启一下Web应用,测试:
我们的小写英文变成了大写。
我们讲解完了自定义标签的内容,但是,回顾一下这张图:
我们所讲述的是左边的技术,它其实是jsp2.0以前的技术,后来sun公司觉得Tag的学习成本比较高,不利于标签开发技术的推广,于是在jsp2.0的时候他们又定义了SimpleTag接口,单单使用这一个接口,就可以完成左边3个接口完成的事情。
我们现在公司使用的很多框架还是jsp2.0之前的技术,所以我们学习老技术还是很有必要的,这样就会理解老标签的源码。
jsp2.0以前的标签叫“传统标签”,以后的叫“简单标签”
下一次我们就讲解新的“简单标签”。