一、简单标签(SimpleTag)

  由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。

  

实现SimpleTag接口的标签通常称为简单标签。简单标签共定义了5个方法:

  • setJspContext方法
  • setParent和getParent方法
  • setJspBody方法
  • doTag方法(非常重要),简单标签使用这个方法就可以完成所有的业务逻辑

二、SimpleTag方法介绍

2.1、setJspContext方法

  用于把JSP页面的pageContext对象传递给标签处理器对象

2.2、setParent方法

  用于把父标签处理器对象传递给当前标签处理器对象

2.3、getParent方法

用于获得当前标签的父标签处理器对象

2.4、setJspBody方法

  用于把代表标签体的JspFragment对象传递给标签处理器对象

2.5、doTag方法

  用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。

三、SimpleTag接口方法的执行顺序

  当web容器开始执行标签时,会调用如下方法完成标签的初始化:

  1. WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
  2. WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
  3. 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
  4. 如果简单标签有标签体,WEB容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
  5. 执行标签时WEB容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。

四、开发简单标签实现页面逻辑

  SUN公司针对SimpleTag接口提供了一个默认的实现类SimpleTagSupport,SimpleTagSupport类中实现了SimpleTag接口的所有方法,因此我们可以编写一个类继承SimpleTagSupport类,然后根据业务需要再重写doTag方法。

4.1、控制jsp页面某一部分内容是否执行

 编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面不调用jspFrament.invoke方法即可。

示例代码如下:

SimpleTagDemo1.java

 1 package me.gacl.web.simpletag; 
 2  
 3 import java.io.IOException; 
 4  
 5 import javax.servlet.jsp.JspException; 
 6 import javax.servlet.jsp.PageContext; 
 7 import javax.servlet.jsp.tagext.JspFragment; 
 8 import javax.servlet.jsp.tagext.SimpleTagSupport; 
 9  
10 /** 
11  * @author gacl 
12  * SimpleTagSupport类实现了SimpleTag接口, 
13  * SampleTagDemo1类继承SimpleTagSupport 
14  */ 
15 public class SimpleTagDemo1 extends SimpleTagSupport { 
16  
17     /* 简单标签使用这个方法就可以完成所有的业务逻辑 
18      * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 
19      * 重写doTag方法,控制标签体是否执行 
20      */ 
21     @Override 
22     public void doTag() throws JspException, IOException { 
23         //得到代表jsp标签体的JspFragment 
24         JspFragment jspFragment = this.getJspBody(); 
25          
26         //得到jsp页面的的PageContext对象 
27         //PageContext pageContext = (PageContext) jspFragment.getJspContext(); 
28         //调用JspWriter将标签体的内容输出到浏览器 
29         //jspFragment.invoke(pageContext.getOut()); 
30          
31         //将标签体的内容输出到浏览器 
32         jspFragment.invoke(null); 
33          
34     } 
35 }

  在WEB-INF目录下新建一个simpletag.tld文件,然后在simpletag.tld文件中添加对该标签处理类的描述,如下:

  

  simpletag.tld文件代码如下:

 1 <?xml version="1.0" encoding="UTF-8" ?> 
 2  
 3 <taglib xmlns="http://java.sun.com/xml/ns/j2ee" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 5     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 
 6     version="2.0"> 
 7     <!-- description用来添加对taglib(标签库)的描述 --> 
 8     <description>孤傲苍狼开发的SimpleTag自定义标签库</description> 
 9     <!--taglib(标签库)的版本号 --> 
10     <tlib-version>1.0</tlib-version> 
11     <short-name>GaclSimpleTagLibrary</short-name> 
12     <!--  
13         为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/simpletag , 
14         在Jsp页面中引用标签库时,需要通过uri找到标签库 
15         在Jsp页面中就要这样引入标签库:<%@taglib uri="/simpletag" prefix="gacl"%> 
16     --> 
17     <uri>/simpletag</uri> 
18      
19     <!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述  --> 
20     <!-- 一个tag标记对应一个自定义标签 --> 
21      <tag> 
22         <description>SimpleTag(简单标签)Demo1</description> 
23         <!--  
24             为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的 
25             通过demo1就能找到对应的me.gacl.web.simpletag.SimpleTagDemo1类 
26          --> 
27         <name>demo1</name> 
28         <!-- 标签对应的处理器类--> 
29         <tag-class>me.gacl.web.simpletag.SimpleTagDemo1</tag-class> 
30         <!--  
31         tld文件中有四种标签体类型 :empty  JSP  scriptless  tagdepentend   
32             在简单标签(SampleTag)中标签体body-content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常 
33             在传统标签中标签体body-content的值只允许是empty和JSP 
34             如果标签体body-content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的, 
35             例如:开发一个查询用户的sql标签,此时标签体重的SQL语句就是给SQL标签的标签处理器来使用的 
36             <gacl:sql>SELECT * FROM USER</gacl:sql> 
37             在这种情况下,sql标签的<body-content>就要设置成tagdepentend,tagdepentend用得比较少,了解一下即可 
38         --> 
39         <body-content>scriptless</body-content> 
40     </tag> 
41 </taglib>

  在jsp页面中导入并使用自定义标签,如下:

 1 <%@ page language="java" pageEncoding="UTF-8"%> 
 2 <%--在jsp页面中导入自定义标签库 --%> 
 3 <%@taglib uri="/simpletag" prefix="gacl" %> 
 4 <!DOCTYPE HTML> 
 5 <html> 
 6   <head> 
 7     <title>用简单标签控制标签体是否执行</title> 
 8   </head> 
 9    
10   <body> 
11    
12   <%--在jsp页面中使用自定义标签 demo1标签是带有标签体的,标签体的内容是"孤傲苍狼"这几个字符串--%> 
13     <gacl:demo1> 
14         孤傲苍狼 
15     </gacl:demo1> 
16   </body> 
17 </html>

  运行效果如下:

  

4.2、控制jsp页面内容重复执行

  编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面重复调用jspFrament.invoke方法即可。

示例代码如下:

SimpleTagDemo2.java

 1 package me.gacl.web.simpletag; 
 2  
 3 import java.io.IOException; 
 4  
 5 import javax.servlet.jsp.JspException; 
 6 import javax.servlet.jsp.tagext.JspFragment; 
 7 import javax.servlet.jsp.tagext.SimpleTagSupport; 
 8  
 9 /** 
10  * @author gacl 
11  * SimpleTagSupport类实现了SimpleTag接口, 
12  * SampleTagDemo2类继承SimpleTagSupport 
13  */ 
14 public class SimpleTagDemo2 extends SimpleTagSupport { 
15  
16     /* 简单标签使用这个方法就可以完成所有的业务逻辑 
17      * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 
18      * 重写doTag方法,控制标签执行5次 
19      */ 
20     @Override 
21     public void doTag() throws JspException, IOException { 
22         // 得到代表jsp标签体的JspFragment 
23         JspFragment jspFragment = this.getJspBody(); 
24         for (int i = 0; i < 5; i++) { 
25             // 将标签体的内容输出到浏览器 
26             jspFragment.invoke(null); 
27         } 
28     } 
29 }

  在WEB-INF目录下的simpletag.tld文件中添加对该标签处理类的描述,如下:

1 <tag> 
2         <!-- 标签名 --> 
3         <name>demo2</name> 
4         <!-- 标签处理器类--> 
5         <tag-class>me.gacl.web.simpletag.SimpleTagDemo2</tag-class> 
6         <!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码--> 
7         <body-content>scriptless</body-content> 
8 </tag>

  在jsp页面中导入并使用自定义标签,如下:

 1 <%@ page language="java" pageEncoding="UTF-8"%> 
 2 <%--在jsp页面中导入自定义标签库 --%> 
 3 <%@taglib uri="/simpletag" prefix="gacl" %> 
 4 <!DOCTYPE HTML> 
 5 <html> 
 6   <head> 
 7     <title>用简单标签控制标签体执行5次</title> 
 8   </head> 
 9    
10   <body> 
11    
12   <%--在jsp页面中使用自定义标签 --%> 
13     <gacl:demo2> 
14         孤傲苍狼<p/> 
15     </gacl:demo2> 
16   </body> 
17 </html>

  运行效果如下:

  

4.3、修改jsp页面内容输出

  编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法调用jspFrament.invoke方法时,让执行结果写一个自定义的缓冲中即可,然后开发人员可以取出缓冲的数据修改输出。

示例代码如下:

SimpleTagDemo3.java

 1 package me.gacl.web.simpletag; 
 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 /** 
12  * @author gacl 
13  * SimpleTagSupport类实现了SimpleTag接口, 
14  * SampleTagDemo3类继承SimpleTagSupport 
15  */ 
16 public class SimpleTagDemo3 extends SimpleTagSupport { 
17  
18     /* 简单标签使用这个方法就可以完成所有的业务逻辑 
19      * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 
20      * 重写doTag方法,修改标签体里面的内容,将标签体的内容转换成大写 
21      */ 
22     @Override 
23     public void doTag() throws JspException, IOException { 
24         // 得到代表jsp标签体的JspFragment 
25         JspFragment jspFragment = this.getJspBody(); 
26         StringWriter sw = new StringWriter(); 
27         //将标签体的内容写入到sw流中 
28         jspFragment.invoke(sw); 
29         //获取sw流缓冲区的内容 
30         String content = sw.getBuffer().toString(); 
31         content = content.toUpperCase(); 
32         PageContext pageContext = (PageContext) this.getJspContext(); 
33         //将修改后的content输出到浏览器中 
34         pageContext.getOut().write(content); 
35     } 
36 }

  在WEB-INF目录下的simpletag.tld文件中添加对该标签处理类的描述,如下:

1 <tag> 
2         <!-- 标签名 --> 
3         <name>demo3</name> 
4         <!-- 标签处理器类--> 
5         <tag-class>me.gacl.web.simpletag.SimpleTagDemo3</tag-class> 
6         <!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码--> 
7         <body-content>scriptless</body-content> 
8 </tag>

  在jsp页面中导入并使用自定义标签,如下:

 1 <%@ page language="java" pageEncoding="UTF-8"%> 
 2 <%--在jsp页面中导入自定义标签库 --%> 
 3 <%--<%@taglib uri="/simpletag" prefix="gacl" %>--%> 
 4 <%--在jsp页面中也可以使用这种方式导入标签库,直接把uri设置成标签库的tld文件所在目录 --%> 
 5 <%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%> 
 6 <!DOCTYPE HTML> 
 7 <html> 
 8   <head> 
 9     <title>用简单标签修改jsp页面内容输出</title> 
10   </head> 
11    
12   <body> 
13    
14   <%--在jsp页面中使用自定义标签 --%> 
15     <gacl:demo3> 
16         gacl_xdp 
17     </gacl:demo3> 
18   </body> 
19 </html>

  运行效果如下:

  

4.4、控制整个jsp页面是否执行

  编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法抛出SkipPageException异常即可,jsp收到这个异常,将忽略标签余下jsp页面的执行。

示例代码如下:

SimpleTagDemo4.java

 1 package me.gacl.web.simpletag; 
 2  
 3 import java.io.IOException; 
 4 import javax.servlet.jsp.JspException; 
 5 import javax.servlet.jsp.SkipPageException; 
 6 import javax.servlet.jsp.tagext.SimpleTagSupport; 
 7  
 8 /** 
 9  * @author gacl 
10  * SimpleTagSupport类实现了SimpleTag接口, 
11  * SampleTagDemo4类继承SimpleTagSupport 
12  */ 
13 public class SimpleTagDemo4 extends SimpleTagSupport { 
14  
15     /* 简单标签使用这个方法就可以完成所有的业务逻辑 
16      * @see javax.servlet.jsp.tagext.SimpleTagSupport#doTag() 
17      * 重写doTag方法,控制标签余下的Jsp不执行 
18      */ 
19     @Override 
20     public void doTag() throws JspException, IOException { 
21         //抛出一个SkipPageException异常就可以控制标签余下的Jsp不执行 
22         throw new SkipPageException(); 
23     } 
24 }

  在WEB-INF目录下的simpletag.tld文件中添加对该标签处理类的描述,如下:

1 <tag> 
2         <!-- 标签名 --> 
3         <name>demo4</name> 
4         <!-- 标签处理器类--> 
5         <tag-class>me.gacl.web.simpletag.SimpleTagDemo4</tag-class> 
6         <!-- 标签体允许的内容 ,empty表示该标签没有标签体--> 
7         <body-content>empty</body-content> 
8 </tag>

  在jsp页面中导入并使用自定义标签,如下:

 1 <%@ page language="java" pageEncoding="UTF-8"%> 
 2 <%--在jsp页面中导入自定义标签库 --%> 
 3 <%--<%@taglib uri="/simpletag" prefix="gacl" %>--%> 
 4 <%--在jsp页面中也可以使用这种方式导入标签库,直接把uri设置成标签库的tld文件所在目录 --%> 
 5 <%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%> 
 6 <!DOCTYPE HTML> 
 7 <html> 
 8   <head> 
 9     <title>用简单标签控制标签余下的Jsp不执行</title> 
10   </head> 
11  
12   <body> 
13       <h1>孤傲苍狼</h1> 
14        <%--在jsp页面中使用自定义标签 --%> 
15        <gacl:demo4/> 
16        <!-- 这里的内容位于 <gacl:demo4/>标签后面,因此不会输出到页面上 --> 
17        <h1>白虎神皇</h1> 
18   </body> 
19 </html>

  运行效果如下:

  

五、简单标签开发的一些注意细节

5.1、标签类编写细节

  开发标签类时,不要直接去实现SimpleTag接口,而是应该继承SimpleTagSupport类,SimpleTagSupport类是SimpleTag接口的一个默认实现类,通过继承SimpleTagSupport类,就可以直接使用SimpleTagSupport类已经实现的那些方法,如果SimpleTagSupport类的方法实现不满足业务要求,那么就可以根据具体的业务情况将相应的方法进行重写。

5.2、tld文件中标签体类型设置细节

  我们开发好一个简单标签后,需要在tld文件中添加对该标签的描述,例如:

1 <tag> 
2         <!-- 标签名 --> 
3         <name>demo2</name> 
4         <!-- 标签处理器类--> 
5         <tag-class>me.gacl.web.simpletag.SimpleTagDemo2</tag-class> 
6         <!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码--> 
7         <body-content>scriptless</body-content> 
8 </tag>

  开发好一个标签后,在tld文件中使用<tag>来描述一个标签,描述的内容包括标签名(name),标签处理器类(tag-class),标签体的内容(body-content)。

  tld文件中有四种标签体(body-content)类型 :empty、JSP、scriptless、tagdependent 

简单标签标签体的细节注意问题:
     在简单标签(SampleTag)中标签体body-content的值只允许是empty、scriptless、tagdependent,不允许设置成JSP,如果设置成JSP就会出现异常

1 The TLD for the class me.gacl.web.simpletag.SimpleTagDemo1 specifies an invalid body-content (JSP) for a SimpleTag

  body-content的值如果设置成empty,那么就表示该标签没有标签体,如果是设置成scriptless,那么表示该标签是有标签体的,但是标签体中的内容不可以是<%java代码%>,例如:

1 <gacl:xdpdemo1> 
2    <% 
3            //嵌套在标签体中的java代码 
4         int i= 0; 
5     %> 
6       孤傲苍狼 
7 </gacl:xdpdemo1>

  否则运行标签时就会出现如下错误:

1 Scripting elements ( &lt;%!, &lt;jsp:declaration, &lt;%=, &lt;jsp:expression, &lt;%, &lt;jsp:scriptlet ) are disallowed here

  jsp标签技术出现的目的就是为了移除在jsp页面上编写的java代码的,如果在jsp标签中允许出现java代码,那么就违背了jsp标签技术设计时的初衷了。所以在简单标签的标签体中是不允许出现java代码的。

传统标签标签体的细节注意问题:
     在传统标签中标签体body-content的值允许是empty、JSP、scriptless、tagdependentbody-content的值如果是设置成JSP那么表示该标签是有标签体的,并且标签体的内容可以是任意的,包括java代码,如果是设置成scriptless那么表示该标签是有标签体的,但是标签体的内容不能是java代码
    

  如果传统标签简单标签的标签体body-content的值设置成tagdependent,那么就表示标签体里面的内容是给标签处理器类使用的,tagdependent用得比较少,了解一下即可

5.3、tld文件中标签库的uri设置细节

  如果在一个项目中使用或者开发了多个标签库,例如:

  

  那么标签库的uri不能设置成相同的,否则在Jsp页面中通过uri引用标签库时就不知道引用哪一个标签库了,如果真的有那么巧,两个标签库的uri是刚好一样的,如下图所示:

  

  那么在jsp页面中引用标签库时如果"<%@taglib uri="/gacl" prefix="gacl" %>"这样引用,那么就无法判断当前引用的标签库到底是gacl.tld标签库中的标签还是simpletag.tld标签库中的标签,因为两个标签库的uri刚好都是"/gacl",在两个标签库的引用uri一样的情况下,为了能够在jsp中区别到底引用的是哪个标签库,可以换一种引用方式:<%@taglib uri="要引用的标签库的tld文件目录" prefix="gacl"%>,使用taglib指令引入标签库时,taglib指令的uri属性指定为标签库的tld文件目录,这样就可以区别开了,例如:

  引用gacl.tld标签库:<%@taglib uri="/WEB-INF/gacl.tld" prefix="gacl"%>、

  引用simpletag.tld标签库:<%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%>

  所以当在项目中引用了多个标签库,如果标签库的uri刚好是一样的,就可以用这种方式解决。

六、简单标签开发步骤总结

  1、编写一个类继承SimpleTagSupport类,然后根据业务需要重写SimpleTagSupport类中已经实现了的方法,一般情况下只需要重写doTag()方法即可。

  2、在WEB-INF目录下创建一个tld文件,在tld文件中添加对该标签的描述。tld文件不一定放在WEB-INF目录下,也可以放在别的目录,习惯是放在WEB-INF目录下。

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

javaweb学习总结(二十四)——jsp传统标签开发详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。