JSP 标准标记库(JSP Standard Tag LibraryQJSTLQ是一个实?Web 应用E序中常见的通用功能的定制标记库集,q些功能包括q代和条件判断、数据管理格式化、XML 操作以及(qing)数据库访问。在 developerWorks 上其新系列的W一文章中QY件工E师 Mark Kolb 向?zhn)展示了(jin)如何?JSTL 标记来避免在 JSP 面中用脚本编制元素。?zhn)q将?jin)解如何通过从表C层删除源代码来化Y件维护。最后,(zhn)将?jin)?JSTL l过化的表达式语aQ它允许在不必用功能齐全的~程语言的情况下?JSTL 操作指定动态属性倹{?/blockquote>
JavaServer PagesQJSPQ是用于 J2EE q_的标准表C层技术。JSP 技术提供了(jin)用于执行计算Q这些计用来动态地生成面内容Q的脚本~制元素和操作。脚本编制元素允许在 JSP 面中包括程序源代码Q在为响应用戯求而呈现页面时可以执行q些源代码。操作将计算操作装到很?HTML ?XML 标记的标CQJSP 面的模板文本通常包含q些标记。JSP 规范只将几种操作定义成了(jin)标准Q但?JSP 1.1 开始,开发h员已l能够以定制标记库的方式创徏其自q操作?jin)?/p>
JSP 标准标记库(JSTLQ是 JSP 1.2 定制标记库集Q这些标记库实现大量服务器端 Java 应用E序常用的基本功能。通过为典型表C层dQ如数据格式化和q代或条件内容)(j)提供标准实现QJSTL ?JSP 作者可以专注于特定于应用程序的开发需求,而不是ؓ(f)q些通用操作“另L(fng)灶”?/p>
当然Q?zhn)可以使?JSP 脚本~制元素Qscriptlet、表辑ּ和声明)(j)来实现此cMQ务。例如,可以使用三个 scriptlet 实现条g内容Q清?1 中着重显CZ(jin)q三?scriptlet。但是,因ؓ(f)脚本~制元素依赖于在面中嵌入程序源代码Q通常?Java 代码Q,所以对于用这些脚本编制元素的 JSP 面Q其软gl护d的复杂度大大增加?jin)。例如,清单 1 中的 scriptlet CZ严格C赖于花括L(fng)正确匚w。如果不l意间引入了(jin)一个语法错误,则条件内容中的嵌套其?scriptlet 可能?x)造成严重破坏Qƈ且在 JSP 容器~译该页面时Q要使所产生的错误信息有意义可能?x)很困难?/p>
清单 1. 通过 scriptlet 实现条g内容
<% if (user.getRole() == "member")) { %>
<p>Welcome, member!</p>
<% } else { %>
<p>Welcome, guest!</p>
<% } %>
|
修正此类问题通常需要相当丰富的~程l验。尽通常?x)由十分_N页面布局和图形设计的设计人员来开发和l护 JSPQ但是同一面中的脚本~制元素出现问题Ӟ需要程序员的介入。这U状况将单个文g中代码的责Q分担l多人,因而得开发、调试和增强此类 JSP 面成ؓ(f)很麻?ch)的d。通过常用功能包装到定制标记库的标准集合中,JSTL ?JSP 作者可以减对~制脚本元素的需求,甚至可以不需要它们,q免了(jin)相关的维护成本?/p>
JSTL 1.0
JSTL 1.0 发布?2002 q?6 月,由四个定制标记库Q?core
?format
?xml
?sql
Q和一寚w用标记库验证器Q?ScriptFreeTLV
?PermittedTaglibsTLV
Q组成?core
标记库提供了(jin)定制操作Q通过限制?jin)作用域的变量管理数据,以?qing)执行面内容的P代和条g操作。它q提供了(jin)用来生成和操?URL 的标记。顾名思义Q?format
标记库定义了(jin)用来格式化数据(其是数字和日期Q的操作。它q支持用本地化资源束进?JSP 面的国际化?xml
库包含一些标讎ͼq些标记用来操作通过 XML 表示的数据,?sql
库定义了(jin)用来查询关系数据库的操作?
两个 JSTL 标记库验证器允许开发h员在?JSP 应用E序中强制用编码标准。可以配|?ScriptFreeTLV
验证器以?JSP 面中禁用各U类型的 JSP 脚本元素 ?scriptlet、表辑ּ和声明。类似地Q?PermittedTaglibsTLV
验证器可以用来限制可能由应用E序?JSP 面讉K的定制标记库集(包括 JSTL 标记库)(j)?
管 JSTL 最l将?x)成?J2EE q_的必需lgQ但目前只有数应用E序服务器包括它。JSTL 1.0 的参考实现可作ؓ(f) Apache 软g基金?x)(Apache Software FoundationQ的 Jakarta Taglibs 目Q请参阅 参考资?/font>Q的一部分而获得。可以将该参考实C的定制标记库合ƈCQ何支?JSP 1.2 ?Servlet 2.3 规范的服务器Q以d?JSTL 的支持?
表达式语a
?JSP 1.2 中,可以使用?rn)态字W串或表辑ּQ如果允许的话)(j)指定 JSP 操作的属性。例如,在清?2 中,?<jsp:setProperty>
操作?name
?property
属性指定了(jin)?rn)态|而用表达式指定了(jin)?value
属性。这个操作的效果是将h参数的当前D予命名的 bean Ҏ(gu)。以q种形式使用的表辑ּ被称?h时属性|request-time attribute valueQ?/i>Q这是构建到 JSP 规范中的用于动态指定属性值的唯一机制?
清单 2. 合ƈh时属性值的 JSP 操作
<jsp:setProperty name="user" property="timezonePref"
value='<%= request.getParameter("timezone") %>'/>
|
因ؓ(f)h时属性值是用表辑ּ指定的,所以它们往往有和其它脚本元素一L(fng)软gl护问题。因此,JSTL 定制标记支持另一U用于指定动态属性值的机制。可以用化的 表达式语aQELQ而不使用完整?JSP 表达式来指定 JSTL 操作的属性倹{EL 提供?jin)一些标识符、存取器和运符Q用来检索和操作ȝ?JSP 容器中的数据。EL 在某U程度上?EcmaScriptQ请参阅 参考资?/font>Q和 XML 路径语言QXML Path LanguageQXPathQؓ(f)基础Q因此页面设计h员和E序员都应该熟?zhn)它的语法。EL 擅长L对象?qing)其?gu),然后对它们执行简单操作;它不是编E语aQ甚至不是脚本编制语a。但是,?JSTL 标记一起用时Q它?yu)p使用单而又方便的符h表示复杂的行为。EL 表达式的格式是这L(fng)Q用元W号Q?Q定界,内容包括在花括号Q{}Q中Q如清单 3 所C?
清单 3. 说明 EL 表达式定界符?JSTL 操作
<c:out value="${user.firstName}"/>
|
此外Q?zhn)可以多个表辑ּ与?rn)态文本组合在一起以通过字符串ƈ|来构造动态属性|如清?4 所C。单独的表达式由标识W、存取器、文字和q算W组成。标识符用来引用存储在数据中?j)中的数据对象。EL ?11 个保留标识符Q对应于 11 ?EL 隐式对象。假定所有其它标识符都引?限制?jin)作用域的变?/i>。存取器用来(g)索对象的Ҏ(gu)或集合的元素。文字表C固定的??数字、字W、字W串、布?yu)(dng)型或空倹{运符允许Ҏ(gu)据和文字q行l合以及(qing)比较?
清单 4. l合?rn)态文本和多个 EL 表达式以指定动态属性?/b>
<c:out value="Hello ${user.firstName} ${user.lastName}"/>
|
限制?jin)作用域的变?/font>
JSP API 通过 <jsp:useBean>
操作允许?JSP 容器内的四个不同作用域中存储和检索数据。JSTL 通过提供用于指定和除去这些作用域中的对象的附加操作来扩展q一能力。此外,EL 提供这些对象作为限制了(jin)作用域的变量q行(g)索的内置支持。特别地QQ何出现在 EL 表达式中但不对应于Q?EL 隐式对象的标识符Q都被自动假定ؓ(f)引用存储在四?JSP 作用域的其中某个中的对象Q这四个作用域是Q?
- 面作用?
- h作用?
- ?x)话作用?
- 应用E序作用?
(zhn)可能还记得Q只有在为特定请求处理页面期间才能检索存储在该页面作用域中的对象。如果对象是存储在请求作用域中的Q可以在处理所有参与处理某h的页面期间检索这些对象(譬如在对某个h的处理中遇到?jin)一个或多个 <jsp:include>
?<jsp:forward>
操作Q。如果对象是存储在会(x)话作用域中的Q则在与 Web 应用E序的交互式?x)话期间Q可以由用户讉K的Q何页面检索它Q即Q直C该用户交互相兌?HttpSession
对象无效为止Q。可以由M用户从Q何页面访问存储在应用E序作用域中的对象,直到卸蝲 Web 应用E序本n为止Q通常是由于关?JSP 容器所_(d)(j)?
通过字W串映射为期望作用域中的对象来将对象存储到该作用域。然后,可以通过提供相同字符串来从该作用域检索该对象。在作用域的映射中查扑֭W串Qƈq回被映的对象。在 Servlet API 中,此cd象称为相应作用域?属?/i>。但是,?EL 的上下文中,也将与属性相兌的字W串看作变量的名Uͼ该变量通过属性映的方式获得特定的倹{?
?EL 中,与隐式对象无兌的标识符被认为是存储在四?JSP 作用域中的名U对象。首先对面作用域检查是否存在这L(fng)标识W,其次对请求作用域、然后对?x)话作用域、最后对应用E序作用域依ơ进行这L(fng)(g)查,然后试该标识符的名U是否与存储在该作用域中的某个对象的名称匚w。第一个这L(fng)匚w作ؓ(f) EL 标识W的Dq回。通过q种Ҏ(gu)Q可以将 EL 标识W看作引用限制了(jin)作用域的变量?/p>
从更技术的斚w来说Q没有映到隐式对象的标识符是用 PageContext
实例?findAttribute()
Ҏ(gu)求值的Q该实例表示寚w面的处理Q在该页面上Q当前正在处理用于请求的表达式。标识符的名UC为参C递给q个Ҏ(gu)Q然后该Ҏ(gu)依次在四个作用域中搜索具有相同名U的属性。ƈ所扑ֈ的第一个匹配项作ؓ(f) findAttribute()
Ҏ(gu)的D回。如果未在这四个作用域中扑ֈq样的属性,则返?null
?
最l,限制?jin)作用域的变量是四?JSP 作用域的属性,q些属性具有可以用?EL 标识W的名称。只要对限制?jin)作用域的变量赋予由字母数字l成的名Uͼ可以通过 JSP 中提供的用于讄属性的M机制来创建它们。这包括内置?<jsp:useBean>
操作Q以?qing)?Servlet API 中的几个cd义的 setAttribute()
Ҏ(gu)。此外,四个 JSTL 库中定义的许多定制标记本w就能够讄作ؓ(f)限制?jin)作用域的变量用的属性倹{?
隐式对象
?1 中列Z(jin) 11 ?EL 隐式对象的标识符。不要将q些对象?JSP 隐式对象Q一共只有九(ji)个)(j)hQ其中只有一个对象是它们所共有的?/p>
?1. EL 隐式对象
cd
|
标识W?/b>
|
描述
|
JSP |
pageContext
|
PageContext 实例对应于当前页面的处理 |
作用?/td>
|
pageScope
|
与页面作用域属性的名称和值相兌?Map c? |
requestScope
|
与请求作用域属性的名称和值相兌?Map c? |
sessionScope
|
与会(x)话作用域属性的名称和值相兌?Map c? |
applicationScope
|
与应用程序作用域属性的名称和值相兌?Map c? |
h参数 |
param
|
按名U存储请求参数的主要值的 Map c? |
paramValues
|
请求参数的所有g?String 数组存储?Map c? |
h?/td>
|
header
|
按名U存储请求头主要值的 Map c? |
headerValues
|
请求头的所有g?String 数组存储?Map c? |
Cookie |
cookie
|
按名U存储请求附带的 cookie ?Map c? |
初始化参?/td>
|
initParam
|
按名U存?Web 应用E序上下文初始化参数?Map c? |
管 JSP ?EL 隐式对象中只有一个公共对象( pageContext
Q,但通过 EL 也可以访问其?JSP 隐式对象。原因是 pageContext
拥有讉K所有其它八?JSP 隐式对象的特性。实际上Q这是将它包括在 EL 隐式对象中的主要理由?
其余所?EL 隐式对象都是映射Q可以用来查扑֯应于名称的对象。前四个映射表示先前讨论的各U属性作用域。可以用它们来查扄定作用域中的标识W,而不用依赖于 EL 在缺省情况下使用的顺序查找过E?/p>
接下来的四个映射用来获取h参数和请求头的倹{因?HTTP 协议允许h参数和请求头h多个|所以它们各有一Ҏ(gu)。每对中的第一个映返回请求参数或头的主要|通常是恰巧在实际h中首先指定的那个倹{每对中W二个映允许检索参数或头的所有倹{这些映中的键是参数或头的名称Q但q些值是 String
对象的数l,其中的每个元素都是单一参数值或头倹{?
cookie 隐式对象提供?jin)对p求设|的 cookie 名称的访问。这个对象将所有与h相关联的 cookie 名称映射到表C那?cookie Ҏ(gu)的 Cookie
对象?
最后一?EL 隐式对象 initParam
是一个映,它储存(sh) Web 应用E序相关联的所有上下文的初始化参数的名U和倹{初始化参数是通过 web.xml
部v描述W文件指定的Q该文g位于应用E序?WEB-INF
目录中?
存取?/font>
因ؓ(f) EL 标识W是作ؓ(f)隐式对象或限制了(jin)作用域的变量Q通过属性来实现Q解析的Q因此有必要它们{换成 Java 对象。EL 可以自动包装和解包其相应?Java cM的基本类型(例如Q可以在后台?int
强制转换?Integer
c,反之亦可Q,但大多数的标识符成为指向完整的 Java 对象的指针?
l果是,对这些对象的Ҏ(gu)或Q在对象是数l和集合的情况下Q对其元素的讉K通常是o(h)人满意的。就Z(jin)实现q种用途,EL 提供?jin)两U不同的存取器(点运符Q?.
Q和Ҏ(gu)可符Q?[]
Q)(j)Q也支持通过 EL 操作Ҏ(gu)和元素?
点运符通常用于讉K对象的特性。例如,在表辑ּ ${user.firstName}
中,使用点运符来访?user
标识W所引用对象的名?firstName
的特性。EL 使用 Java bean U定讉K对象Ҏ(gu),因此必须定义q个Ҏ(gu)的 getter Ҏ(gu)Q通常是名?getFirstName()
的方法)(j)Q以便表辑ּ正确求倹{当被访问的Ҏ(gu)本w是对象Ӟ可以递归地应用点q算W。例如,如果我们虚构?user
对象有一个实Cؓ(f) Java 对象?address
Ҏ(gu),那么也可以用点运符来访问这个对象的Ҏ(gu)。例如,表达?${user.address.city}
会(x)q回q个地址对象嵌套?city
Ҏ(gu)?
Ҏ(gu)可符用来(g)索数l和集合的元素。在数组和有序集合(也即Q实C(jin) java.util.List
接口的集合)(j)的情况下Q把要检索的元素的下标放在方括号中。例如,表达?${urls[3]}
q回 urls
标识W所引用的数l或集合的第四个元素Q和 Java 语言以及(qing) JavaScript 中一PEL 中的下标是从零开始的Q?
对于实现 java.util.Map
接口的集合,Ҏ(gu)可符使用兌的键查找存储在映中的倹{在Ҏ(gu)号中指定键,q将相应的g辑ּ的D回。例如,表达?${commands["dir"]}
q回?commands
标识W所引用?Map
中的 "dir"
键相兌的倹{?
对于上述两种情况Q都可允许表辑ּ出现在方括号中。对嵌套表达式求值的l果被作ؓ(f)下标或键Q用来检索集合或数组的适当元素。和点运符一PҎ(gu)可符也可以递归应用。这使得 EL 能够从多l数l、嵌套集合或两者的Ll合中检索元素。此外,点运符和方括号q算W还可以互操作。例如,如果数组的元素本w是对象Q则可以使用Ҏ(gu)可符来检索该数组的元素,q结合点q算W来(g)索该元素的一个特性(例如 ${urls[3].protocol}
Q?
假定 EL 充当指定动态属性值的化语aQEL 存取器有一个有的功能Q与 Java 语言的存取器不同Q,那就是它们在应用?null
时不抛出异常。如果应?EL 存取器的对象Q例如, ${foo.bar}
?${foo["bar"]}
中的 foo
标识W)(j)?null
Q那么应用存取器的结果也?null
。事实证明,在大多数情况下,q是一个相当有用的行ؓ(f)Q不久?zhn)׃?x)?jin)解q一炏V?
最后,点运符和方括号q算W可能实现某U程度的互换。例如,也可以?${user["firstName"]}
来检?user
对象?firstName
Ҏ(gu),正如可以?${commands.dir}
获取?commands
映射中的 "dir"
键相兌的g栗?
q算W?/font>
EL q可以通过使用标识W和存取器,遍历包含应用E序数据Q通过限制?jin)作用域的变量公开Q或关于环境的信息(通过 EL 隐式对象Q的对象层次l构。但是,只是讉Kq些数据Q通常不以实现许?JSP 应用E序所需的表C逻辑?/p>
最l,EL q包括了(jin)几个用来操作和比?EL 表达式所讉K数据的运符。表 2 中汇M(jin)q些q算W?/p>
?2. EL q算W?/font>
cd
|
q算W?/b>
|
术q算W?/td>
|
+ ?- ?* ?/ Q或 div Q和 % Q或 mod Q? |
关系q算W?/td>
|
== Q或 eq Q?!= Q或 ne Q?< Q或 lt Q?> Q或 gt Q?<= Q或 le Q和 >= Q或 ge Q? |
逻辑q算W?/td>
|
&& Q或 and Q?|| Q或 or Q和 ! Q或 not Q? |
验证q算W?/td>
|
empty
|
术q算W支持数值的加法、减法、乘法和除法。还提供?jin)一个求余运符。注Q除法和求余q算W都有替代的、非W号的名Uͼ为的是与 XPath 保持一_(d)(j)。清?5 中显CZ(jin)一个演C算术运符用法的示例表辑ּ。对几个 EL 表达式应用算术运符的结果是该术q算W应用于q些表达式返回的数值所得的l果?/p>
清单 5. 利用术q算W的 EL 表达?/b>
${item.price * (1 + taxRate[user.address.zipcode])}
|
关系q算W允许比较数字或文本数据。比较的l果作ؓ(f)布尔D回。逻辑q算W允许合q布?yu)(dng)|q回新的布尔倹{因此,可以?EL 逻辑q算W应用于嵌套的关pL逻辑q算W的l果Q如清单 6 所C?/p>
清单 6. 利用关系和逻辑q算W的 EL 表达?/b>
${(x >= min) && (x <= max)}
|
最后一U?EL q算W是 empty
Q它对于验证数据特别有用?empty
q算W采用单个表辑ּ作ؓ(f)其变量(也即Q?${empty input}
Q,q返回一个布?yu)(dng)|该布?yu)(dng)DC对表达式求值的l果是不是“空”倹{求值结果ؓ(f) null
的表辑ּ被认为是I,x(chng)元素的集合或数组。如果参数是寚w度ؓ(f)零的 String
求值所得的l果Q则 empty
q算W也返?true
?
?3 昄?EL q算W的优先U。正如清?5 ?6 所C,可以用圆括号对表辑ּ分组Q高?sh)普通的优先U规则?/p>
?3. EL q算W优先Q自到底,从左到右Q?/font>
[] , . |
()
|
unary - ?not ?! ?empty |
* ?/ ?div ?% ?mod |
+ 、binary - |
() <</code> ?> ?<= ?>= ?lt ?gt ?le ?ge |
== ?!= ?eq ?ne |
&& ?and |
|| ?or |
文字
?EL 表达式中Q数字、字W串、布?yu)(dng)值和 null
都可以被指定为文字倹{字W串可以用单引号或双引号定界。布?yu)(dng)D指定?true
?false
?
Taglib 伪指?/font>
正如我们先前讨论的,JSTL 1.0 包括四个定制标记库。ؓ(f)?jin)演C?JSTL 标记和表辑ּ语言的交互,我们研I几个来?JSTL core
库的标记。和使用M JSP 定制标记库一P必须在?zhn)惌使用q个库标记的M面中包?taglib
伪指令。清?7 昄?jin)用于这个特定库的伪指o(h)?
清单 7. 用于 JSTL core ?EL 版本?taglib 伪指?/b>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
|
实际上,对应?JSTL core
库的 taglib
伪指令有两种Q因为在 JSTL 1.0 中,EL 是可选的。所有四?JSTL 1.0 定制标记库都有?JSP 表达式(而不?ELQ指定动态属性值的备用版本。因些备用库依赖?JSP 的更传统的请求时属性|所以它们被UCؓ(f) RT库,而那些用表辑ּ语言的则被称?EL 库。开发h员用不同?taglib
伪指令来区分每个库的q两个版本。清?8 昄?jin)?core 库的 RT 版本的伪指o(h)。但是,׃现在我们讨论的重Ҏ(gu) ELQ所以首先需要这些伪指o(h)?
清单 8. 用于 JSTL core ?RT 版本?taglib 伪指?/b>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>
|
变量标记
我们首先要考虑?JSTL 定制标记?<c:set>
操作。正如已l说明的Q限制了(jin)作用域的变量?JSTL 中v关键作用Q?<c:set>
操作提供Z标记的机制来创徏和设|限制了(jin)作用域的变量。清?9 中显CZ(jin)该操作的语法Q其?var
属性指定了(jin)限制?jin)作用域的变量的名称Q?scope
属性表明了(jin)该变量驻留在哪个作用域中Q?value
属性指定了(jin)分配l该变量的倹{如果指定变量已l存在,则简单地所指明的Dl它。如果不存在Q则创徏新的限制?jin)作用域的变量,q用该值初始化q个变量?
清单 9. <c:set> 操作的语?/b>
<c:set var="
name" scope="
scope" value="
expression"/>
|
scope
属性是可选的Q其~省值是 page
?
清单 10 中显CZ(jin) <c:set>
的两个示例。在W一个示例中Q将?x)话作用域变量设|成 String
倹{在W二个示例中Q用表达式来讄数|(x)页面作用域内名?square
的变量赋gؓ(f)名ؓ(f) x
的请求参数的值的qx(chng)?
清单 10. <c:set> 操作CZ
<c:set var="timezone" scope="session" value="CST"/>
<c:set var="square" value="${param['x'] * param['x']}"/>
|
(zhn)还可以限制了(jin)作用域的变量的值指定ؓ(f) <c:set>
操作的主体内容,而不是用属性。用这U方法,(zhn)可以重新编写清?10 中的W一个示例,如清?11 所C。此外,正如我们马上可以看到的, <c:set>
标记的主体内Ҏ(gu)w也可以使用定制标记?<c:set>
M内生成的所有内定w作Z?String
Dl指定变量?
清单 11. 通过M内容指定 <c:set> 操作的?/b>
<c:set var="timezone" scope="session">CST</c:set>
|
JSTL core 库包含第二个用于理限制?jin)作用域的变量的标??<c:remove>
。顾名思义Q?<c:remove>
操作是用来删除限制了(jin)作用域的变量的,它获取两个属性?var
属性指定待删除变量的名Uͼ scope
属性是可选的Q它表示待删除变量来自哪个作用域Q缺省ؓ(f) page
Q如清单 12 所C?
清单 12. <c:remove> 操作CZ
<c:remove var="timezone" scope="session"/>
|
输出
管 <c:set>
操作允许表辑ּl果赋给限制?jin)作用域的变量,但开发h员通常?x)希望只昄表达式的|而不存储它。JSTL <c:out>
定制标记承担q一dQ其语法如清?13 所C。该标记对由?value
属性指定的表达式进行求|然后打印l果。如果指定了(jin)可选属?default
Q那么,在对 value
属性的表达式求值所得结果ؓ(f) null
或空 String
的情况下Q?<c:out>
打印其倹{?
清单 13. <c:out> 操作的语?/b>
<c:out value="
expression" default="
expression" escapeXml="
boolean"/>
|
escapeXml
属性也是可选的。它控制当用 <c:out>
标记输出诸如?lt;”、?gt;”和?amp;”之cȝ字符Q在 HTML ?XML 中具有特D意义)(j)时是否应该进行{义。如果将 escapeXml
讄?trueQ则?x)自动将q些字符转换成相应的 XML 实体Q此处提到的字符分别转换?<
?>
?&
Q?
例如Q假定有一个名?user
的会(x)话作用域变量Q它是一个类的实例,该类为用户定义了(jin)两个Ҏ(gu):(x) username
?company
。每当用戯问站Ҏ(gu)Q这个对象被自动分配l会(x)话,但直到用户实际登录后Q才?x)设|这两个Ҏ(gu)。假定是q种Ҏ(gu)Q请考虑清单 14 中的 JSP 片段。在用户d之后Q这个片D将昄单词“Hello”,其后是他Q她的用户名和一个惊叹号。但是,在用L(fng)录之前,p个片D는成的内容则是短语“Hello Guest!”。在q种情况下,因ؓ(f) username
Ҏ(gu)还有待初始化,所?<c:out>
标记{而打印出 default
属性的|卛_W串“Guest”)(j)?
清单 14. 带缺省内容的 <c:out> 操作CZ
Hello <c:out value="${user.username}" default=="Guest"/>!
|
接下来,考虑清单 15Q它使用?<c:out>
标记?escapeXml
属性。如果在q种情况下已l将 company
Ҏ(gu)设|成 Java String
?"Flynn & Sons"
Q那么,实际上该操作生成的内容将?Flynn & Sons
。如果这个操作是生成 HTML ?XML 内容?JSP 面的一部分Q那么,q个字符串中间的?amp;”符hl可能被解释?HTML ?XML 控制字符Q从而妨了(jin)对该内容的显C或解析。但是,如果?escapeXml
属性D|成 true
Q则所生成的内容将?Flynn & Sons
。浏览器或解析器不会(x)因在解释旉到这U内容而出问题。假?HTML ?XML ?JSP 应用E序中最常见的内容类型,所?escapeXml
属性的~省值是 true
׃ؓ(f)奇了(jin)?
清单 15. 用转义?<c:out> 操作CZ
<c:out value="${user.company}" escapeXml=="false"/>
|
用缺省D|变?/font>
除了(jin)化动态数据的昄之外Q当通过 <c:set>
讄变量值时Q?<c:out>
指定~省值的能力也很有用。正?清单 11 所C,用来赋给限制?jin)作用域的变量的值可以指定ؓ(f) <c:set>
标记的主体内容,也可以通过其值属性来指定。通过?<c:out>
操作嵌套?<c:set>
标记的主体内容中Q变量赋值就可以利用其缺省D力?
清单 16 中说明了(jin)q种Ҏ(gu)。外?<c:set>
标记的行为非常简单:(x)它根据其M内容讄?x)话作用?timezone
变量的倹{但是,在这U情况下Q主体内Ҏ(gu)通过 <c:out>
操作生成的。这个嵌套操作的值属性是表达?${cookie['tzPref'].value}
Q它?yu)试通过 cookie
隐式对象q回名ؓ(f) tzPref
?cookie 倹{( cookie
隐式对象?cookie 名称映射到相应的 Cookie
实例Q这意味着必须通过对象?value
Ҏ(gu)用点q算W来(g)索储存在 cookie 中的实际数据。)(j)
清单 16. 合ƈ <c:set> ?<c:out> 以提供缺省变量?/b>
<c:set var="timezone" scope=="session">
<c:out value="${cookie['tzPref'].value}" default=="CST"/>
</c:set>
|
但是Q请考虑以下情况Q用hW一ơ尝试用这D代码的 Web 应用E序。结果是Q请求中没有提供名ؓ(f) tzPref
?cookie。这意味着使用隐式对象的查扑ְq回 null
Q在q种情况下整个表辑ּ返?null
。因为对 <c:out>
标记?value
属性求值的l果?null
Q所?<c:out>
标记?x){而输出对?default
属性求值的l果。在q里是字W串 CST
。因此,实际的结果是?timezone
限制?jin)作用域的变量设|成用户?tzPref
cookie 中存储的时区Q或者,如果没有Q则使用~省时区 CST
?
|
EL ?JSP 2.0
目前Q表辑ּ语言仅可用于指定 JSTL 定制标记中的动态属性倹{但 JSTL 1.0 表达式语a的一个扩展已l被提出Q会(x)把它包括?JSP 2.0 中去Q眼下正在进行最后评审。这个扩展将允许开发h员通过自己的定制标记来使用 EL。页面作者将可以在目前允怋?JSP 表达式的M地方使用 EL 表达式,譬如动态值插入模板文本中Q?<p>Your preferred time zone is ${timezone}</p> ?
q个 JSP 2.0 功能Q就?JSTL 本n一P(j)支持页面作者进一步减对 JSP ~制脚本元素的依赖,从而改q?JSP 应用E序的可l护性?
|
|
l束?/font>
ELQ与四个 JSTL 定制标记库提供的操作l合hQ允?dng)R面作者不使用脚本元素卛_实现表示层逻辑。例如,Ҏ(gu)本文开?清单 1 中的 JSP 代码和清?17 中显C的通过 JSTL 实现的同样功能。(JSTL core
库中其余的标讎ͼ包括 <c:choose>
?qing)其子标讎ͼ在本系列的下一文章中讨论。)(j)管昄执行?jin)条仉辑Q但?JSTL 版本中没?Java 语言源代码,q且标记之间的关p(其是关于嵌套需求)(j)对于M_N?HTML 语法的h都应该是熟?zhn)的?
清单 17. 合ƈ <c:set> ?<c:out> 以提供缺省变量?/b>
<c:choose><c:when test="${user.role == 'member'}">
<p>Welcome, member!</p>
</c:when><c:otherwise>
<p>Welcome, guest!</p>
</c:otherwise></c:choose>
|
通过提供大多?Web 应用E序常用功能的标准实玎ͼJSTL 有助于加速开发周期。与 EL l合hQJSTL 可以不需要对表示层程序编写代码,q极大地化了(jin) JSP 应用E序的维护?/p>

]]>