第六章_编写定制标签

简介:

6.1、定制标签概述

利用jsp标准动作指令访问和操作javaBeans,是首次尝试将表现代码和业务逻辑实现分离。但是,标准动作指令的功能不够强大,单独使用时,开发者经常要使用jsp页面中的Java代码。例如,标准动作指令无法像jstlforEach标签那样迭代集合。

认识到了用javabean分离表现逻辑和业务逻辑的不足之处之后,jsp1.1就定义了定制标签。定制标签具有javaBeans所没有的优势。例如,定制标签可以访问jsp隐式对象,可以带有属性等。

 

6.2、简单的标签处理器

jsp2.0中,他们在javax.servlet.jsp.tagext包中添加了新的接口:simpleTag。实现SimpleTag接口的标签处理器称作简单的标签处理器,实现TagIterationBodyTag接口的标签处理器称作典型的标签处理器。

简单的标签处理器的声明周期更加简单,并且更容易。SimpleTag接口中只有一个方法:doTag,并且在标签调用时只执行一次。业务逻辑、迭代及主体操作代码都要在这里编写。简单的标签处理器中的主体是用一个JspFragment类实例表示的。


一个简单的标签处理器的生命周期如下:

1、jsp容器通过调用其无参构造器,创建一个简单标签处理器实例。因此,简单的标签处理器必须有一个无参构造器。

2、JSP容器调用setJspContext方法,同时传递一个JspContext对象。JspContext最重要的方法是getOut,它返回一个JspWriter,用于将响应发送到客户端。setJspContext方法的签名如下:

Public void setJspContext(JspContext jspContext)

大多数时候,会需要将传进的JspContext赋给一个类变量,以便供后续使用。

3、如果表示标签处理器的定制标签是嵌套在另一个标签中的,jsp容器就会调用setParent方法。该方法具有以下签名:

Public void setParent(JspTag parent)

4、JSP容器为给该标签定义的每个属性都调用设置方法。(setter

5、如果标签中有主体内容,JSP将调用SimpleTag接口的setJspBody方法,将主体内容作为JspFragment传递。如果没有主体内容,JSP容器则不会调用这个方法。

6、JSP容器调用doTag方法。所有变量在doTag方法返回时进行同步。

 

6.3SimpleTag实例

下面是我的测试代码的项目结构。


下面是我的代码:

[html]  view plain  copy
 print ?
  1. package customtag;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.jsp.JspContext;  
  6. import javax.servlet.jsp.JspException;  
  7. import javax.servlet.jsp.tagext.JspFragment;  
  8. import javax.servlet.jsp.tagext.JspTag;  
  9. import javax.servlet.jsp.tagext.SimpleTag;  
  10.   
  11. public class MyFirstTag implements SimpleTag{  
  12.     JspContext jspContext ;  
  13.     public void doTag() throws JspException, IOException {  
  14.         // TODO Auto-generated method stub  
  15.         System.out.println("doTag");  
  16.         jspContext.getOut().print("This is my first tag.") ;  
  17.     }  
  18.   
  19.     public JspTag getParent() {  
  20.         // TODO Auto-generated method stub  
  21.         System.out.println("getParent");  
  22.         return null;  
  23.     }  
  24.   
  25.     public void setJspBody(JspFragment arg0) {  
  26.         // TODO Auto-generated method stub  
  27.         System.out.println("set JspBody");  
  28.     }  
  29.   
  30.     public void setJspContext(JspContext arg0) {  
  31.         // TODO Auto-generated method stub  
  32.         System.out.println("setJspContext");  
  33.         this.jspContext = arg0 ;  
  34.     }  
  35.   
  36.     public void setParent(JspTag arg0) {  
  37.         // TODO Auto-generated method stub  
  38.         System.out.println("set parent");  
  39.     }  
  40.       
  41. }  

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <taglib xmlnx="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/j2eeweb-jsptaglibrary_2_1.xsd"  
  5.     version="2.1">  
  6.     <description>  
  7.         Simple tag examples  
  8.     </description>  
  9.     <tlib-version>1.0</tlib-version>  
  10.     <short-name>My First Taglib Example</short-name>  
  11.     <tag>  
  12.         <name>firstTag</name>  
  13.         <tag-class>customtag.MyFirstTag</tag-class>  
  14.         <body-content>empty</body-content>  
  15.     </tag>  
  16. </taglib>  

[html]  view plain  copy
 print ?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib prefix="easy" uri="/WEB-INF/mytags.tld" %>  
  3. <html>  
  4.   <head>  
  5.     <title>Testing my first tag</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     Hello!!!  
  10.     <br />  
  11.     <easy:firstTag/>  
  12.   </body>  
  13. </html>  

6.4、处理属性

实现SimpleTag接口或者继承SImpleTagSupport的标签处理器可以带有属性。

下面是项目结构图:


下面是程序代码:

[html]  view plain  copy
 print ?
  1. package customtag;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.StringTokenizer;  
  5.   
  6. import javax.servlet.jsp.JspContext;  
  7. import javax.servlet.jsp.JspException;  
  8. import javax.servlet.jsp.JspWriter;  
  9. import javax.servlet.jsp.tagext.SimpleTagSupport;  
  10.   
  11. public class DataFormatterTag extends SimpleTagSupport{  
  12.     private String header ;  
  13.     private String items ;  
  14.       
  15.     public void setHeader(String header) {  
  16.         this.header = header;  
  17.     }  
  18.   
  19.     public void setItems(String items) {  
  20.         this.items = items;  
  21.     }  
  22.   
  23.     @Override  
  24.     public void doTag() throws JspException, IOException {  
  25.         JspContext jspContext = getJspContext() ;  
  26.         JspWriter out = jspContext.getOut() ;  
  27.         out.print("<table style='border:1px solid green'>\n"  
  28.                 +"<tr><td><span style='font-wright:bold'>"  
  29.                 + header + "</span></td></tr>\n") ;  
  30.         StringTokenizer tokenizer = new StringTokenizer(items, ",") ;  
  31.         while(tokenizer.hasMoreTokens()){  
  32.             String token = tokenizer.nextToken() ;  
  33.             out.print("<tr><td>" + token + "</td></tr>\n") ;  
  34.         }  
  35.         out.print("</table>") ;  
  36.     }  
  37.       
  38. }  

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <taglib xmlnx="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/j2eeweb-jsptaglibrary_2_1.xsd"    
  5.     version="2.1">   
  6.     <tlibversion>2.1</tlibversion>  
  7.     <jspversion>2.1</jspversion>  
  8.     <tag>  
  9.         <name>dataFormatter</name>  
  10.         <tag-class>customtag.DataFormatterTag</tag-class>  
  11.         <body-content>empty</body-content>  
  12.         <attribute>  
  13.             <name>header</name>  
  14.             <required>true</required>  
  15.         </attribute>  
  16.         <attribute>  
  17.             <name>items</name>  
  18.             <required>true</required>  
  19.         </attribute>  
  20.     </tag>  
  21. </taglib>   

[html]  view plain  copy
 print ?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="/WEB-INF/mytags.tld" prefix="easy"%>  
  3. <html>  
  4.   <head>  
  5.     <title>Testing DataFormatterTag</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     <easy:dataFormatter items="Alabama,Alaska,Georgia,Florida" header="States"/>  
  10.     <br/>  
  11.     <easy:dataFormatter header="Countries">  
  12.         <jsp:attribute name="items">  
  13.             US,UK,Canada,Korea  
  14.         </jsp:attribute>  
  15.     </easy:dataFormatter>  
  16.   </body>  
  17. </html>  

运行结果图:



6.5、管理标签主体

有了SImpleTag,就可以通过JSP闯过来的JspFragment管理标签主体了。JspFragment类表示一段JSP代码,可以不调用,也可以调用多次。JSP片段的定义中不能包含Scriplet或者Scriptlet表达式,它只能包含模版文本和JSP动作指令元素。

JspFragment类有两个方法:getJspContextinvoke,其方法签名如下:

Public abstract JspContext getJspContext()

Public abstract void invoke(java.io.Writer writer)throws JspException, java.io.IOException

getJspContext方法返回与这个JspFragment相关的JspContext。我们可以调用invoke方法来执行片段(标签主体),并将所有输出内容导到指定的Writer。如果传给invoke方法的值为null,那么输出的结果将会被导到与该片段相关的JspContextgetOut方法所返回的JspWriter

下面是代码段:

[html]  view plain  copy
 print ?
  1. package customtag;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.jsp.JspContext;  
  6. import javax.servlet.jsp.JspException;  
  7. import javax.servlet.jsp.JspWriter;  
  8. import javax.servlet.jsp.tagext.SimpleTagSupport;  
  9.   
  10. public class SelectElementTag extends SimpleTagSupport{  
  11.     private String[] countries = {"Australia", "Brazil", "China"} ;  
  12.     @Override  
  13.     public void doTag() throws JspException, IOException {  
  14.         // TODO Auto-generated method stub  
  15.         JspContext jspContext = getJspContext() ;  
  16.         JspWriter out = jspContext.getOut() ;  
  17.         out.print("<select>\n") ;  
  18.         for(int i=0;i<3; i++){  
  19.             getJspContext().setAttribute("value", countries[i]) ;  
  20.             getJspContext().setAttribute("text", countries[i]) ;  
  21.             getJspBody().invoke(null) ;  
  22.         }  
  23.         out.print("</select>\n") ;  
  24.     }  
  25. }  

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <taglib xmlnx="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/j2eeweb-jsptaglibrary_2_1.xsd"    
  5.     version="2.1">   
  6.     <tlibversion>2.1</tlibversion>  
  7.     <jspversion>2.1</jspversion>  
  8.     <tag>  
  9.         <name>dataFormatter</name>  
  10.         <tag-class>customtag.DataFormatterTag</tag-class>  
  11.         <body-content>empty</body-content>  
  12.         <attribute>  
  13.             <name>header</name>  
  14.             <required>true</required>  
  15.         </attribute>  
  16.         <attribute>  
  17.             <name>items</name>  
  18.             <required>true</required>  
  19.         </attribute>  
  20.     </tag>  
  21.     <tag>  
  22.         <name>select</name>  
  23.         <tag-class>customtag.SelectElementTag</tag-class>  
  24.         <body-content>scriptless</body-content>  
  25.     </tag>  
  26. </taglib>   

[html]  view plain  copy
 print ?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="/WEB-INF/mytags.tld" prefix="easy" %>  
  3. <html>  
  4.   <head>  
  5.     <title>My JSP 'selectElementTagTest.jsp' starting page</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     <easy:select>  
  10.         <option value="${value }">${text }</option>  
  11.     </easy:select>  
  12.   </body>  
  13. </html>  

输出结果显示:



6.6、编写EL函数

一般来说,编写一个EL函数要遵循以下两个步骤:

1、创建一个包含讲台方法的public类。每个静态方法表示一个函数。这个类不需要实现接口或者继承类。你可以根据需要,像对待其他任何类一样部署这个类。这个类必须保存到WEB-INF/classes目录或其下面的某个目录中。

2、利用function元素在标签类库描述符中注册函数。

Function元素必须直接放在taglib元素下,并且可以带有以下子元素:

description。这是一条特定于标签的可选信息。

display-nameXML工具显示的简称。

iconXML工具可以使用的可选图标元素。

name。该函数独特的名称。

function-class。实现该函数的java类的全类名。

function-signature。表示该函数的静态java方法签名。

example。使用该函数的一个example的可选信息描述。

function-extension。通过XML工具使用,没有扩展名,或者有多个扩展名,提供关于该函数的其他信息。

使用函数时,需利用taglib指令及其uri属性,它指向标签类库描述符,以及要使用的前缀。然后在jsp页面中利用以下语法调用函数:

${prefix:functionName(parameterList)}

下面是关于EL函数的例子:

[html]  view plain  copy
 print ?
  1. package function;  
  2.   
  3. public class StringFunctions {  
  4.     public static String reverseString(String s){  
  5.         return new StringBuffer(s).reverse().toString() ;  
  6.     }  
  7. }  

[html]  view plain  copy
 print ?
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@ taglib uri="/WEB-INF/functions.tld" prefix="f" %>  
  3. <html>  
  4.   <head>  
  5.     <title>My JSP 'reverseStringFunctionTest.jsp' starting page</title>  
  6.   </head>  
  7.     
  8.   <body>  
  9.     ${f:reverseString("Hello World")}  
  10.   </body>  
  11. </html>  

[html]  view plain  copy
 print ?
  1. <?xml version="1.0" encoding="utf-8"?>    
  2. <taglib xmlnx="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/j2eeweb-jsptaglibrary_2_1.xsd"    
  5.     version="2.1">   
  6.     <tlibversion>2.1</tlibversion>  
  7.     <jspversion>2.1</jspversion>  
  8.      <function>  
  9.         <description>  
  10.             Reverse a String  
  11.         </description>  
  12.         <name>  
  13.             reverseString  
  14.         </name>  
  15.         <function-class>  
  16.             function.StringFunctions  
  17.         </function-class>  
  18.         <function-signature>  
  19.             java.lang.String reverseString(java.lang.String)  
  20.         </function-signature>  
  21.     </function>  
  22. </taglib>  

在浏览器输入:http://localhost:8089/servlet/reverseStringFunctionTest.jsp



6.7、发布定制标签

我们可以将定制标签处理器和标签类库描述符打包成一个jar文件,以便发给其他人使用,像jstl一样。在这种情况下,就需要包含所有的标签处理器,以及描述它们的tld文件。此外,还需要在描述符的uri元素中指定一个绝对的URL

例如,我就打包成一个cc.jar文件。Jar文件内容如图所示。


可以直接利用cmd的jar命令打包,如图:




这样我们就可以把jar包复制到项目的lib目录下,并且jsp中引用刚才的uri地址。




项目运行截图:

目录
相关文章
|
12月前
|
机器学习/深度学习 编译器 C++
C++模板元模板实战书籍讲解第一章(顺序、分支与循环代码的编写)--续篇
C++模板元模板实战书籍讲解第一章(顺序、分支与循环代码的编写)--续篇
90 0
|
12月前
|
设计模式 JavaScript 前端开发
如何学习JavaScript语法和概念,附上详细的步骤和建议
如何学习JavaScript语法和概念,附上详细的步骤和建议
算法入门几个有用的代码
算法入门几个有用的代码
|
前端开发 测试技术 Python
python接口自动化(二十八)--html测试 报告——下(详解)
上一篇我们批量执行完用例后,已经生成的测试报告是生成 HTML 格式的。但是我们可以看出那个官方的测试报告既不美观也不大方,我们这里需要优化一下,优化的让人赏心悦目,就和看到一个美女一样看了一眼,忍不住回头再多看一眼 - _ - 并且把上一篇遇到的问题列举解决一下。
263 0
python接口自动化(二十八)--html测试 报告——下(详解)
|
移动开发 前端开发 JavaScript
Web前端开发笔记——第二章 HTML语言 第九节 框架标签、脚本标签
Web前端开发笔记——第二章 HTML语言 第九节 框架标签、脚本标签
Web前端开发笔记——第二章 HTML语言 第九节 框架标签、脚本标签
|
JavaScript 前端开发 Java
|
Web App开发 设计模式 IDE
软件测试面试题:Selenium 包含哪些组件,简述各组件的作用?
软件测试面试题:Selenium 包含哪些组件,简述各组件的作用?
135 0
|
测试技术 Python
Python编程:使用doctest进行文档测试
Python编程:使用doctest进行文档测试
105 0
|
Java 测试技术 Go
第八章 测试与性能调优--生成文档和测试示例代码
java也可以生成文档, 就像一个手册一样, 可以用来查看方法, 接口, 下面我们给go项目生成文档
93 0
第八章 测试与性能调优--生成文档和测试示例代码
|
JavaScript 前端开发 算法
每天学习使用代码片段(八)
在项目开发过程中,总觉得有更好的方式来组织代码,通过代码片段,间接的学习一些代码组织技巧。阅读开源代码,是开阔编码思维最快捷的方式,如果觉得内容能够带来点帮助,可以查看专栏《碎片时间学习JavaScript代码》其他内容,又或者有用到的需求片段,不妨在留言区留言。
149 0