﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-奋起直追</title><link>http://www.blogjava.net/wsbjwjt/</link><description>奋起直追，追求技术的真谛。</description><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 01:00:33 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 01:00:33 GMT</pubDate><ttl>60</ttl><item><title>JSTL标签的用法</title><link>http://www.blogjava.net/wsbjwjt/archive/2006/05/29/48793.html</link><dc:creator>wsbjwjt</dc:creator><author>wsbjwjt</author><pubDate>Mon, 29 May 2006 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/wsbjwjt/archive/2006/05/29/48793.html</guid><wfw:comment>http://www.blogjava.net/wsbjwjt/comments/48793.html</wfw:comment><comments>http://www.blogjava.net/wsbjwjt/archive/2006/05/29/48793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wsbjwjt/comments/commentRss/48793.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wsbjwjt/services/trackbacks/48793.html</trackback:ping><description><![CDATA[
		<table style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>顾名思义，JSP 标准标记库（JSP Standard Tag Library，JSTL）core 库为一些基本功能（如，管理限定了作用域的变量和与 URL 交互等）和基本操作（如，迭代和条件化）提供了定制标记。这些标记不仅可以由页面设计人员直接利用，而且还为与其它 JSTL 库相结合从而提供更复杂的表示逻辑奠定了基础。Mark Kolb 在本文中继续对 JSTL 和 core 库进行探讨，研究用标记来协助流控制和 URL 管理。 <br />通过阅读本系列的第一篇文章，您对 JSTL 有了初步的了解。我们描述了使用其表达式语言（EL）来访问数据和操作数据。正如您所了解的那样，EL 用来为 JSTL 定制标记的属性赋予动态值，因此，它所起的作用与 JSP 表达式一样，为内置操作及其它定制标记库指定请求时的属性值。 <br /><br />为了演示 EL 的用法，我们介绍了 core 库中的三个标记：&lt;c:set&gt;;、&lt;c:remove&gt;; 和 &lt;c:out&gt;;。&lt;c:set&gt;; 和 &lt;c:remove&gt;; 用于管理限定了作用域的变量；而 &lt;c:out&gt;; 用于显示数据，尤其是显示用 EL 计算出的值。在此基础上，接下来本文把注意力集中在 core 库的其余标记上，这些标记可以大致归为两大类别：流控制和 URL 管理。 <br /><br />示例应用程序 <br />为了演示 JSTL 标记，我们将使用来自一个工作应用程序的示例，本系列中余下的文章都将使用此应用程序。由于基于 Java 的 Weblog 日渐流行及为人们所熟悉，因此我们将出于此目的使用一个简单的基于 Java 的 Weblog；参阅参考资料以下载该应用程序的 JSP 页面和源代码。Weblog（也称为 blog）是一种基于 Web 的简短注释的日志，这些注释是有关 Weblog 的作者所感兴趣的主题，通常带有与 Web 上其它地方的相关文章及讨论的链接。图 1 中显示了该应用程序正在运行时的抓屏。<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/weblog1.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 1. Weblog 应用程序</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 19:19:36</b><br /><br />虽然完整的实现需要二十四个 Java 类，但在表示层中却只涉及 Weblog 应用程序中的两个类，Entry 和 UserBean。这样，对于理解 JSTL 示例而言，只有这两个类比较重要。图 2 显示了 Entry 和 UserBean 的类图。<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/classes2.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 2. Weblog 应用程序的类图</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 19:33:02</b><br /><br />Entry 类表示 Weblog 中一个标有日期的项。其 id 属性用于在数据库中存储及检索该项，而 title 和 text 属性则表示该项的实际内容。created 和 lastModified 属性引用了 Java 语言中 Date 类的两个实例，分别用来表示最初创建该项的时间和最后编辑该项的时间。author 属性引用了标识该项的创建者的 UserBean 实例。 <br /><br />UserBean 类存储了有关应用程序的已认证用户的信息，如用户名、全名和电子邮件地址。该类还包含一个用于与相关数据库进行交互的 id 属性。其最后一个属性 roles 引用一列 String 值，这列值标识与相应用户相关的、特定于应用程序的角色。对于 Weblog 应用程序，相关的角色是“User”（所有应用程序用户常用的缺省角色）和“Author”（该角色指定可以创建和编辑 Weblog 项的用户）。 <br /><br />流控制 <br />由于可以用 EL 替代 JSP 表达式来指定动态属性值，因此页面创作人员无需使用脚本编制元素。因为脚本编制元素可能是引起 JSP 页面中维护问题的主要原因，所以 JSTL 的主要优点就在于提供了这样简单（且标准）的替代方法。 <br /><br />EL 从 JSP 容器检索数据，遍历对象层次结构，然后对结果执行简单的操作。不过，除了访问和操作数据之外，JSP 脚本编制元素的另一个常见用法是流控制。尤其是，页面创作人员常借助 scriptlet 来实现迭代或条件内容。然而，因为这样的操作超出了 EL 的能力，所以 core 库提供了几个定制操作来管理流控制，其形式有迭代、条件化和异常处理。 <br /><br />迭代 <br />在 Web 应用程序环境中，迭代主要用于访存和显示数据集，通常是以列表或表中的一系列行的形式显示。实现迭代内容的主要 JSTL 操作是 &lt;c:forEach&gt;; 定制标记。该标记支持两种不同样式的迭代：整数范围上的迭代（类似 Java 语言的 for 语句）和集合上的迭代（类似 Java 语言的 Iterator 和 Enumeration 类）。 <br /><br />进行整数范围迭代用到了清单 1 中所示的 &lt;c:forEach&gt;; 标记的语法。begin 和 end 属性要么是静态整数值，要么是可以得出整数值的表达式。它们分别指定迭代索引的初始值以及迭代索引的终止值。当使用 &lt;c:forEach&gt;; 在整数范围内进行迭代时，这两个属性是必需的，而其它所有属性都是可选的。 <br /><br />清单 1. 通过 &lt;c:forEach&gt;; 操作进行数字迭代的语法 <br />&lt;c:forEach var="name" varStatus="name" <br />    begin="expression" end="expression" step="expression"&gt;; <br />  body content <br />&lt;/c:forEach&gt;; <br /><br /><br />  <br /><br />当出现 step 时，它也必须是整数值。它指定每次迭代后索引的增量。这样，迭代索引从 begin 属性的值开始，以 step 属性的值为增量进行递增，在迭代索引超过 end 属性的值时停止迭代。注：如果省略了 step 属性，那么步长缺省为 1。 <br /><br />如果指定了 var 属性，那么将会创建一个带有指定名称的并限定了作用域的变量，并将每次迭代的当前索引值赋给该变量。这一限定了作用域的变量具有嵌套式可视性 — 只可以在 &lt;c:forEach&gt;; 标记体内对其进行访问。（我们很快将讨论可选属性 varStatus 的用法。）清单 2 显示了对一组固定整数值进行迭代的 &lt;c:forEach&gt;; 操作示例。 <br /><br />清单 2. 使用 &lt;c:forEach&gt;; 标记来生成表列数据，这些数据对应于某一范围内的数值。 <br />&lt;table&gt;; <br />&lt;tr&gt;;&lt;th&gt;;Value&lt;/th&gt;; <br />    &lt;th&gt;;Square&lt;/th&gt;;&lt;/tr&gt;; <br />&lt;c:forEach var="x" begin="0" end="10" step="2"&gt;; <br />  &lt;tr&gt;;&lt;td&gt;;&lt;c:out value="${x}"/&gt;;&lt;/td&gt;; <br />      &lt;td&gt;;&lt;c:out value="${x * x}"/&gt;;&lt;/td&gt;;&lt;/tr&gt;; <br />&lt;/c:forEach&gt;; <br />&lt;/table&gt;; <br /><br /><br />  <br /><br />如图 3 中所示，上面的示例代码生成了一张表，显示前五个偶数及其平方。这是通过将 begin 和 step 属性值指定为 2，而将 end 属性值指定为 10 实现的。此外，用 var 属性创建用于存储索引值的限定了作用域的变量，&lt;c:forEach&gt;; 标记体内引用了该变量。尤其是，使用了一对 &lt;c:out&gt;; 操作来显示索引及其平方，其中索引的平方是使用一个简单的表达式计算得来的。<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/foreach3.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 3. 清单 2 的输出</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 22:53:10</b><br /><br />在对集合的成员进行迭代时，用到了 &lt;c:forEach&gt;; 标记的另一个属性：items 属性，清单 3 中显示了该属性。当使用这种形式的 &lt;c:forEach&gt;; 标记时，items 属性是唯一必需的属性。items 属性的值应该是一个集合，对该集合的成员进行迭代，通常使用 EL 表达式指定值。如果变量名称是通过 &lt;c:forEach&gt;; 标记的 item 属性指定的，那么对于每次迭代该已命名变量都将被绑定到集合后续元素上。 <br /><br />清单 3. 通过 &lt;c:forEach&gt;; 操作对集合进行迭代的语法 <br />&lt;c:forEach var="name" items="expression" varStatus="name" <br />    begin="expression" end="expression" step="expression"&gt;; <br />  body content <br />&lt;/c:forEach&gt;; <br /><br /><br />  <br /><br />&lt;c:forEach&gt;; 标记支持 Java 平台所提供的所有标准集合类型。此外，您可以使用该操作来迭代数组（包括基本类型数组）中的元素。表 1 列出了 items 属性所支持的所有值。正如表的最后一行所指出的那样，JSTL 定义了它自己的接口 javax.servlet.jsp.jstl.sql.Result，用来迭代 SQL 查询的结果。（我们将在本系列后面的文章中详细讨论这一功能。） <br /><br />表 1. &lt;c:forEach&gt;; 标记的 items 属性所支持的集合 <br /><br />items 的值 所产生的 item 值  <br />java.util.Collection 调用 iterator() 所获得的元素  <br />java.util.Map java.util.Map.Entry 的实例  <br />java.util.Iterator 迭代器元素  <br />java.util.Enumeration 枚举元素  <br />Object 实例数组 数组元素  <br />基本类型值数组 经过包装的数组元素  <br />用逗号定界的 String 子字符串  <br />javax.servlet.jsp.jstl.sql.Result SQL 查询所获得的行  <br /><br /><br /><br />可以使用 begin、end 和 step 属性来限定在迭代中包含集合中哪些元素。和通过 &lt;c:forEach&gt;; 进行数字迭代的情形一样，在迭代集合中的元素时同样要维护一个迭代索引。&lt;c:forEach&gt;; 标记实际上只处理那些与索引值相对应的元素，这些索引值与指定的 begin、end 和 step 值相匹配。 <br /><br />清单 4 显示了用来迭代集合的 &lt;c:forEach&gt;; 标记。对于该 JSP 代码段，entryList 这一限定了作用域的变量被设置成了 Entry 对象列表（确切的说，ArrayList）。&lt;c:forEach&gt;; 标记依次处理列表中的每个元素，将其赋给一个限定了作用域的变量 blogEntry，然后生成两个表行 — 一个用于 Weblog 项的 title，另一个则用于该项 text。这些特性是通过一对带有相应 EL 表达式的 &lt;c:out&gt;; 操作从 blogEntry 变量检索得到的。注：由于 Weblog 项的标题和文本都可能包含 HTML 标记，因此这两个 &lt;c:out&gt;; 标记的 escapeXml 属性都被设置成了 false。图 4 显示了结果。 <br /><br />清单 4. 使用 &lt;c:forEach&gt;; 标记显示表示给定日期的 Weblog 项 <br />&lt;table&gt;; <br />  &lt;c:forEach items="${entryList}" var="blogEntry"&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogTitle"&gt;; <br />      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogText"&gt;; <br />      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />  &lt;/c:forEach&gt;; <br />&lt;/table&gt;;<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/blog14.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 4. 清单 4 的输出</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 22:56:04</b><br /><br />不论是对整数还是对集合进行迭代，&lt;c:forEach&gt;; 剩余的属性 varStatus 所起的作用相同。和 var 属性一样，varStatus 用于创建限定了作用域的变量。不过，由 varStatus 属性命名的变量并不存储当前索引值或当前元素，而是赋予 javax.servlet.jsp.jstl.core.LoopTagStatus 类的实例。该类定义了一组特性，它们描述了迭代的当前状态，表 2 中列出了这些特性。 <br /><br />表 2. LoopTagStatus 对象的特性 <br /><br />特性 Getter 描述  <br />current getCurrent() 当前这次迭代的（集合中的）项  <br />index getIndex() 当前这次迭代从 0 开始的迭代索引  <br />count getCount() 当前这次迭代从 1 开始的迭代计数  <br />first isFirst() 用来表明当前这轮迭代是否为第一次迭代的标志  <br />last isLast() 用来表明当前这轮迭代是否为最后一次迭代的标志  <br />begin getBegin() begin 属性值  <br />end getEnd() end 属性值  <br />step getStep() step 属性值  <br /><br /><br /><br />清单 5 显示了关于如何使用 varStatus 属性的一个示例。这个示例修改了清单 4 中的代码，将 Weblog 项的编号添加到显示 Weblog 标题（title）的表行。它是通过为 varStatus 属性指定一个值，然后访问所生成的限定了作用域的变量的 count 特性来实现这一点的。结果显示在图 5 中。 <br /><br />清单 5. 使用 varStatus 属性来显示 Weblog 项的数目 <br />&lt;table&gt;; <br />  &lt;c:forEach items= <br />    "${entryList}" var="blogEntry" varStatus="status"&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogTitle"&gt;; <br />      &lt;c:out value="${status.count}"/&gt;;. <br />      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogText"&gt;; <br />      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />  &lt;/c:forEach&gt;; <br />&lt;/table&gt;;<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/blog25.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 5. 清单 5 的输出</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 22:58:50</b><br /><br />除 &lt;c:forEach&gt;; 以外，core 库还提供了另一个迭代标记：&lt;c:forTokens&gt;;。JSTL 的这个定制操作与 Java 语言的 StringTokenizer 类的作用相似。清单 6 中显示的 &lt;c:forTokens&gt;; 标记除了比 &lt;c:forEach&gt;; 的面向集合版本多一个属性之外，其它属性都相同。对于 &lt;c:forTokens&gt;; 而言，通过 items 属性指定要标记化的字符串，而通过 delims 属性提供用于生成标记的一组定界符。和 &lt;c:forEach&gt;; 的情形一样，可以使用 begin、end 和 step 属性将要处理的标记限定为那些与相应索引值相匹配的标记。 <br /><br />清单 6. 使用 &lt;c:forTokens&gt;; 操作来迭代字符串标记的语法 <br />&lt;c:forTokens var="name" items="expression" <br />    delims="expression" varStatus="name" <br />    begin="expression" end="expression" step="expression"&gt;; <br />  body content <br />&lt;/c:forTokens&gt;; <br /><br /><br />  <br /><br />条件化 <br />对于包含动态内容的 Web 页面，您可能希望不同类别的用户看到不同形式的内容。例如，在我们的 Weblog 中，访问者应该能够阅读各项，也许还应该能够提交反馈，但只有经过授权的用户才能公布新项，或编辑已有内容。 <br /><br />在同一个 JSP 页面内实现这样的功能，然后使用条件逻辑来根据每条请求控制所显示的内容，这样做常常能够改善实用性和软件维护。core 库提供了两个不同的条件化标记 — &lt;c:if&gt;; 和 &lt;c:choose&gt;; — 来实现这些功能。 <br /><br />&lt;c:if&gt;; 是这两个操作中较简单的一个，它简单地对单个测试表达式进行求值，接下来，仅当对表达式求出的值为 true 时，它才处理标记的主体内容。如果求出的值不为 true，就忽略该标记的主体内容。如清单 7 所示，&lt;c:if&gt;; 可以通过其 var 和 scope 属性（它们所起的作用和在 &lt;c:set&gt;; 中所起的作用一样）选择将测试结果赋给限定了作用域的变量。当测试代价非常高昂时，这种能力尤为有用：可以将结果高速缓存在限定了作用域的变量中，然后在随后对 &lt;c:if&gt;; 或其它 JSTL 标记的调用中检索该结果。 <br /><br />清单 7. &lt;c:if&gt;; 条件操作的语法 <br />&lt;c:if test="expression" var="name" scope="scope"&gt;; <br />  body content <br />&lt;/c:if&gt;; <br /><br /><br />  <br /><br />清单 8 显示了与 &lt;c:forEach&gt;; 标记的 LoopTagStatus 对象的 first 特性一起使用的 &lt;c:if&gt;;。如图 6 中所示，在这种情况下，只在 Weblog 项的第一项上显示这组项的创建日期，而不在任何其它项前面重复该日期。 <br /><br />清单 8. 使用 &lt;c:if&gt;; 来为 Weblog 项显示日期 <br />&lt;table&gt;; <br />  &lt;c:forEach items= <br />    "${entryList}" var="blogEntry" varStatus="status"&gt;; <br />    &lt;c:if test="${status.first}"&gt;; <br />      &lt;tr&gt;;&lt;td align="left" class="blogDate"&gt;; <br />            &lt;c:out value="${blogEntry.created}"/&gt;; <br />      &lt;/td&gt;;&lt;/tr&gt;; <br />    &lt;/c:if&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogTitle"&gt;; <br />      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />    &lt;tr&gt;;&lt;td align="left" class="blogText"&gt;; <br />      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;; <br />    &lt;/td&gt;;&lt;/tr&gt;; <br />  &lt;/c:forEach&gt;; <br />&lt;/table&gt;;<br /><table class="attachtable" cellspacing="4" cellpadding="1" align="center" border="3"><tbody><tr><td align="middle" colspan="2"><br /><img src="http://bbs.chinaunix.net/attachments/blog36.jpg" border="0" /><br /><br /></td></tr><tr><td><table cellspacing="4" cellpadding="0" width="100%" align="center" border="0"><tbody><tr><td class="attachrow"><span class="genmed">图 6. 清单 8 的输出</span></td></tr></tbody></table></td></tr></tbody></table><br /><br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-13 22:59:57</b><br /><br />如清单 8 所示，&lt;c:if&gt;; 标记为条件化内容的一些简单情形提供了一种非常简洁的表示法。对于需要进行互斥测试来确定应该显示什么内容的情况下，JSTL core 库还提供了 &lt;c:choose&gt;; 操作。清单 9 中显示了 &lt;c:choose&gt;; 的语法。 <br /><br />清单 9. &lt;c:choose&gt;; 操作的语法 <br />&lt;c:choose&gt;; <br />  &lt;c:when test="expression"&gt;; <br />    body content <br />  &lt;/c:when&gt;; <br />  ... <br />  &lt;c:otherwise&gt;; <br />    body content <br />  &lt;/c:otherwise&gt;; <br />&lt;/c:choose&gt;; <br /><br /><br />  <br /><br />每个要测试的条件都由相应的 &lt;c:when&gt;; 标记来表示，至少要有一个 &lt;c:when&gt;; 标记。只会处理第一个其 test 值为 true 的 &lt;c:when&gt;; 标记体内的内容。如果没有一个 &lt;c:when&gt;; 测试返回 true，那么会处理 &lt;c:otherwise&gt;; 标记的主体内容。注：尽管如此，&lt;c:otherwise&gt;; 标记却是可选的；&lt;c:choose&gt;; 标记至多可有一个嵌套的 &lt;c:otherwise&gt;; 标记。如果所有 &lt;c:when&gt;; 测试都为 false，而且又没有给出 &lt;c:otherwise&gt;; 操作，那么不会处理任何 &lt;c:choose&gt;; 标记的主体内容。 <br /><br />清单 10 显示了运用 &lt;c:choose&gt;; 标记的示例。在这里，检索请求对象而获得协议信息（通过 EL 的 pageContext 隐式对象），并用简单的字符串比较对协议信息进行测试。根据这些测试的结果，会显示相应的文本消息。 <br /><br />清单 10. 使用 &lt;c:choose&gt;; 进行内容条件化 <br />&lt;c:choose&gt;; <br />  &lt;c:when test="${pageContext.request.scheme eq 'http'}"&gt;; <br />    This is an insecure Web session. <br />  &lt;/c:when&gt;; <br />  &lt;c:when test="${pageContext.request.scheme eq 'https'}"&gt;; <br />    This is a secure Web session. <br />  &lt;/c:when&gt;; <br />  &lt;c:otherwise&gt;; <br />    You are using an unrecognized Web protocol. How did this happen?! <br />  &lt;/c:otherwise&gt;; <br />&lt;/c:choose&gt;; <br /><br /><br />  <br /><br />异常处理 <br />最后一个流控制标记是 &lt;c:catch&gt;;，它允许在 JSP 页面内进行初级的异常处理。更确切地说，在该标记的主体内容中产生的任何异常都会被捕获并被忽略（即，不会调用标准的 JSP 错误处理机制）。然而，如果产生了一个异常并且已经指定了 &lt;c:catch&gt;; 标记的可选属性 var，那么会将异常赋给（具有页面作用域的）指定的变量，这使得能够在页面自身内部进行定制错误处理。清单 11 显示了 &lt;c:catch&gt;; 的语法（稍后在清单 18 中给出一个示例）。 <br /><br />清单 11. &lt;c:catch&gt;; 操作的语法 <br />&lt;c:catch var="name"&gt;; <br />  body content <br />&lt;/c:catch&gt;; <br /><br /><br />  <br /><br />URL 操作 <br />JSTL core 库中的其余标记主要是关于 URL。这些标记中的第一个被适当地命名为 &lt;c:url&gt;; 标记，用于生成 URL。尤其是，&lt;c:url&gt;; 提供了三个功能元素，它们在为 J2EE Web 应用程序构造 URL 时特别有用： <br /><br />在前面附加当前 servlet 上下文的名称  <br />为会话管理重写 URL  <br />请求参数名称和值的 URL 编码  <br />清单 12 显示了 &lt;c:url&gt;; 标记的语法。value 属性用来指定基本 URL，然后在必要时标记对其进行转换。如果这个基本 URL 以一个斜杠开始，那么会在它前面加上 servlet 的上下文名称。可以使用 context 属性提供显式的上下文名称。如果省略该属性，那么就使用当前 servlet 上下文的名称。这一点特别有用，因为 servlet 上下文名称是在部署期间而不是开发期间决定的。（如果这个基本 URL 不是以斜杠开始的，那么就认为它是一个相对 URL，这时就不必添加上下文名称。） <br /><br />清单 12. &lt;c:url&gt;; 操作的语法 <br />&lt;c:url value="expression" context="expression" <br />    var="name" scope="scope"&gt;; <br />  &lt;c:param name="expression" value="expression"/&gt;; <br />  ... <br />&lt;/c:url&gt;; <br /><br /><br />  <br /><br />URL 重写是由 &lt;c:url&gt;; 操作自动执行的。如果 JSP 容器检测到一个存储用户当前会话标识的 cookie，那么就不必进行重写。但是，如果不存在这样的 cookie，那么 &lt;c:url&gt;; 生成的所有 URL 都会被重写以编码会话标识。注：如果在随后的请求中存在适当的 cookie，那么 &lt;c:url&gt;; 将停止重写 URL 以包含该标识。 <br /><br />如果为 var 属性提供了一个值（还可以同时为 scope 属性提供一个相应的值，这是可选的），那么将生成的 URL 赋值给这个限定了作用域的指定变量。否则，将使用当前的 JspWriter 输出生成的 URL。这种直接输出其结果的能力允许 &lt;c:url&gt;; 标记作为值出现，例如，作为 HTML &lt;a&gt;; 标记的 href 属性的值，如清单 13 中所示。 <br /><br />清单 13. 生成 URL 作为 HTML 标记的属性值 <br />&lt;a href="&lt;c:url value='/content/sitemap.jsp'/&gt;;"&gt;;View sitemap&lt;/a&gt;; <br /><br /><br />  <br /><br />最后，如果通过嵌套 &lt;c:param&gt;; 标记指定了任何请求参数，那么将会使用 HTTP GET 请求的标准表示法将它们的名称和值添加到生成的 URL 后面。此外，还进行 URL 编码：为了生成有效的 URL，将对这些参数的名称或值中出现的任何字符适当地进行转换。清单 14 演示了 &lt;c:url&gt;; 的这种行为。 <br /><br />清单 14. 生成带请求参数的 URL  <br />&lt;c:url value="/content/search.jsp"&gt;; <br />  &lt;c:param name="keyword" value="${searchTerm}"/&gt;; <br />  &lt;c:param name="month" value="02/2003"/&gt;; <br />&lt;/c:url&gt;; <br /><br /><br />  <br /><br />清单 14 中的 JSP 代码被部署到一个名为 blog 的 servlet 上下文，限定了作用域的变量 searchTerm 的值被设置为 "core library"。如果检测到了会话 cookie，那么清单 14 生成的 URL 将类似于清单 15 中的 URL。注：在前面添加上下文名称，而在后面附加请求参数。此外，keyword 参数值中的空格和 month 参数值中的斜杠都被按照 HTTP GET 参数的需要进行了编码（确切地说，空格被转换成了 +，而斜杠被转换成了 %2F 序列）。 <br /><br />清单 15. 有会话 cookie 时生成的 URL <br />/blog/content/search.jsp?keyword=foo+bar&amp;month=02%2F2003 <br /><br /><br />  <br /><br />当没有会话 cookie 时，生成的结果如清单 16 中所示。同样，servlet 上下文被添加到了前面，而 URL 编码的请求参数被附加到了后面。不过，除此以外还重写了基本 URL 以包含指定的会话标识。当浏览器发送用这种方式重写的 URL 请求时，JSP 容器自动抽取会话标识，并将请求与相应的会话进行关联。这样，需要会话管理的 J2EE 应用程序就无需依赖由应用程序用户启用的 cookie 了。 <br /><br />清单 16. 没有会话 cookie 时生成的 URL <br />/blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290 <br />  ?keyword=foo+bar&amp;month=02%2F2003 <br /><br /><br />  <br /><br />导入内容 <br />JSP 有两种内置机制可以将来自不同 URL 的内容合并到一个 JSP 页面：include 伪指令和 &lt;jsp:include&gt;; 操作。不过，不管是哪种机制，要包含的内容都必须属于与页面本身相同的 Web 应用程序（或 servlet 上下文）。两个标记之间的主要区别在于：include 伪指令在页面编译期间合并被包含的内容，而 &lt;jsp:include&gt;; 操作却在请求处理 JSP 页面时进行。 <br /><br />从本质上讲，core 库的 &lt;c:import&gt;; 操作是更通用、功能更强大的 &lt;jsp:include&gt;; 版本（好像是 &lt;jsp:include&gt;;“服用了兴奋剂”的）。和 &lt;jsp:include&gt;; 一样，&lt;c:import&gt;; 也是一种请求时操作，它的基本任务就是将其它一些 Web 资源的内容插入 JSP 页面中。如清单 17 中所示，它的语法非常类似于 &lt;c:url&gt;; 的语法。 <br /><br />清单 17. &lt;c:import&gt;; 操作的语法 <br />&lt;c:import url="expression" context="expression" <br />    charEncoding="expression" var="name" scope="scope"&gt;; <br />  &lt;c:param name="expression" value="expression"/&gt;; <br />  ... <br />&lt;/c:import&gt;; <br /><br /><br />  <br /><br />通过 url 属性指定将要导入内容的 URL，这个属性是 &lt;c:import&gt;; 的唯一一个必选属性。这里允许使用相对 URL，并且根据当前页面的 URL 来解析这个相对 URL。但是，如果 url 属性的值以斜杠开始，那么它就被解释成本地 JSP 容器内的绝对 URL。如果没有为 context 属性指定值，那么就认为这样的绝对 URL 引用当前 servlet 上下文内的资源。如果通过 context 属性显式地指定了上下文，那么就根据指定的 servlet 上下文解析绝对（本地）URL。 <br /><br />但 &lt;c:import&gt;; 操作并不仅仅限于访问本地内容。也可以将包含协议和主机名的完整 URI 指定为 url 属性的值。实际上，协议甚至不仅局限于 HTTP。&lt;c:import&gt;; 的 url 属性值可以使用 java.net.URL 类所支持的任何协议。清单 18 中显示了这种能力。 <br /><br />其中，&lt;c:import&gt;; 操作用来包含通过 FTP 协议访问的文档内容。此外，还使用了 &lt;c:catch&gt;; 操作，以便在本地处理 FTP 文件传送期间可能发生的任何错误。错误处理是这样实现的：使用 &lt;c:catch&gt;; 的 var 属性为异常指定一个限定了作用域的变量，然后使用 &lt;c:if&gt;; 检查其值。如果产生了异常，那么就会对那个限定了作用域的变量进行赋值：如清单 18 中的 EL 表达式所显示的那样，该变量的值将不会为空。由于 FTP 文档的检索将会失败，因此会显示有关这种情况的错误消息。 <br /><br />清单 18. 将 &lt;c:import&gt;; 与 &lt;c:catch&gt;; 相结合的示例 <br />&lt;c:catch var="exception"&gt;; <br />  &lt;c:import url="ftp://ftp.example.com/package/README"/&gt;; <br />&lt;/c:catch&gt;; <br />&lt;c:if test="${not empty exception}"&gt;; <br />  Sorry, the remote content is not currently available. <br />&lt;/c:if&gt;; <br /><br /><br />  <br /><br />&lt;c:import&gt;; 操作的最后两个（可选的）属性是 var 和 scope。var 属性会导致从指定 URL 获取的内容（作为 String 值）被存储在一个限定了作用域的变量中，而不是包含在当前 JSP 页面中。scope 属性控制该变量的作用域，缺省情况下是页面作用域。如同我们在今后的文章中将要看到的那样，JSTL xml 库中的标记利用了 &lt;c:import&gt;; 这种能力，即将整个文档存储在一个限定了作用域的变量中。 <br /><br />还要注意的是，可以使用（可选的）嵌套的 &lt;c:param&gt;; 标记来为正在导入的 URL 指定请求参数。与在 &lt;c:url&gt;; 中嵌套 &lt;c:param&gt;; 标记一样，必要时也要对参数名称和参数值进行 URL 编码。 <br /><br />请求重定向 <br />最后一个 core 库标记是 &lt;c:redirect&gt;;。该操作用于向用户的浏览器发送 HTTP 重定向响应，它是 JSTL 中与 javax.servlet.http.HttpServletResponse 的 sendRedirect() 方法功能相当的标记。清单 19 中显示了该标记的 url 和 context 属性，它们的行为分别等同于 &lt;c:import&gt;; 的 url 和 context 属性的行为，是嵌套任何 &lt;c:param&gt;; 标记的结果。 <br /><br />清单 19. &lt;c:redirect&gt;; 操作的语法 <br />&lt;c:redirect url="expression" context="expression"&gt;; <br />  &lt;c:param name="expression" value="expression"/&gt;; <br />  ... <br />&lt;/c:redirect&gt;; <br /><br /><br />  <br /><br />清单 20 显示了 &lt;c:redirect&gt;; 操作，它用一个到指定错误页面的重定向代替了清单 18 中的错误消息。在该示例中，&lt;c:redirect&gt;; 标记的用法与标准 &lt;jsp:forward&gt;; 操作的用法类似。不过请回忆一下：通过请求分派器进行转发是在服务器端实现的，而重定向却是由浏览器来执行的。从开发人员的角度来讲，转发比重定向更有效率，但 &lt;c:redirect&gt;; 操作却更灵活一些，因为 &lt;jsp:forward&gt;; 只能分派到当前 servlet 上下文内的其它 JSP 页面。 <br /><br />清单 20. 响应异常的重定向 <br />&lt;c:catch var="exception"&gt;; <br />  &lt;c:import url="ftp://ftp.example.com/package/README"/&gt;; <br />&lt;/c:catch&gt;; <br />&lt;c:if test="${not empty exception}"&gt;; <br />  &lt;c:redirect url="/errors/remote.jsp"/&gt;; <br />&lt;/c:if&gt;; <br /><br /><br />  <br /><br />从用户的角度来看，主要区别在于重定向会更新浏览器所显示的 URL，并因此影响书签的设置。转发却不这样，它对最终用户是透明的。这样，选择 &lt;c:redirect&gt;; 还是 &lt;jsp:forward&gt;; 还取决于所期望的用户体验。 <br /><br />结束语 <br />JSTL core 库含有多种通用的定制标记，广大的 JSP 开发人员都会使用这些标记。例如，URL 和异常处理标记很好地补充了现有的 JSP 功能，如 &lt;jsp:include&gt;; 和 &lt;jsp:forward&gt;; 操作、include 伪指令以及 page 伪指令的 errorpage 属性。迭代和条件操作使得无需脚本编制元素就能够实现复杂的表示逻辑，尤其在将变量标记（&lt;c:set&gt;; 和 &lt;c:remove&gt;;）与 EL 相结合使用时更是如此。<br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=43751" target="_blank">echoguo</a> 回复于：2003-08-15 11:00:48</b><br /><br />请关注本系列的其他文章： <br /> JSTL 入门(1)：表达式语言 <br />http://www.chinaunix.net/forum/viewtopic.php?t=138463 <br /><br /><br />JSTL 入门(3)：表示就是一切—通过定制标记进行格式化和国际化 <br />http://www.chinaunix.net/forum/viewtopic.php?t=139893 <br /><br /><br />JSTL 入门(4)：访问SQL和XML内容 <br />http://www.chinaunix.com/forum/viewtopic.php?t=139910<br /><br /><hr /><b> <a href="http://bbs.chinaunix.net/viewpro.php?uid=66663" target="_blank">郝君</a> 回复于：2003-08-19 02:48:21</b><br /><br />收藏吼~~~~~~~~<br /><br /><br /><br /></td>
						</tr>
						<tr>
								<td bgcolor="#747474" height="1">
										<img height="1" src="http://image2.sina.com.cn/c.gif" width="1" />
								</td>
						</tr>
						<tr>
								<td>
										<br />原文链接：<a href="http://bbs.chinaunix.net/viewthread.php?tid=138695">http://bbs.chinaunix.net/viewthread.php?tid=138695</a><br />转载请注明作者名及原文出处<br /><br /><br /><!---广告　开- --><script type="text/javascript"><![CDATA[
var arrBaiduCproConfig=new Array(); 
arrBaiduCproConfig['uid'] =309462;
arrBaiduCproConfig['n'] ='chinaunix888_cpr';
arrBaiduCproConfig['tm'] =20;
arrBaiduCproConfig['cm'] =0;
arrBaiduCproConfig['um'] =26;
arrBaiduCproConfig['w'] =728;
arrBaiduCproConfig['h'] =90;
arrBaiduCproConfig['wn'] =4;
arrBaiduCproConfig['hn'] =3;
arrBaiduCproConfig['ta'] ='right';
arrBaiduCproConfig['tl'] ='bottom';
arrBaiduCproConfig['bu'] =0;
arrBaiduCproConfig['bd'] ='#EDF0F5';
arrBaiduCproConfig['bg'] ='#EDF0F5';
arrBaiduCproConfig['tt'] ='#0000ff';
arrBaiduCproConfig['ct'] ='#000000';
arrBaiduCproConfig['url'] ='#666666';
arrBaiduCproConfig['bdl'] ='#EDF0F5';
arrBaiduCproConfig['rad'] =1;
]]&gt;</script><script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"></script><script type="text/javascript"><!-- 
document.write(baiduCproIFrame()); 
--></script><iframe marginwidth="0" marginheight="0" src="http://cpro.baidu.com/cpro/ui/uijs.php?&amp;uid=309462&amp;n=chinaunix888_cpr&amp;tm=20&amp;cm=0&amp;um=26&amp;rsi0=728&amp;rsi1=90&amp;wn=4&amp;hn=3&amp;rssl0=right&amp;rssl1=bottom&amp;rsi2=0&amp;rss0=%23EDF0F5&amp;rss1=%23EDF0F5&amp;rss2=%230000ff&amp;rss3=%23000000&amp;rss4=%23666666&amp;rss5=%23EDF0F5&amp;rad=1&amp;word=http%3A%2F%2Fwww.chinaunix.net%2Fjh%2F26%2F138695.html" frameborder="0" width="728" scrolling="no" height="90" allowtransparency=""></iframe><!---广告　结- --></td>
						</tr>
				</tbody>
		</table>
		<!-- 正文end -->
<img src ="http://www.blogjava.net/wsbjwjt/aggbug/48793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wsbjwjt/" target="_blank">wsbjwjt</a> 2006-05-29 17:14 <a href="http://www.blogjava.net/wsbjwjt/archive/2006/05/29/48793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>