Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30465693
  • 博文数量: 708
  • 博客积分: 12163
  • 博客等级: 上将
  • 技术积分: 8240
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-04 20:59
文章分类

全部博文(708)

分类: Java

2008-12-15 11:04:04

引用
在JSP规范的1.1版中增加了自定义标签库规范,自定义标签库是一种非常优秀的表现层组件技术。通过使用自定义标签库,可以在简单的标签中封装复杂的功能。


....在JSP1.1规范中开发自定义标签库比较复杂,JSP2规范简化了标签库的开发,在JSP2中开发标签库只需如下几个步骤:
  1. 开发自定义标签处理类;
  2. 建立一个*.tld文件,每个*.tld文件对应一个标签库,每个标签库对应多个标签;
  3. 在JSP文件中使用自定义标签。


....提示:标签库是非常重要的技术,通常来说,初学者、普通开发人员自己开发标签库的机会很少,但如果希望成为高级程序员,或者希望开发通用框架,就需要大量开发自定义标签了。所有的MVC框架,如Struts2、SpringMVC、JSF等都提供了丰富的自定义标签。

1 开发自定义标签类
....当我们在JSP页面使用一个简单的标签时,底层实际上由标签处理类提供支持,从而可以使用简单的标签来封装复杂的功能,从而使团队更好地协作开发(能让美工人员更好地参与JSP页面的开发)。
....自定义标签类都必须继承一个父类:javax.servlet.jsp.tagext.SimpleTagSupport除此之外,JSP自定义标签类还有如下要求。
  1. 如果标签类包含属性,每个属性都有对应的getter和setter方法。
  2. 重写doTag()方法,这个方法负责生成页面内容。

........下面开发一个最简单的自定义标签,该标签负责在页面上输出HelloWorld。
Java代码 复制代码
  1. //标签处理类,继承SimpleTagSupport父类   
  2. public class HelloWorldTag extends SimpleTagSupport   
  3. {   
  4. //重写doTag方法,该方法在标签结束生成页面内容   
  5. public void doTag()throws JspException,   
  6.   IOException   
  7. {   
  8.   //获取页面输出流,并输出字符串   
  9.   getJspContext().getOut().write("Hello World");   
  10. }   
  11. }  


........上面这个标签处理类非常简单,它继承了SimpleTagSupport父类,并重写doTag()方法,而doTag()方法则负责输出页面内容。该标签没有属性,因此无须提供setter和getter方法。

2 建立TLD文件
........TLD是Tag Library Definition的缩写,即标签库定义,文件的后缀是tld,每个TLD文件对应一个标签库,一个标签库中可包含多个标签,TLD文件也称为标签库定义文件。
........标签库定义文件的根元素是taglib,它可以包含多个tag子元素,每个tag子元素都定义一个标签。通常我们可以到Web容器下复制一个标签库定义文件,并在此基础上进行修改即可。例如Tomcat6.0,在webapps\examples\WEB-INF\jsp2路径下包含了一个jsp2-example-taglib.tld文件,这就是示范用的标签库定义文件。
........将该文件复制到Web应用的WEB-INF/路径,或WEB-INF的任意子路径下,并对该文件进行简单修改,修改后的mytaglib.tld文件代码如下:
Java代码 复制代码
  1. "1.0" encoding="GBK"?>   
  2. ""  
  3. xmlns:xsi=""  
  4. xsi:schemaLocation=" web-jsptaglibrary_2_0.xsd"  
  5. version="2.0">   
  6. 1.0   
  7. <short-name>mytaglibshort-name>   
  8.   
  9. http://   
  10.   
  11.   
  12.      
  13.   helloWorld   
  14.      
  15.   class>lee.HelloWorldTagclass>   
  16.      
  17.   empty   
  18.   
  19.   

........上面标签库定义文件也是一个标准的XML文件,该XML文件的根元素是taglib元素,因此我们每次编写标签库定义文件都直接添加该元素即可。

taglib下有三个子元素:
  1. tlib-version:指定该标签库实现的版本,这是一个作为标识的内部版本号,对程序没有太大的作用。
  2. short-name:该标签库的默认短名,该名称通常也没有太大的用处。
  3. uri:这个属性非常重要,它指定该标签库的URI,相当于指定该标签库的唯一标识。如上斜体字代码所示,JSP页面中使用标签库时就是根据该URI属性来定位标签库的。

........除此之外,taglib元素下可以包含多个tag元素,每个tag元素定义一个标签,tag元素下至少应包含如下三个子元素:
  1. name:该标签库的名称,这个属性很重要,JSP页面中就是根据该名称来使用此标签的。
  2. tag-class:指定标签的处理类,毋庸置疑,这个属性非常重要,指定了标签由哪个Java类来处理。
  3. body-content:这个属性也很重要,它指定标签体内容。该元素的值可以是如下几个:
    • tagdependent:指定标签处理类自己负责处理标签体。
    • empty:指定该标签只能作用空标签使用。
    • scriptless:指定该标签的标签体可以是静态HTML元素,表达式语言,但不允许出现JSP脚本。
    • JSP:指定该标签的标签体可以使用JSP脚本。
    提示:因为JSP2规范不再推荐使用JSP脚本,所以JSP2自定义标签的标签体中不能包含JSP脚本。所以实际上body-content元素的值不可以是JSP。

........定义了上面的标签库定义文件后,将标签库文件放在Web应用的WEB-INF路径,或任意子路径下,Java Web规范会自动加载该文件,则该文件定义的标签库也将生效。

3 使用标签库
在JSP页面中确定指定标签需要2点:
  1. 标签库URI:确定使用哪个标签库。
  2. 标签名:确定使用哪个标签。

使用标签库分成以下两个步骤:
  1. 导入标签库:使用taglib编译指令导入标签库,就是将标签库和指定前缀关联起来。
  2. 使用标签:在JSP页面中使用自定义标签。

taglib的语法格式如下:
Java代码 复制代码
  1. <%@ taglib uri="tagliburi" prefix="tagPrefix" %>  

其中uri属性确定标签库的URI,这个URI可以确定一个标签库。而prefix属性指定标签库前缀,即所有使用该前缀的标签将由此标签库处理。
使用标签的语法格式如下:
Java代码 复制代码
  1.   
  2.      
  3.   

如果该标签没有标签体,则可以使用如下语法格式:
Java代码 复制代码
  1.   

........上面使用标签的语法里都包含了设置属性值,前面我们介绍的HelloWorldTag标签没有任何属性,所以使用该标签只需用即可。其中mytag是taglib指令为标签库指定的前缀,而helloWorld是标签名。
下面是使用helloWorld标签的JSP页面代码:
Java代码 复制代码
  1. <%@ page contentType="text/html; charset=GBK"%>   
  2.   
  3. <%@ taglib uri="http://" prefix="mytag"%>   
  4.   
  5.   
  6. 自定义标签示范   
  7.   
  8. "#ffffc0">   
  9. 下面显示的是自定义标签中的内容

      
  10.   

  11.   
  12.   
  13.   
上面页面中第一行粗体字代码指定了http://标签库的前缀为mytag,第二行粗体字代码表明使用mytag前缀对应标签库里的helloWorld标签。

4 带属性的标签
前面的简单标签既没有属性,也没有标签体,用法、功能都比较简单。实际上还有如下两种常用的标签:
  • 带属性的标签。
  • 带标签体的标签。

正如前面介绍的,带属性标签必须为每个属性提供对应的setter和getter方法。带属性标签的配置方法与简单标签也略有差别,下面介绍一个带属性标签的示例:
Java代码 复制代码
  1. public class QueryTag extends SimpleTagSupport   
  2. {   
  3. //标签的属性   
  4. private String driver;   
  5. private String url;   
  6. private String user;   
  7. private String pass;   
  8. private String sql;   
  9. //执行数据库访问的对象    
  10. private Connection conn = null;   
  11. private Statement stmt = null;   
  12. private ResultSet rs = null;   
  13. private ResultSetMetaData rsmd = null;   
  14. //标签属性driver的setter方法   
  15. public void setDriver(String driver) {   
  16.   this.driver = driver;    
  17. }   
  18.      //标签属性url的setter方法   
  19. public void setUrl(String url) {   
  20.   this.url = url;    
  21. }   
  22.      //标签属性user的setter方法   
  23. public void setUser(String user) {   
  24.   this.user = user;    
  25. }   
  26.      //标签属性pass的setter方法   
  27. public void setPass(String pass) {   
  28.   this.pass = pass;    
  29. }   
  30.      //标签属性driver的getter方法   
  31. public String getDriver() {   
  32.   return (this.driver);    
  33. }   
  34.      //标签属性url的getter方法   
  35. public String getUrl() {   
  36.   return (this.url);    
  37. }   
  38.      //标签属性user的getter方法   
  39. public String getUser() {   
  40.   return (this.user);    
  41. }   
  42.      //标签属性pass的getter方法   
  43. public String getPass() {   
  44.   return (this.pass);    
  45. }   
  46.      //标签属性sql的getter方法   
  47. public String getSql() {   
  48.   return (this.sql);    
  49. }   
  50.      //标签属性sql的setter方法   
  51. public void setSql(String sql) {   
  52.   this.sql = sql;    
  53. }   
  54. public void doTag()throws JspException,   
  55.   IOException   
  56. {   
  57.         try  
  58.   {   
  59.    //注册驱动   
  60.    Class.forName(driver);   
  61.    //获取数据库连接   
  62.    conn = DriverManager.getConnection(url,user,pass);   
  63.    //创建Statement对象   
  64.    stmt = conn.createStatement();   
  65.    //执行查询   
  66.    rs = stmt.executeQuery(sql);   
  67.    rsmd = rs.getMetaData();   
  68.    //获取列数目   
  69.    int columnCount = rsmd.getColumnCount();   
  70.    //获取页面输出流   
  71.    Writer out = getJspContext().getOut();   
  72.    //在页面输出表格   
  73.    out.write("");   
  74.    //遍历结果集   
  75.    while (rs.next())   
  76.    {   
  77.     out.write("");   
  78.     //逐列输出查询到的数据   
  79.     for (int i = 1 ; i <= columnCount ; i++ )   
  80.     {   
  81.      out.write("");   
  82.      out.write(rs.getString(i));   
  83.      out.write("");   
  84.     }   
  85.     out.write("");   
  86.    }   
  87.   }   
  88.   catch(ClassNotFoundException cnfe)   
  89.   {   
  90.    cnfe.printStackTrace();   
  91.    throw new JspException("自定义标签错误" + cnfe.getMessage());   
  92.   }   
  93.   catch (SQLException ex)   
  94.   {   
  95.    ex.printStackTrace();   
  96.    throw new JspException("自定义标签错误" + ex.getMessage());   
  97.   }   
  98.   finally  
  99.   {   
  100.    //关闭结果集   
  101.    try  
  102.    {   
  103.     if (rs != null)   
  104.      rs.close();   
  105.     if (stmt != null)   
  106.      stmt.close();   
  107.     if (conn != null)   
  108.      conn.close();   
  109.    }   
  110.    catch (SQLException sqle)   
  111.    {   
  112.     sqle.printStackTrace();   
  113.    }   
  114.   }   
  115. }   
  116. }  

........上面页面代码中粗体字代码即可实现通过iterator标签来遍历指定集合。

从iteratorTag.jsp页面的代码来看,使用iterator标签遍历集合元素比使用JSP脚本遍历集合元素要优雅得多,这就是自定义标签的魅力。
提示:实际上JSTL标签库提供了一套功能非常强大标签,例如普通的输出标签,像我们刚刚便携的迭代器标签,还有用于分支判断的标签等等,JSTL都有非常完善的实现。
阅读(2296) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~