一:自定义标签
1、自定义标签主要用于移除 JSP 页面中的 java 代码
2、要使用自定义标签,需要完成以下两个步骤:
a、编写一个实现 Tag 接口的 java 类,把页面 java 代码写在这个 java 类中(标签处理器类)
b、编写标签库描述符(tld)文件,在tld 文件中对标签处理器类描述成一个标签
二:入门
定义一个查看本机IP的标签:
diyTagViewIP.java
package com.haizhu.diyTag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
public class diyTagViewIP extends TagSupport {
public int doStartTag() throws JspException{
/**
* 在 doStartTga 执行之前,TagSupport中的 setPageContext 方法就执行过了(服务器调用执行),所以可以直接使用
*/
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();
}
}
viewIpTag.tld,注意这个文件的位置是在:WEB-INF 目录下
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.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>SimpleTagLibrary</short-name>
<!-- 指定保定这些标签的 URI -->
<uri>http://www.haizhu.cn/viewIP</uri>
<tag>
<!-- 标签属性名称 -->
<name>viewIP</name>
<!-- 对应 的 java 类 -->
<tag-class>com.haizhu.diyTag.diyTagViewIP</tag-class>
<!-- 有没有标签体,这里empty 表示没有,有的话就写 JSP -->
<body-content>empty</body-content>
</tag>
</taglib>
DIYTagDemo.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- 通过 URI 引入自己定义的标签,这里prefix取值是标签的tld文件的名字,这样容易找到对应的文件,好查看源码 -->
<%@taglib uri="http://www.haizhu.cn/viewIP" prefix="viewIpTag"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'ELDemo.jsp' starting page</title>
</head>
<body>
您的IP是:
<%
String ip = request.getRemoteAddr();
out.print(ip);
%>
<br><br>*********************************************************<br><br>
您的IP是:
<!-- 因为没有标签体,所以直接一个标签就可以了 -->
<viewIpTag:viewIP/>
</body>
</html>
三:分析自定义标签的执行流程
1、首先呢,需要明白的一点,运行 JSP 页面页面的时候,其实是运行编译成为 servlet 的程序
2、遇到自定义标签,首先实例化标签对应的标签处理器类
3、调用setPageContext 方法,把页面的pageContext 对象传递给标签处理器类
4、看标签是否有父标签,如果有,则把父标签多为一个对象,调用setParent方法,传递改标签处理器类,没有,传递NULL。
5、标签初始化工作后,标签处理器类开始处理标签,遇到开始标签,调用doStart方法
6、如果标签有标签体,服务器一般执行标签体
7、服务器遇到JSP页面结束标签,调用标签处理器类的 doEnd 方法
8、整个标签执行完毕后,一般情况下调用 release方法,释放标签工作时占用的资源
四:自定义标签功能扩展
1、控制JSP 页面某一部分内容是否执行
只需要在编写的标签类中覆写doStartTag 方法,“return Tag.EVAL_BODY_INCLUDE;”,则显示标签体,“return Tag.SKIP_BODY;”就不显示
2、控制整个JSP 页面是否执行
覆写doEndTag 方法,“return Tag.EVAL_PAGE;”就执行余下的JSP,“return Tag.SKIP_PAGE;”就不执行余下的JSP。
3、控制JSP 页面内容重复执行:IterationTag 接口 ——> TagSupport 实现类
先覆写 doStartTag 方法,返回 Tag.EVAL_BODY_INCLUDE ,之后覆写 doAfterBody 方法,通过返回“return IterationTag.EVAL_BODY_AGAIN”或“return IterationTag.SKIP_BODY”来控制是否再次显示 标签体中的文字
4、修改JSP 页面内容输出:BodyTag 接口 ——> BodyTagSupport 实现类
范例:
package com.haizhu.diyTag;
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 TagDemo extends BodyTagSupport {
// 标签开始执行的时候,执行这个方法
public int doStartTag() throws JspException{
// 表示将标签体封装到 bodyContent 对象中
return BodyTag.EVAL_BODY_BUFFERED;
}
// 标签结束的时候执行这个方法
public int doEndTag(){
// 得到标签体
BodyContent bc = this.getBodyContent();
// 得到标签体内容
String content = bc.getString();
// 将内容转换为大写
content = content.toUpperCase();
try {
// 将内容输出给 JSP 页面
this.pageContext.getOut().write(content);
} catch (IOException e) {
// 抛出运行时异常
throw new RuntimeException(e);
}
// 表示继续执行本页面中这个标签下面的代码
return Tag.EVAL_PAGE;
}
}
5、注意,sun 公司现在为了方便,现在只需要实现SimpleTag 接口,继承 SimpleTagSupport 就可以实现上面的功能了,而不必在使用IterationTag接口和BodyTag接口。
范例:
SimpleTagDemo.java
package com.haizhu.diyTag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTagDemo extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
this.getJspContext().getOut().write("<br><br>**********************************得到标签内容********************************<br>");
// 得到标签体
JspFragment jf = this.getJspBody();
// invoke 表示标签体执行,执行的内容是得到标签体内容输出给浏览器
jf.invoke(this.getJspContext().getOut());
this.getJspContext().getOut().write("<br><br>*********************************循环输出标签内容******************************<br>");
// 如果想多次输出标签体,可以这么做
for(int i=0;i<5;i++){
jf.invoke(this.getJspContext().getOut());
}
this.getJspContext().getOut().write("<br><br>**********************************改变标签内容********************************<br>");
// 初始化一个输出到缓冲区的流
StringWriter sw = new StringWriter();
// invoke 到缓冲区
jf.invoke(sw);
// 取出缓冲区的内容并转化为大写
String content = sw.toString();
content = content.toUpperCase();
// 输出给浏览器
this.getJspContext().getOut().write(content);
this.getJspContext().getOut().write("<br><br>*********************************标签以下的内容*******************************<br>");
// 控制页面标签以下的内容是否输出,更加简单,只要抛出一个异常即可
throw new SkipPageException();
}
}
simpleTagTLD.tld
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.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">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<!-- 指定保定这些标签的 URI -->
<uri>http://www.haizhu.cn/simpleTagDemoTLD</uri>
<tag>
<!-- 标签属性名称 -->
<name>simpleTagName</name>
<!-- 对应 的 java 类 -->
<tag-class>com.haizhu.diyTag.SimpleTagDemo</tag-class>
<!-- 有没有标签体,这里empty 表示没有,而有内容时传统的写法是 JSP ,这里不再是了,而是 scriptless -->
<body-content>scriptless</body-content>
</tag>
</taglib>
simpleTag.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.haizhu.cn/simpleTagDemoTLD" prefix="simpleTag"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>'simpleTag.jsp' 使用范例</title>
</head>
<body>
标签之上的内容。
<simpleTag:simpleTagName>
Hello world !
</simpleTag:simpleTagName>
标签以下的内容。
</body>
</html>
注意:这个标签中写了很多的功能,这些功能每个都可以写成一个标签。
6、带有属性的标签:
要想让一个自定义标签具有属性,通常需要完成两个任务:在标签处理器类中编写每个属性对应的setter方法,并在TLD文件中描述标签的属性。这样的话,JSP引擎在解析执行开始标签前,也就是在调用doStartTag方法前,会调用set 属性方法,为标签设置属性。
标签处理类:TagWithAttrDemo.java
package com.haizhu.attrTag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class TagWithAttrDemo extends SimpleTagSupport {
// 定义属性,并声明setter方法
private int count;
public void setCount(int count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
JspFragment jf = this.getJspBody();
// 直接使用这个接收的参数
for(int i=0;i<count;i++){
jf.invoke(null);
}
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.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">
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<!-- 指定保定这些标签的 URI -->
<uri>http://www.haizhu.cn/simpleTagDemoTLD</uri>
<tag>
<!-- 标签属性名称 -->
<name>tagWithAttr</name>
<!-- 对应 的 java 类 -->
<tag-class>com.haizhu.attrTag.TagWithAttrDemo</tag-class>
<!-- 有没有标签体,这里empty 表示没有,而有内容时传统的写法是 JSP ,这里不再是了,而是 scriptless -->
<body-content>scriptless</body-content>
<!-- 属性 -->
<attribute>
<!-- 名字 -->
<name>count</name>
<!-- 是否必须 -->
<required>true</required>
<!-- 参数赋值类型 -->
<!-- true:可以使用${user.name}的形式赋值,比如 count="${user.age}" -->
<!-- false:只能使用这种方式 count="110" -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
显示页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.haizhu.cn/simpleTagDemoTLD" prefix="simpleTag"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>'simpleTag.jsp' 使用范例</title>
</head>
<body>
<simpleTag:tagWithAttr count="110">
Hello world !
</simpleTag:tagWithAttr>
</body>
</html>