我们经常用到的JSTL(JSP标签标准库)是典型的自定义标签的案例。
自定义标签,即是在JSP页面的标签中自定义它们的功能,因为在MVC和三层架构中,JSP页面作为视图(view)是不允许出现Java代码的,一旦迫不得已要写Java代码,我们可以将其用自定义标签移除。
而且主流框架如Struts2等也使用了自己的一套自定义标签,学习自定义标签有利于对框架源码的理解。
自定义标签有两种实现方式:
一是实现Tag或IterationTag接口,或者继承TagSupport类,但是这种方法接口太多不统一,JSP2.0后不再使用,但是主流框架的源码仍然使用这种方式
二是实现SimpleTag接口,或继承SimpleTagSupport类,这个类是sun公司后来重新统一接口设计的实现类。
本文简单介绍两种方式。(资料参考传智播客,在此感谢)
场景是:使标签体的内容输出5次。
方式一:
1.首先编写一个实现Tag接口或者继承TagSupport实现类的Java类(称为标签处理器类):
1 package web.tag; 2 3 import javax.servlet.jsp.JspException; 4 import javax.servlet.jsp.tagext.IterationTag; 5 import javax.servlet.jsp.tagext.Tag; 6 import javax.servlet.jsp.tagext.TagSupport; 7 8 public class Repeat extends TagSupport { 9 private int times = 5; 10 @Override 11 //这个方法调用发生在标签体的开始标签,返回值是一个Tag接口的常量,表示执行标签体(相应的还有不执行标签体,自行查阅API) 12 public int doStartTag() throws JspException { 13 14 return Tag.EVAL_BODY_INCLUDE; 15 } 16 17 @Override 18 //这个方法调用发生在标签体执行一次结束,结束标签之前。返回EVAL_BODY_AGAIN表示再执行一次这个方法;返回SKIP_BODY表示跳过标签体 19 public int doAfterBody() throws JspException { 20 --times;//标签体执行这个方法前会把body执行一遍,所以直接减一次 21 if (times > 0) { 22 return IterationTag.EVAL_BODY_AGAIN; 23 } 24 return IterationTag.SKIP_BODY; 25 } 26 27 28 }
2.在tld文件中对标签处理器类进行描述。tld文件本身是一个xml文档,可以参考Tomcat服务器下webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.tld的写法,写一个自己标签的声明,放到/WEB-INF目录下:
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>simple</short-name> <uri>http://localhost:8080</uri> <!--这里是给tld文件一个标识符,在JSP页面中要引入这个标识符,以便服务器能找到这个tld文件--> <tag> <name>repeat</name> <!--这里应该挺好理解的,最后一个body-content可以写JSP(有)、empty(没有标签体)--> <tag-class>web.tag.Repeat</tag-class> <body-content>JSP</body-content> </tag> </taglib>
3.在jsp页面中导入uri和使用自定义标签
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri = "http://localhost:8080" prefix = "zzqiltw" %> <!--这里写上刚才写的uri,后面的prefix可以任意改--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>使标签体循环5次</title> </head> <body> <zzqiltw:repeat> 这句话会输出五次<br> <!--使用标签--> </zzqiltw:repeat> </body> </html>
方式二:
步骤大同小异,简单说一下:
1.
package web.SimpleTag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class Repeat extends SimpleTagSupport{ @Override //这个方法相当与传统方式的doStartTag、doEndTag等等方法,全部封装到doTag方法里 public void doTag() throws JspException, IOException { JspFragment jf = this.getJspBody(); //这里得到整个标签体封装成的JspFragment对象 for (int i = 0; i < 5; ++i) { jf.invoke(null);//相当于jf.invoke(this.getJspContext().getOut()); 调用invoke方法即可 } } }
2.
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>simple</short-name> <uri>http://localhost:8080/simple</uri> <tag> <name>repeat</name> <tag-class>web.SimpleTag.Repeat</tag-class> <!--scriptless相对于之前的JSP,但是这里sun公司设计成这样,是希望我们不要在jsp里写java代码--> <body-content>scriptless</body-content> </tag> </taglib>
3.
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri = "http://localhost:8080/simple" prefix = "simple" %> 3 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title></title> 8 </head> 9 <body> 10 <simple:repeat> 11 This is my JSP page. <br> 12 </simple:repeat> 13 </body> 14 </html>
======================
简单的入门就到这里结束了。API文档里的Tag接口和SimpleTag接口里还有几个常量和方法,使用方法里面都介绍得很详尽了,可以自己查阅。