JSTL

在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/><BR>  
  14. </body>  
  15. </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都有非常完善的实现。

<think>好的,我现在需要帮助用户了解JSTL的使用教程和示例。首先,我应该回顾用户提供的引用内容,确保回答准确。用户提到了几个引用,涉及JSTL的基本概念、核心标签库、与EL的结合以及特定标签的用法,比如<c:import>和<c:url>。用户可能希望了解如何开始使用JSTL,包括配置步骤、常用标签的示例以及最佳实践。 首先,我应该确认JSTL的基本介绍,包括它的作用和优势。根据引用[2],JSTL用于解决常见的逻辑控制问题,如遍历集合、条件测试等,而无需在JSP中编写Java代码。这需要提到JSTL的不同标签库,比如核心库、格式化库、SQL库等,但可能用户更关注核心库的使用。 接下来,用户需要教程和示例,所以需要分步骤说明如何配置JSTL。引用[4]提到需要导入标签库,可能需要说明如何在JSP页面中添加taglib指令,例如<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>。同时,用户可能需要知道如何下载JSTL库并将其添加到项目中,不过具体的下载步骤可能需要简略提及,或者建议查看官方文档。 然后,针对核心标签库的常用标签,需要给出示例。例如,变量操作标签<c:set>和<c:out>,条件判断标签<c:if>、<c:choose>,循环标签<c:forEach>和<c:forTokens>,URL处理标签<c:import>和<c:url>。每个标签都需要一个简单的代码示例,比如使用<c:forEach>遍历列表,用<c:if>进行条件判断。 另外,结合EL(表达式语言)的使用也很重要,引用[1]和[3]提到EL和JSTL的结合可以避免Java代码。因此,在示例中应该展示如何用EL表达式访问变量,例如${user.name}。 可能需要注意JSTLJSP的版本兼容性,比如JSP 2.0及以上版本对EL的支持,但用户可能没有提到这个问题,所以可能不需要深入,但可以稍微提及。 最后,根据用户提供的引用[4],需要说明<c:import>与<jsp:include>的区别,指出前者可以包含其他Web应用或网络资源,而后者仅限于同一应用。这部分可以作为使用技巧或注意事项来强调。 在生成相关问题的时候,需要考虑用户可能进一步想知道的内容,比如JSTL的其他标签库(如格式化、SQL),与EL的协作细节,常见错误处理,或者性能优化等。因此,相关问题可以围绕这些主题展开。 现在需要确保回答结构清晰,分步骤说明,并包含实际示例。同时,引用正确的来源,比如引用[2]说明JSTL的功能,引用[4]说明<c:import>的用法。每个引用标识要正确对应,比如在讲解核心标签时引用[2],在讲解<c:import>时引用[4]。 检查是否有遗漏的部分,比如配置步骤是否需要详细说明jar包的添加,或者是否需要提及Maven依赖。不过用户可能只需要基础的教程,所以简要说明导入taglib即可,具体依赖管理可能属于更高级的内容,可以放在相关问题中。 总结,回答的结构应该是:简介、配置步骤、核心标签示例(变量、条件、循环、URL)、与EL结合的优势、注意事项或高级用法,最后相关问题。</think>### JavaServer Pages Standard Tag Library (JSTL) 使用教程和示例 #### **1. JSTL简介** JSTLJSP 的标准标签库,提供了一系列标签用于简化页面逻辑控制,例如遍历集合、条件判断、格式化数据等。通过与 EL(Expression Language)结合,开发者可以避免在 JSP 中直接编写 Java 代码,提升代码可维护性[^2]。 --- #### **2. 配置 JSTL** - **步骤1**:下载 JSTL 库(如 `jstl-1.2.jar`),并将其添加到项目的 `WEB-INF/lib` 目录。 - **步骤2**:在 JSP 页面顶部声明标签库: ```jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> ``` 这里 `prefix="c"` 表示使用核心标签库的简写前缀。 --- #### **3. 核心标签库示例** ##### **(1) 变量操作** - **设置变量**:`<c:set>` ```jsp <c:set var="userName" value="Alice" scope="session" /> ``` - **输出变量**:`<c:out>` ```jsp 用户名:<c:out value="${userName}" default="Guest" /> ``` ##### **(2) 条件判断** - **单条件判断**:`<c:if>` ```jsp <c:if test="${user.age >= 18}"> 已成年 </c:if> ``` - **多条件选择**:`<c:choose>` ```jsp <c:choose> <c:when test="${score >= 90}">优秀</c:when> <c:when test="${score >= 60}">及格</c:when> <c:otherwise>不及格</c:otherwise> </c:choose> ``` ##### **(3) 循环遍历** - **遍历集合**:`<c:forEach>` ```jsp <c:forEach items="${userList}" var="user" varStatus="status"> 第${status.index + 1}位用户:${user.name} </c:forEach> ``` - **分割字符串**:`<c:forTokens>` ```jsp <c:forTokens items="Java,Python,C++" delims="," var="lang"> 语言:${lang} </c:forTokens> ``` ##### **(4) URL 处理** - **生成动态 URL**:`<c:url>` ```jsp <a href="<c:url value='/user/profile?id=${userId}' />">查看详情</a> ``` - **包含外部资源**:`<c:import>` ```jsp <c:import url="https://example.com/api/data" charEncoding="UTF-8" /> ``` 与 `<jsp:include>` 不同,`<c:import>` 支持跨应用或网络资源包含[^4]。 --- #### **4. 结合 EL 简化逻辑** JSTL 通常与 EL 配合使用,例如通过 `${}` 直接访问变量或对象属性: ```jsp <c:if test="${empty cart.items}"> 购物车为空 </c:if> ``` --- #### **5. 注意事项** - **作用域管理**:使用 `scope` 属性明确变量作用域(如 `request`、`session`)。 - **错误处理**:可通过 `<c:catch>` 捕获异常: ```jsp <c:catch var="errorMsg"> <%-- 可能出错的代码 --%> </c:catch> <c:if test="${not empty errorMsg}"> 错误:${errorMsg} </c:if> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值