Skip to content

8. JSTL 标签库

8.0.1. 简介

请看 [erreurs.jsp] 视图,它显示了一组错误列表:

Image

编写此类页面有多种方法。这里我们仅关注错误显示部分。一种解决方案是像之前那样使用 Java 代码:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ page import="java.util.ArrayList" %>
 
<%
// on récupère les données du modèle
  ArrayList erreurs=(ArrayList)request.getAttribute("erreurs"); 
  String lienRetourFormulaire=(String)request.getAttribute("lienRetourFormulaire");
%>
 
<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
        <%
          for(int i=0;i<erreurs.size();i++){
            out.println("<li>" + (String) erreurs.get(i) + "</li>\n");
        }//for
      %>
    </ul>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      <%= lienRetourFormulaire %>
    </a>
  </body>
</html>
 

该 JSP 页面从请求中获取错误列表(第 8 行),并使用 Java 循环将其显示出来(第 19–23 行)。 该页面混合了 HTML 和 Java 代码,如果页面需要由通常不理解 Java 代码的网页设计师进行维护,这可能会带来问题。为避免这种混合,通常使用标签库为 JSP 页面提供新功能。使用 JSTL(Java 标准标签库)后,之前的视图变为如下所示:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
 
<html>
    <head>
      <title>Personne</title>
  </head>
  <body>
      <h2>Les erreurs suivantes se sont produites</h2>
    <ul>
            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
    </ul>
    <br>
    <form name="frmPersonne" method="post">
      <input type="hidden" name="action" value="retourFormulaire">
    </form>
    <a href="javascript:document.frmPersonne.submit();">
      ${lienRetourFormulaire}
    </a>
  </body>
</html>

该标签(第4行)

<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

表示使用了在文件 [/WEB-INF/c.tld] 中定义的标签库。这些标签将在页面代码中使用,并以字母 c 为前缀(prefix="c")。 您可以使用任意前缀。此处,c 代表 [core]。前缀使您能够使用某些标签名称可能相同的标签库。使用前缀可消除任何歧义。新页面中,先前包含 Java 代码的两个位置现已不再包含

  • 检索页面模板 [errors, returnFormLink](已删除部分)
  • 显示错误列表(第 13–15 行)

错误显示循环已被以下代码取代:


            <c:forEach var="erreur" items="${erreurs}">
                <li>${erreur}</li>
            </c:forEach>
  • <forEach> 标签用于定义循环
  • ${variable} 语法用于显示变量的值

此处的 <forEach> 标签有两个属性:

  • items="${errors}" 指定了要迭代的对象集合。此处,该集合即为 errors 对象。该对象位于何处?JSP 页面会按以下顺序依次搜索名为 "errors" 的属性:
    • [request] 对象,它代表控制器发送的请求:request.getAttribute("errors")
    • [session] 对象,代表客户端的会话:session.getAttribute("errors")
    • [application] 对象,代表 Web 应用程序上下文:application.getAttribute("errors")

items 属性指定的集合可以是多种形式:数组ArrayList、实现 List 接口的对象等。

  • var="error" 用于命名当前正在处理的集合中的元素。<forEach> 循环将依次针对 items 集合中的每个元素执行。因此,在循环内部,正在处理的集合中的元素将在此处被称为 error

${error} 语法将 error 变量的值插入到文本中。该变量不一定是字符串。JSTL 使用 error.toString() 方法来插入 error 变量的值。除了 ${error} 语法外,您还可以使用 <c:out value="${error}"/> 标签。

回到我们显示错误的示例:

  • 控制器会将一个包含错误消息的 ArrayList(即一个 String 对象的 ArrayList)放入发送给 JSP 页面的请求中:request.setAttribute("errors", errors),其中 errors 是该 ArrayList
  • 由于 items="${errors}" 属性的存在,JSP 页面将依次在请求话和应用程序中查找名为 errors 的属性。它将在请求中找到该属性:request.getAttribute("errors") 将返回控制器放入请求中的 ArrayList
  • 因此,var="error" 属性中的 error 变量将指向 ArrayList 的当前元素,该元素是一个 String 对象。error.toString() 方法会将该 String 的值(在本例中即错误消息)插入到页面的 HTML 输出中。

由 <forEach> 标签处理的集合中的对象可能比简单的字符串更为复杂。让我们以一个显示文章列表的 JSP 页面为例:

1
2
3
4
5
6
7
            <c:forEach var="article" items="${listarticles}">
                <tr>
                    <td><c:out value="${article.nom}"/></td>
                    <td><c:out value="${article.prix}"/></td>
                    <td><a href="<c:url value="?action=infos&id=${article.id}"/>">Infos</a></td>
                </tr>
     </c:forEach>

其中 [listarticles] 是一个包含 [Article] 类型对象的 ArrayList,我们假设 [Article] 是一个 JavaBean,具有 [id, name, price, currentStock, minimumStock] 字段,每个字段都有自己的 getset 方法。 该 [listarticles] 对象是由控制器放入请求中的。前面的 JSP 页面通过 forEach 标签的 items 属性将其检索出来。因此,当前的 article 对象(var="article")指代一个 [Article] 类型的对象。请看第 3 行中的标签:

<c:out value="${article.nom}"/>

${article.nom} 是什么意思?实际上,这取决于 article 对象的性质,可能表示不同的内容。为了获取 article.nom 的值,JSP 页面会尝试以下两种方法:

  1. article.getNom() - 请注意拼写 getNom,用于获取 name 字段(JavaBean 标准)
  2. article.get("name")

因此,[article] 对象可以是一个带有 "name" 字段的 Bean,也可以是一个包含 "name" 键的字典。

被处理对象的嵌套深度没有限制。因此,该标签

<c:out value="${individu.enfants[1].nom}"/>

允许您处理以下类型的对象 [individu]:

class Individu{
    private String nom;
    private String prénom;
    private Individu[] enfants;
    // méthodes de la norme Javabean
    public String getNom(){ return nom;}
    public String getPrénom(){ return prénom;}
    public Individu getEnfants(int i){ return enfants[i];}
}

要获取 ${person.children[1].lastName} 的值,JSP 页面会尝试多种方法,包括以下这种成功的方法:

person.getChildren(1).getLastName(),其中 person 指代 Person 类型的对象。

8.0.2. 安装和探索 JSTL 库

上述说明对于我们感兴趣的应用程序已足够,但 JSTL 标签库除了已介绍的标签外还提供了其他标签。要探索这些标签,您可以运行库包中包含的教程。

我们将使用 [Jakarta Taglibs] 项目提供的 JSTL 1.1 实现版本,该版本可通过以下网址获取:[http://jakarta.apache.org/taglibs/](2006 年 5 月):

下载的 ZIP 文件包含以下内容:

Image

两个扩展名为 .war 的文件是 Web 应用程序归档文件:

  • standard-doc:关于 JSTL 标签的文档
  • standard-examples:标签使用示例

我们将把该应用程序部署到 Tomcat 中。通过 [开始] 菜单中的相应选项启动 Tomcat,然后输入 URL [http://localhost:8080] 并点击 [Tomcat Manager] 链接:

Image

随后将显示一个身份验证页面。我们使用 manager/manager admin/admin 登录,具体操作如第 2.3.3 节所示。

Image

此时将显示一个页面,列出了当前部署在 Tomcat 中的应用程序:

Image

我们可以使用页面底部的表单添加一个新应用程序:

Image

我们使用 [浏览] 按钮选择要部署的 .war 文件。

Image

虽然截图中未显示,但我们已从下载的 JSTL 发行版中选中了 [standard-examples.war] 文件。[部署] 按钮将保存并在此 Tomcat 环境中部署该应用程序。

Image

[/standard-examples] 应用程序已成功部署。我们启动它:

Image

建议读者在查找 JSTL 标签的使用示例时,参考本页面提供的各种链接。

[standard-doc] 应用程序可通过 [standard-doc.war] 文件以相同方式进行部署。该应用程序提供了关于 JSTL 库的较为技术性的信息,对初学者而言吸引力较小。

8.0.3. 在 Web 应用程序中使用 JSTL

在 JSTL 1.2 库提供的示例中,JSP 页面以以下标签开头:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

我们在第 8.1.1 节中已经遇到过这个标签,并给出了简要说明:

  • [uri]:URI(统一资源标识符),用于指定页面中使用的标签定义所在的位置。当 JSP 页面被编译为 Java 代码以生成 Servlet 时,Web 服务器将使用此 URI。Web 页面开发工具也会使用它来验证页面中使用的标签语法是否正确,或提供自动完成建议。 当您开始输入标签时,熟悉该库的工具便会向用户建议该标签的可能属性。
  • [前缀]:用于在页面上标识这些标签的前缀

若未连接到公共互联网,则无法使用 URI [http://java.sun.com/jsp/jstl/core]。此时,您可以将标签定义文件放置在本地。JSTL 1.2 发行版中的 [tld](标签语言定义)文件夹内提供了若干此类文件:

Image

JSTL 实际上是一组标签库的集合。我们将仅使用名为 [c.tld] 的库,即所谓的“核心”库。我们将把上述 [c.tld] 文件放置在应用程序的 [WEB-INF] 文件夹中:

Image

并在 JSP 页面中包含以下标签,以声明使用“核心”库:

<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

虽然使用标签库可以避免在 JSP 页面中直接编写 Java 代码,但当 JSP 页面编译为 Java Servlet 时,这些标签当然会被转换为 Java 代码。它们使用的是 JSTL 发行版 [lib] 文件夹中两个 JAR 文件 [jstl.jar, standard.jar] 中定义的类:

Image

这两个 JAR 文件被放置在应用程序的 [WEB-INF/lib] 文件夹中:

Image

现在,我们已经掌握了处理示例应用程序下一版本的基础知识。