JSP2的自定義標籤

引用
在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父類
public class HelloWorldTag extends SimpleTagSupport
{
//重寫doTag方法,該方法在標籤結束生成頁面內容
public void doTag()throws JspException,
  IOException
{
  //獲取頁面輸出流,並輸出字符串
  getJspContext().getOut().write("Hello World");
}
}



........上面這個標籤處理類非常簡單,它繼承了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. <?xml version="1.0" encoding="GBK"?>   
  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 web-jsptaglibrary_2_0.xsd"  
  5. version="2.0">   
  6. <tlib-version>1.0</tlib-version>   
  7. <short-name>mytaglib</short-name>   
  8. <!-- 定義該標籤庫的URI -->   
  9. <uri>http://www.leegang.org/mytaglib&lt;/uri>   
  10. <!-- 定義第一個標籤 -->   
  11. <tag>   
  12.   <!-- 定義標籤名 -->   
  13.   <name>helloWorld</name>   
  14.   <!-- 定義標籤處理類 -->   
  15.   <tag-class>lee.HelloWorldTag</tag-class>   
  16.   <!-- 定義標籤體爲空 -->   
  17.   <body-content>empty</body-content>   
  18. </tag>   
  19. </taglib>  
<?xml version="1.0" encoding="GBK"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>mytaglib</short-name>
<!-- 定義該標籤庫的URI -->
<uri>http://www.leegang.org/mytaglib&lt;/uri>
<!-- 定義第一個標籤 -->
<tag>
  <!-- 定義標籤名 -->
  <name>helloWorld</name>
  <!-- 定義標籤處理類 -->
  <tag-class>lee.HelloWorldTag</tag-class>
  <!-- 定義標籤體爲空 -->
  <body-content>empty</body-content>
</tag>
</taglib>


........上面標籤庫定義文件也是一個標準的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" %>  
<%@ taglib uri="tagliburi" prefix="tagPrefix" %>


其中uri屬性確定標籤庫的URI,這個URI可以確定一個標籤庫。而prefix屬性指定標籤庫前綴,即所有使用該前綴的標籤將由此標籤庫處理。
使用標籤的語法格式如下:

Java代碼 複製代碼
  1. <tagPrefix:tagName tagAttribute=”tagValue” …>   
  2.   <tagBody/>   
  3. </tagPrefix:tagName>  
<tagPrefix:tagName tagAttribute=”tagValue” …>
  <tagBody/>
</tagPrefix:tagName>


如果該標籤沒有標籤體,則可以使用如下語法格式:

Java代碼 複製代碼
  1. <tagPrefix:tagName tagAttribute=”tagValue” …/>  
<tagPrefix:tagName tagAttribute=”tagValue” …/>


........上面使用標籤的語法裏都包含了設置屬性值,前面我們介紹的HelloWorldTag標籤沒有任何屬性,所以使用該標籤只需用<mytag:helloWorld/>即可。其中mytag是taglib指令爲標籤庫指定的前綴,而helloWorld是標籤名。
下面是使用helloWorld標籤的JSP頁面代碼:

Java代碼 複製代碼
  1. <%@ page contentType="text/html; charset=GBK"%>   
  2. <!-- 導入標籤庫,指定mytag前綴的標籤,   
  3. 由http://www.leegang.org/mytaglib的標籤庫處理 -->   
  4. <%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>   
  5. <html>   
  6. <head>   
  7. <title>自定義標籤示範</title>   
  8. </head>   
  9. <body bgcolor="#ffffc0">   
  10. <h2>下面顯示的是自定義標籤中的內容</h2>   
  11. <!-- 使用標籤 ,其中mytag是標籤前綴,根據taglib的編譯指令,   
  12. mytag前綴將由http://www.leegang.org/mytaglib的標籤庫處理 -->   
  13. <mytag:helloWorld/>  
  14.   
  15. </body>   
  16. </html>  
<%@ page contentType="text/html; charset=GBK"%>
<!-- 導入標籤庫,指定mytag前綴的標籤,
由http://www.leegang.org/mytaglib的標籤庫處理 -->
<%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>
<html>
<head>
<title>自定義標籤示範</title>
</head>
<body bgcolor="#ffffc0">
<h2>下面顯示的是自定義標籤中的內容</h2>
<!-- 使用標籤 ,其中mytag是標籤前綴,根據taglib的編譯指令,
mytag前綴將由http://www.leegang.org/mytaglib的標籤庫處理 -->
<mytag:helloWorld/><BR>
</body>
</html>

上面頁面中第一行粗體字代碼指定了http://www.leegang.org/mytaglib標籤庫的前綴爲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("<table border='1' bgColor='9999cc' width='400'>");   
  74.    //遍歷結果集   
  75.    while (rs.next())   
  76.    {   
  77.     out.write("<tr>");   
  78.     //逐列輸出查詢到的數據   
  79.     for (int i = 1 ; i <= columnCount ; i++ )   
  80.     {   
  81.      out.write("<td>");   
  82.      out.write(rs.getString(i));   
  83.      out.write("</td>");   
  84.     }   
  85.     out.write("</tr>");   
  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. }  
public class QueryTag extends SimpleTagSupport
{
//標籤的屬性
private String driver;
private String url;
private String user;
private String pass;
private String sql;
//執行數據庫訪問的對象 
private Connection conn = null;
private Statement stmt = null;
private ResultSet rs = null;
private ResultSetMetaData rsmd = null;
//標籤屬性driver的setter方法
public void setDriver(String driver) {
  this.driver = driver; 
}
     //標籤屬性url的setter方法
public void setUrl(String url) {
  this.url = url; 
}
     //標籤屬性user的setter方法
public void setUser(String user) {
  this.user = user; 
}
     //標籤屬性pass的setter方法
public void setPass(String pass) {
  this.pass = pass; 
}
     //標籤屬性driver的getter方法
public String getDriver() {
  return (this.driver); 
}
     //標籤屬性url的getter方法
public String getUrl() {
  return (this.url); 
}
     //標籤屬性user的getter方法
public String getUser() {
  return (this.user); 
}
     //標籤屬性pass的getter方法
public String getPass() {
  return (this.pass); 
}
     //標籤屬性sql的getter方法
public String getSql() {
  return (this.sql); 
}
     //標籤屬性sql的setter方法
public void setSql(String sql) {
  this.sql = sql; 
}
public void doTag()throws JspException,
  IOException
{
        try
  {
   //註冊驅動
   Class.forName(driver);
   //獲取數據庫連接
   conn = DriverManager.getConnection(url,user,pass);
   //創建Statement對象
   stmt = conn.createStatement();
   //執行查詢
   rs = stmt.executeQuery(sql);
   rsmd = rs.getMetaData();
   //獲取列數目
   int columnCount = rsmd.getColumnCount();
   //獲取頁面輸出流
   Writer out = getJspContext().getOut();
   //在頁面輸出表格
   out.write("<table border='1' bgColor='9999cc' width='400'>");
   //遍歷結果集
   while (rs.next())
   {
    out.write("<tr>");
    //逐列輸出查詢到的數據
    for (int i = 1 ; i <= columnCount ; i++ )
    {
     out.write("<td>");
     out.write(rs.getString(i));
     out.write("</td>");
    }
    out.write("</tr>");
   }
  }
  catch(ClassNotFoundException cnfe)
  {
   cnfe.printStackTrace();
   throw new JspException("自定義標籤錯誤" + cnfe.getMessage());
  }
  catch (SQLException ex)
  {
   ex.printStackTrace();
   throw new JspException("自定義標籤錯誤" + ex.getMessage());
  }
  finally
  {
   //關閉結果集
   try
   {
    if (rs != null)
     rs.close();
    if (stmt != null)
     stmt.close();
    if (conn != null)
     conn.close();
   }
   catch (SQLException sqle)
   {
    sqle.printStackTrace();
   }
  }
}
}


上面這個標籤稍微複雜一點,它包含了5個屬性,如程序中粗體字代碼所示,則程序需要爲這5個屬性提供setter和getter方法。
該標籤輸出的內容依然由doTag()方法決定,該方法會根據SQL語句查詢數據庫,並將查詢結果顯示在當前頁面中。
對於有屬性的標籤,需要爲tag元素增加attribute子元素,每個attribute子元素定義一個屬性,attribue子元素通常還需要指定如下幾個子元素:

  1. name:設置屬性名,子元素的值是字符串內容。
  2. required:設置該屬性是否爲不需屬性,該子元素的值是true或false。
  3. fragment:設置該屬性是否支持JSP腳本、表達式等動態內容,子元素的值是true或false。



爲了配置上面的QueryTag標籤,我們需要在mytaglib.tld文件中增加如下配置片段:

Java代碼 複製代碼
  1. <!-- 定義第二個標籤 -->   
  2. <tag>   
  3. <!-- 定義標籤名 -->   
  4. <name>query</name>   
  5. <!-- 定義標籤處理類 -->   
  6. <tag-class>lee.QueryTag</tag-class>   
  7. <!-- 定義標籤體爲空 -->   
  8. <body-content>empty</body-content>   
  9. <!-- 配置標籤屬性:driver -->   
  10. <attribute>   
  11.   <name>driver</name>    
  12.   <required>true</required>   
  13.   <fragment>true</fragment>   
  14. </attribute>   
  15. <!-- 配置標籤屬性:url -->   
  16. <attribute>   
  17.   <name>url</name>    
  18.   <required>true</required>   
  19.   <fragment>true</fragment>   
  20. </attribute>   
  21. <!-- 配置標籤屬性:user -->   
  22. <attribute>   
  23.   <name>user</name>    
  24.   <required>true</required>   
  25.   <fragment>true</fragment>   
  26. </attribute>   
  27. <!-- 配置標籤屬性:pass -->   
  28. <attribute>   
  29.   <name>pass</name>    
  30.   <required>true</required>   
  31.   <fragment>true</fragment>   
  32. </attribute>   
  33. <!-- 配置標籤屬性:sql -->   
  34. <attribute>   
  35.   <name>sql</name>    
  36.   <required>true</required>   
  37.   <fragment>true</fragment>   
  38. </attribute>   
  39. </tag>  
<!-- 定義第二個標籤 -->
<tag>
<!-- 定義標籤名 -->
<name>query</name>
<!-- 定義標籤處理類 -->
<tag-class>lee.QueryTag</tag-class>
<!-- 定義標籤體爲空 -->
<body-content>empty</body-content>
<!-- 配置標籤屬性:driver -->
<attribute>
  <name>driver</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
<!-- 配置標籤屬性:url -->
<attribute>
  <name>url</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
<!-- 配置標籤屬性:user -->
<attribute>
  <name>user</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
<!-- 配置標籤屬性:pass -->
<attribute>
  <name>pass</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
<!-- 配置標籤屬性:sql -->
<attribute>
  <name>sql</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
</tag>


上面5行粗體字代碼分別爲該標籤配置了driver、url、user、pass和sql等5個屬性,並指定這5個屬性都不需屬性、而且屬性值支持動態內容。
配置完畢後,就可在頁面中使用標籤,先導入標籤庫,然後使用標籤。使用標籤的JSP頁面片段如下:

Java代碼 複製代碼
  1. <!-- 導入標籤庫,指定mytag前綴的標籤,   
  2. 由http://www.leegang.org/mytaglib的標籤庫處理 -->   
  3. <%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>   
  4. ...   
  5. <!-- 其他HTML內容 -->   
  6. <!-- 使用標籤 ,其中mytag是標籤前綴,根據taglib的編譯指令,   
  7. mytag前綴將由http://www.leegang.org/mytaglib的標籤庫處理 -->   
  8. <mytag:query   
  9. driver="com.mysql.jdbc.Driver"  
  10. url="jdbc:mysql://localhost:3306/javaee"  
  11. user="root"  
  12. pass="32147"  
  13. sql="select * from newsinf"/>  
<!-- 導入標籤庫,指定mytag前綴的標籤,
由http://www.leegang.org/mytaglib的標籤庫處理 -->
<%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>
...
<!-- 其他HTML內容 -->
<!-- 使用標籤 ,其中mytag是標籤前綴,根據taglib的編譯指令,
mytag前綴將由http://www.leegang.org/mytaglib的標籤庫處理 -->
<mytag:query
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/javaee"
user="root"
pass="32147"
sql="select * from newsinf"/>


........在JSP頁面中只需要使用簡單的標籤,即可完成“複雜”的功能:執行數據庫查詢,並將查詢結果在頁面上以表格形式顯示。這也正是自定義標籤庫的目的——以簡單的標籤,隱藏複雜的邏輯。
........當然,並不推薦在標籤處理類中訪問數據庫,因爲標籤庫是表現層組件,它不應該包含任何業務邏輯實現代碼,更不應該執行數據庫訪問,它只應該負責顯示邏輯。
注意:JSTL是Sun提供的一套標籤庫,這套標籤庫的功能非常強大。另外,DisplayTag是Apache組織下的一套開源標籤庫,主要用於生成頁面並顯示效果。
5 帶標籤體的標籤
........帶標籤體的標籤,可以在標籤內嵌入其他內容(包括靜態的HTML內容和動態的JSP內容),通常用於完成一些邏輯運算,例如判斷和循環等。下面以一個迭代器標籤爲示例,介紹帶標籤體標籤的開發過程。
........一樣先定義一個標籤處理類,該標籤處理類的代碼如下:

Java代碼 複製代碼
  1. public class IteratorTag extends SimpleTagSupport   
  2. {   
  3. //標籤屬性,用於指定需要被迭代的集合   
  4. private String collection;   
  5. //標籤屬性,指定迭代集合元素,爲集合元素指定的名稱   
  6. private String item;   
  7. //collection屬性的setter和getter方法   
  8. public void setCollection(String collection)   
  9. {   
  10.   this.collection = collection;   
  11. }   
  12. public String getCollection()   
  13. {   
  14.   return this.collection;   
  15. }   
  16. //item屬性的setter和getter方法   
  17. public void setItem(String item)   
  18. {   
  19.   this.item = item;   
  20. }   
  21. public String getItem()   
  22. {   
  23.   return this.item;   
  24. }   
  25. //標籤的處理方法,簡單標籤處理類只需要重寫doTag方法   
  26. public void doTag() throws JspException, IOException   
  27. {   
  28.   //從page scope中獲取屬性名爲collection的集合   
  29.   Collection itemList = (Collection)getJspContext().   
  30.    getAttribute(collection);   
  31.   //遍歷集合   
  32.   for (Object s : itemList)   
  33.   {   
  34.    //將集合的元素設置到page 範圍   
  35.    getJspContext().setAttribute(item, s );   
  36.    //輸出標籤體   
  37.    getJspBody().invoke(null);   
  38.   }   
  39. }   
  40. }  
public class IteratorTag extends SimpleTagSupport
{
//標籤屬性,用於指定需要被迭代的集合
private String collection;
//標籤屬性,指定迭代集合元素,爲集合元素指定的名稱
private String item;
//collection屬性的setter和getter方法
public void setCollection(String collection)
{
  this.collection = collection;
}
public String getCollection()
{
  return this.collection;
}
//item屬性的setter和getter方法
public void setItem(String item)
{
  this.item = item;
}
public String getItem()
{
  return this.item;
}
//標籤的處理方法,簡單標籤處理類只需要重寫doTag方法
public void doTag() throws JspException, IOException
{
  //從page scope中獲取屬性名爲collection的集合
  Collection itemList = (Collection)getJspContext().
   getAttribute(collection);
  //遍歷集合
  for (Object s : itemList)
  {
   //將集合的元素設置到page 範圍
   getJspContext().setAttribute(item, s );
   //輸出標籤體
   getJspBody().invoke(null);
  }
}
}


........上面標籤處理類與前面處理類並沒有太大的不同,該處理類包含2個屬性,併爲這兩個屬性提供了setter和getter方法。標籤處理類的doTag方法首先從page範圍內獲取了指定名稱的Collection對象,然後遍歷Collection對象的元素,每次遍歷都調用了getJspBody()方法,如程序中粗體字代碼所示,該方法返回該標籤所包含的標籤體:JspFragment對象,執行該對象的invoke()方法,即可輸出標籤體內容。該標籤的作用是:遍歷指定集合,每遍歷一個集合元素,即輸出標籤體一次。
........因爲該標籤的標籤體不爲空,配置該標籤時指定body-content爲scriptless,該標籤的配置代碼片段如下代碼所示:

Java代碼 複製代碼
  1. <!-- 定義第三個標籤 -->   
  2. <tag>   
  3. <!-- 定義標籤名 -->   
  4. <name>iterator</name>   
  5. <!-- 定義標籤處理類 -->   
  6. <tag-class>lee.IteratorTag</tag-class>   
  7. <!-- 定義標籤體支持JSP腳本 -->   
  8. <body-content>scriptless</body-content>   
  9. <!-- 配置標籤屬性:collection -->   
  10. <attribute>   
  11.   <name>collection</name>    
  12.   <required>true</required>   
  13.   <fragment>true</fragment>   
  14. </attribute>   
  15. <!-- 配置標籤屬性:item -->   
  16. <attribute>   
  17.   <name>item</name>    
  18.   <required>true</required>   
  19.   <fragment>true</fragment>   
  20. </attribute>   
  21. </tag>  
<!-- 定義第三個標籤 -->
<tag>
<!-- 定義標籤名 -->
<name>iterator</name>
<!-- 定義標籤處理類 -->
<tag-class>lee.IteratorTag</tag-class>
<!-- 定義標籤體支持JSP腳本 -->
<body-content>scriptless</body-content>
<!-- 配置標籤屬性:collection -->
<attribute>
  <name>collection</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
<!-- 配置標籤屬性:item -->
<attribute>
  <name>item</name> 
  <required>true</required>
  <fragment>true</fragment>
</attribute>
</tag>


........上面配置片段中粗體字代碼指定該標籤的標籤體可以是靜態HTML內容,也可以是表達式語言。
........爲了測試在JSP頁面中使用該標籤的效果,我們首先把一個List對象設置成page範圍的屬性,然後使用該標籤來迭代輸出List集合的全部元素。
JSP頁面代碼如下:

Java代碼 複製代碼
  1. <%@ page import="java.util.*"%>   
  2. <%@ page contentType="text/html; charset=GBK"%>   
  3. <!-- 導入標籤庫,指定mytag前綴的標籤,   
  4. 由http://www.leegang.org/mytaglib的標籤庫處理 -->   
  5. <%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>   
  6. <html>   
  7. <head>   
  8.   <title>帶標籤體的標籤-迭代器標籤</title>   
  9. </head>   
  10. <body>   
  11.   <h2>帶標籤體的標籤-迭代器標籤</h2>   
  12.   <hr>   
  13.   <%   
  14.   //創建一個List對象   
  15.   List<String> a = new ArrayList<String>();   
  16.   a.add("hello");   
  17.   a.add("world");   
  18.   a.add("java");   
  19.   //將List對象放入page範圍內   
  20.   pageContext.setAttribute("a" , a);   
  21.   %>   
  22.   <table border="1" bgcolor="aaaadd" width="300">   
  23.   <!-- 使用迭代器標籤,對a集合進行迭代 -->   
  24.   <mytag:iterator collection="a" item="item">   
  25.    <tr>   
  26.     <td>${pageScope.item}</td>   
  27.    <tr>   
  28.   </mytag:iterator>   
  29.   </table>   
  30. </body>   
  31. </html>  
<%@ page import="java.util.*"%>
<%@ page contentType="text/html; charset=GBK"%>
<!-- 導入標籤庫,指定mytag前綴的標籤,
由http://www.leegang.org/mytaglib的標籤庫處理 -->
<%@ taglib uri="http://www.leegang.org/mytaglib" prefix="mytag"%>
<html>
<head>
  <title>帶標籤體的標籤-迭代器標籤</title>
</head>
<body>
  <h2>帶標籤體的標籤-迭代器標籤</h2>
  <hr>
  <%
  //創建一個List對象
  List<String> a = new ArrayList<String>();
  a.add("hello");
  a.add("world");
  a.add("java");
  //將List對象放入page範圍內
  pageContext.setAttribute("a" , a);
  %>
  <table border="1" bgcolor="aaaadd" width="300">
  <!-- 使用迭代器標籤,對a集合進行迭代 -->
  <mytag:iterator collection="a" item="item">
   <tr>
    <td>${pageScope.item}</td>
   <tr>
  </mytag:iterator>
  </table>
</body>
</html>


........上面頁面代碼中粗體字代碼即可實現通過iterator標籤來遍歷指定集合。

從iteratorTag.jsp頁面的代碼來看,使用iterator標籤遍歷集合元素比使用JSP腳本遍歷集合元素要優雅得多,這就是自定義標籤的魅力。
提示:實際上JSTL標籤庫提供了一套功能非常強大標籤,例如普通的輸出標籤,像我們剛剛便攜的迭代器標籤,還有用於分支判斷的標籤等等,JSTL都有非常完善的實現。

發佈了68 篇原創文章 · 獲贊 2 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章