1.定制标签的实现类称为标签处理器,简单标签处理器指实现SimpleTag接口的类,如下图的SimpleTagSupport类,该类为SimpleTag接口的默认实现类。
注:不要直接实现SimpleTag接口,应该继承SimpleTagSupport类,可以直接使用该类已经实现的方法,若该类方法不能满足业务需求,可重写相应方法。
.
2.SimpleTag接口定义了5个方法:
- setJspContext方法
- setParent和getParent方法
- setJspBody方法
- doTag方法(非常重要),简单标签使用这个方法就可以完成所有的业务逻辑
2.1 setJspContext方法:
用于把JSP页面的pageContext对象传递给标签处理器对象,若重写该方法,必须把PageContext赋于成员变量jspContext
2.2 setParent方法:
用于把父标签处理器对象传递给当前标签处理器对象
2.3 getParent方法:
用于获得当前标签的父标签处理器对象
2.4 setJspBody方法:
用于把代表标签体的JspFragment对象传递给标签处理器对象,若重写了该方法,必须赋于成员变量jspFragment
2.5 doTag方法:
用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。
3. SimpleTag接口方法的执行顺序
当web容器开始执行标签时,会调用如下方法完成标签的初始化:
- WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
- WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
- 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
- 如果简单标签有标签体,WEB容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
- 执行标签时WEB容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。
4.JspFragment类介绍
4.1全称javax.servlet.jsp.tagext.JspFragment,WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。
4.2 JspFragment类中只定义了两个方法:
4.2.1 getJspContext方法:public abstract void invoke(java.io.Writer out) ;//用于返回代表调用页面的JspContext对象。
4.2.2 invoke方法:public abstract void invoke(java.io.Writer out);
/*用于执行JspFragment对象所代表的JSP代码片段,参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果 传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器);
该方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。*/
5. 标签属性描述:
6.开发简单标签实现页面逻辑
6.1 标签处理器类:
1 package com.webtest.tag; 2 3 import java.io.IOException; 4 import java.io.StringWriter; 5 6 import javax.servlet.jsp.JspException; 7 import javax.servlet.jsp.PageContext; 8 import javax.servlet.jsp.tagext.JspFragment; 9 import javax.servlet.jsp.tagext.SimpleTagSupport; 10 11 public class TestTag extends SimpleTagSupport { 12 //private JspContext jspContext; 13 //private JspFragment jspFragment; 14 private int count;//定义标签属性 15 16 public void setCount(int count){ 17 this.count=count; 18 } 19 @Override 20 public void doTag() throws JspException, IOException { 21 // TODO Auto-generated method stub 22 23 //获取PageContext对象,若重写了setJspContext方法,必须把PageContext赋于成员变量jspContext 24 PageContext pageContext = (PageContext) this.getJspContext(); 25 26 pageContext.getOut().print("这里是10086<br>"); 27 28 29 //得到代表jsp标签体的JspFragment,若这个类重写了setJspBody方法,必须赋于成员变量jspFragment,所以不需要调用getJspBody方法 30 JspFragment jspFragment=this.getJspBody(); 31 32 //将标签体的内容输出到浏览器 33 jspFragment.invoke(null); 34 pageContext.getOut().print("<br>"); 35 36 /* 37 * 或者把标签条输入缓冲流中,然后对数据进行修改 38 */ 39 StringWriter sw=new StringWriter(); 40 jspFragment.invoke(sw); 41 String str=sw.getBuffer().toString(); 42 str="####"+str+"####"; 43 44 45 pageContext.getOut().print(str+"<br>"); 46 47 //使用标签属性 48 for(int i=0;i<count;i++){ 49 jspFragment.invoke(null); 50 } 51 //得到jsp页面的的PageContext对象 52 //PageContext pageContext = (PageContext) jspFragment.getJspContext(); 53 //调用JspWriter将标签体的内容输出到浏览器 54 //jspFragment.invoke(pageContext.getOut()); 55 System.out.println("doTag方法"); 56 57 } 58 59 /* public JspTag getParent() { 60 // TODO Auto-generated method stub 61 System.out.println("getParent方法"); 62 return null; 63 }*/ 64 65 /** 66 * 当重写setJspBody方法时,需要把传如的JspFragment对象赋值给一个类变量,以供使用 67 */ 68 /* 69 public void setJspBody(JspFragment jspBody) { 70 // TODO Auto-generated method stub 71 jspFragment=jspBody; 72 System.out.println("setJspBody方法"); 73 } 74 75 public void setJspContext(JspContext pc) { 76 // TODO Auto-generated method stub 77 System.out.println("setJspContext方法"); 78 jspContext=pc; 79 } 80 81 public void setParent(JspTag parent) { 82 // TODO Auto-generated method stub 83 System.out.println("setParent方法"); 84 }*/ 85 86 }
6.2 标签描述文件,是xml文件,以tld为后缀名,一般放在WEB-INF目录下,也可以置于其他目录:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <taglib xmlns="http://java.sun.com/xml/ns/j2ee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 5 version="2.0"> 6 <!-- 用于对自定义标签库的描述 --> 7 <description>自定义标签库</description> 8 <!-- 标签库的 版本号 --> 9 <tlib-version>1.0</tlib-version> 10 <short-name>GaclSimpleTagLibrary</short-name> 11 <!-- 12 为自定义标签库设置uri,以 / 开头,/之后的内容随意,如这里的/simpletag,但应该把其设置成与文件名相同,以便知道引用哪个标签库 13 在jsp页面使用自定义标签时,需要先引入标签库,其通过uri找到标签库, 14 jsp页面引入标签库:<%@taglib uri="/simpletag" prefix="gacl" %> 15 其中的prefix属性用于使用自定义标签时的前缀,如同EL中的c,如:<gacl:tagtest/> 16 --> 17 <uri>/mytags</uri> 18 <!-- 一个taglib(标签库)可以包含多个自定义标签,每个自定义标签使用一个tag来描述 --> 19 <tag> 20 <!-- 描述 --> 21 <description>SimpleTag(简单标签)tagtest</description> 22 <!-- 标签名,为标签处理器类配一个标签名,使其在jsp页面可以通过标签名找到 --> 23 <name>tagtest</name> 24 <!-- 标签对应的标签处理器类 --> 25 <tag-class>com.webtest.tag.TestTag</tag-class> 26 <!-- 27 tld文件中有四种标签体类型 :empty JSP scriptless tagdepentend 28 在简单标签(SampleTag)中标签体body-content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常 29 在传统标签中标签体body-content的值只允许是empty和JSP 30 如果标签体body-content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的, 31 例如:开发一个查询用户的sql标签,此时标签体重的SQL语句就是给SQL标签的标签处理器来使用的 32 <gacl:sql>SELECT * FROM USER</gacl:sql> 33 在这种情况下,sql标签的<body-content>就要设置成tagdepentend,tagdepentend用得比较少,了解一下即可 34 --> 35 <body-content>scriptless</body-content> 36 <!-- 标签属性描述 --> 37 <attribute> 38 <description>描述标签的count属性</description> 39 <name>count</name> 40 <!-- 用于表示此属性是否必须设置,默认为false,即可以不设置该属性的值 --> 41 <required>true</required> 42 <!-- rtexprvalue用于指示标签属性值是否可以是一个表达式,一般设置为true,表示可以是表达式 --> 43 <rtexprvalue>true</rtexprvalue> 44 </attribute> 45 </tag> 46 </taglib>
6.3 jsp文件:
1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 2 3 <%--导入自定义标签库 --%> 4 <%@taglib uri="/mytags" prefix="gacl" %> 5 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 7 <html> 8 <head> 9 <title>My JSP 'index.jsp' starting page</title> 10 <meta http-equiv="pragma" content="no-cache"> 11 <meta http-equiv="cache-control" content="no-cache"> 12 <meta http-equiv="expires" content="0"> 13 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 14 <meta http-equiv="description" content="This is my page"> 15 <!-- 16 <link rel="stylesheet" type="text/css" href="styles.css"> 17 --> 18 </head> 19 20 <body> 21 <gacl:tagtest count="5">我是自定义标签<p></gacl:tagtest> 22 23 </body> 24 </html>