??xml version="1.0" encoding="utf-8" standalone="yes"?>
向一个Web站点发送POSTh只需要简单的几步。首先要和URL下的URLConnection对话。URLConnection可以很容易的从URL得到。比如:
// Using java.net.URL and
//java.net.URLConnection
URL url = new
URL("http://jobsearch.dice.com/jobsearch/jobsearch.cgi");
URLConnection connection = url.openConnection();
然后把连接设出模式。URLConnection通常作ؓ输入来用,比如下蝲一个Webc通过把URLConnection设ؓ输出Q你可以把数据向你个Web传送。下面是如何做:
...
connection.setDoOutput(true);
最后,Z得到OutputStreamQ简单v见,把它U束在Writerq且攑օPOST信息中,例如Q?nbsp;
...
OutputStreamWriter out = new
OutputStreamWriter(uc.getOutputStream(), "8859_1");
out.write("username=bob&password="+password+"");
// remember to clean up
out.flush();
out.close();
q样可以发送一个看h象这LPOSTQ?nbsp;
POST /jobsearch/jobsearch.cgi HTTP 1.0
ACCEPT: text/plain
Content-type: application/x-www-form-urlencoded
Content-length: 99
username=bob
password=someword
一旦发送成功,用以下方法就可以得到服务器的回应Q?nbsp;
connection.getInputStream();
一些Web站点用POST形式而不是GETQ这是因为POST能够携带更多的数据,而且不用URLQ这使得它看h不那么庞大。用上面列出的大致的代码,Java代码可以和这些站点轻杄实现对话?img src ="http://www.tkk7.com/georgehill/aggbug/6660.html" width = "1" height = "1" />
]]>
?nbsp; ? 如何让JBuilderX昄中文
发信? BBS 水木清华?(Wed Nov 26 13:42:26 2003), 转信
扑ֈ
Documents and Settings\Administrator\.primetimeX目录下面?BR>user_zh.properties文g
扑ֈ
...
editor.display;fixed_fonts.1=Courier New
editor.display;fixed_fonts.2=Lucida Sans Typewriter
...
大约是在240行吧
自己手动d
editor.display;fixed_fonts.3=“字体名U?BR>注意Q?BR>字体名称必须是下?BR>editor.display;known_fonts中列出的字体名称
依次cLQ可以添加许多字体,
dDialogInput, Monospaced字体可以显CZ?/P>
--
扑ֈ
Documents and Settings\Administrator\.primetimeX目录下面?BR>user_zh.properties文g
扑ֈ
...
editor.display;fixed_fonts.1=Courier New
editor.display;fixed_fonts.2=Lucida Sans Typewriter
...
大约是在240行吧
自己手动d
editor.display;fixed_fonts.3=“字体名U?BR>注意Q?BR>字体名称必须是下?BR>editor.display;known_fonts中列出的字体名称
依次cLQ可以添加许多字体,
dDialogInput, Monospaced字体可以显CZ?/P>
--
?来源:·BBS 水木清华?smth.org·[FROM: 61.48.8.24]
发信? huili (好h), 信区: Java
?nbsp; ? JBuilderx解决中文问题Ҏ(gu)
发信? BBS 水木清华?(Wed Dec 17 08:17:59 2003), 转信
转自 http://www.chinajavaworld.net/forum/topic.cgi?forum=22&topic=5186&show=0
关闭JBuilderXQ修?JBuilderX\bin 目录下的 jbuilder.config 文gQ??BR># applications
vmparam -Xms32m
vmparam -Xmx256m
后添加一?BR>vmparam -Dprimetime.editor.useVariableWidthFont=true
保存后,删除Documents and Settings\Administrator目录下的 .primetimeX文g夹和
.jbuilderX文g夹,然后启动JBuilderX卛_?/P>
中文及光标定位问题全部解?BR>呵呵
转自 http://www.chinajavaworld.net/forum/topic.cgi?forum=22&topic=5186&show=0
关闭JBuilderXQ修?JBuilderX\bin 目录下的 jbuilder.config 文gQ??BR># applications
vmparam -Xms32m
vmparam -Xmx256m
后添加一?BR>vmparam -Dprimetime.editor.useVariableWidthFont=true
保存后,删除Documents and Settings\Administrator目录下的 .primetimeX文g夹和
.jbuilderX文g夹,然后启动JBuilderX卛_?/P>
中文及光标定位问题全部解?BR>呵呵
--
?来源:·BBS 水木清华?smth.org·[FROM: 202.194.156.137]
软g工程?BR>2003 q?8 ?11 ?/P>
Web应用E序的标志是多个子系l的集成。SQL和XML是在q类子系l之间交换数据的两种最通用的机制。在本文中,Mark Kolb介绍讉KJSP面数据库和XML内容的sql和xml库ƈ对JSTLq行了ȝ?/BLOCKQUOTE>Web应用E序的模板式QstereotypicalQ架构分Z层:处理h的Web服务器、实施业务逻辑的应用程序服务器以及理怹性数据的数据库。应用程序和数据库层之间的联接通常采用关系数据库中的SQL调用格式。当业务逻辑被写入到Java语言中时QJDBC用于实现q些调用?
如果应用E序调用与其它服务器(本地或远E?的集成,我们需要用于在不同子系l之间交换数据的更深层次的机制。在Web应用E序内部和应用程序之间传送数据采用的来普遍的一U方法是XML文g的交换?
q今为止Q在我们的JSTL之旅中,我们讨论了JSTL 表达式语aQexpression languageQELQ和 core?fmt标记库。在最后一部分Q我们将考虑sql和xml?-正如它们的名字表C的一?-- 提供定制标记来接入和理从SQL数据库和XML文g索到的数据?
不要遗漏本系列的其它部分
W?部分,?表达式语a?(2003q??W?部分Q?探讨核心?2003q??
W?部分Q?表示是一切(Presentation is everythingQ?(2003q??
xml?/SPAN>
Ҏ(gu)设计QXML提供灉|的方式来表示l构化数据,q些数据同时准备q行验证Q因此它?yu)其适应于在松散联合的系l之间交换数据。这反过来其成为Web应用E序极具吸引力的集成技术?与用XML表示的数据进行交互的W一步是把数据作Z个XML文gQ对其进行检索ƈq行分解Q以创徏数据l构来接入该文g中的内容。在分解文g后,(zhn)可以有选择的对其进行{换以创徏新的XML文gQ?zhn)可以?gu)的XML文gq行相同的操作。最l,文g中的数据可以被提取,然后昄或用作入数据来q行其它操作?/P>
q些步骤都在用于控制XML的JSTL标记中反映出。根据我们在W?部分 探讨核心中所讨论的,我们使用core库中?lt;c:import>标记来检索XML文g。然后?lt;x:parse>标记来分解该文gQ支持标准的XML分解技术,如文件对象模式(Document Object ModelQDOM)和简单XML APIQSimple API for XMLQSAX)?lt;x:transform>标记可用于{换XML文gq依赖标准技术来转换XML数据Q扩展样式表语言Q?Extensible Stylesheet LanguageQ?/I>XSL)。最后,我们提供多个标记来接入和控制分解后的XML数据Q但是所有这一切都依赖于另一U标? XML路径语言QXML Path LanguageQ?/I>XPath)Q以引用分解后的XML文g中的内容?
分解XML
<x:parse>标记有多U格式,取决于用户希望的分解cd。这一Ҏ(gu)作最基本的格式用以下语法:
<x:parse xml=" expression" var=" name" scope=" scope" filter=" expression" systemId=" expression"/>
在这五种属性中Q只有xml属性是需要的Q其值应该是包含要分解的XML文g的字W串Q或者是java.io.Reader实例Q通过它可以读取要被分解的文g。此外,(zhn)可以用以下语法,Ҏ(gu)<x:parse>标记的主体内Ҏ(gu)规定要被分解的文Ӟ
<x:parse var=" name" scope=" scope" filter=" expression" systemId=" expression"> body content </x:parse>
var和scope属性规定存储分解后的文件的scoped变量。然后xml库中的其它标记可以用这一变量来运行其它操作。注意,当var?scope 属性存在时QJSTL用于表示分解后的文g的数据结构类型以实施为导向,从而厂商可以对其进行优化?
如果应用E序需要对JSTL提供的分解后的文件进行处理,它可以用另一U格式的<x:parse>Q它要求分解后的文g坚持使用一个标准接口。在q种情况下,该标记的语法如下Q?
<x:parse xml=" expression" varDom=" name" scopeDom=" scope" filter=" expression" systemId=" expression"/>
当?zhn)使?lt;x:parse>的这一版本Ӟ表示分解后的XML文g的对象必M用org.w3c.dom.Document接口。当Ҏ(gu)<x:parse>中的M内容来规定XML文gӞ(zhn)还可以使用varDom和scopeDom属性来代替var ?scope属性,语法如下Q?/P>
<x:parse varDom=" name" scopeDom=" scope" filter=" expression" systemId=" expression"> body content </x:parse>
其它两个属性filter ?systemId 可以实现对分解流E的_控制。filter 属性规定org.xml.sax.XMLFiltercȝ一个实例,以在分解之前Ҏ(gu)件进行过滤。如果要被分解的文g非常大,但目前的工作只需要处理一部分内Ҏ(gu)q一属性尤其有用。systemId属性表C被分解的文g的URIq解析文件中出现的Q何相关的路径。当被分解的XML文g使用相关的URL来引用分解流E中需要接入的其它文g或资源时需要这U属?/P>
清单1展示?lt;x:parse> 标记的用,包括?<c:import>的交互。此?lt;c:import> 标记用于索众所周知的Slashdot Web |站的RDF Site Summary (RSS)反馈Q然后?lt;x:parse>分解表示RSS 反馈的XML文gQ表C分解后的文件的以实施ؓ导向的数据结构被保存到名为rss的变量(带有page 范围Q中?
清单1Q?lt;x:parse>?lt;c:import>的交?/B>
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/>
转换XML
XML通过XSL样式表来转换。JSTL使用<x:transform>标记来支持这一操作。与<x:parse>的情况一P<x:transform> 标记支持多种不同的格式?lt;x:transform> 最基本的格式的语法是:
<x:transform xml=" expression" xslt=" expression" var=" name" scope=" scope" xmlSystemId=" expression" xsltSystemId=" expression"> <x:param name=" expression" value=" expression"/> ... </x:transform>
关于 RSS
RDF Site Summary (RSS) 是许多以新闻为导向的|站公布的XML文g格式Q它列出它们当前的标题,提供链接到相x章的URL。同P它提供在Web上联合新ȝ单机制。关于RSS的更详细信息Q请参阅 参考资?/A>?此处Qxml 属性规定要被{换的文gQxslt 属性规定定义这ơ{换的样式表。这两种属性是必要的,其它属性ؓ可选?
?lt;x:parse>的xml属性一P<x:transform>的xml 属性值可以是包含XML文g的字W串Q或者是接入q类文g的Reader。此外,它还可以采用 org.w3c.dom.Document cLjavax.xml.transform.Source cȝ实例格式。最后,它还可以是?lt;x:parse> 操作的var或varDom属性分配的变量倹{?
而且Q?zhn)可以?gu)<x:transform> 操作的主体内Ҏ(gu)包含要被转换的XML文g。在q种情况下,<x:transform> 的语法是Q?
<x:transform xslt=" expression" var=" name" scope=" scope" xmlSystemId=" expression" xsltSystemId=" expression"> body content <x:param name=" expression" value=" expression"/> ... </x:transform>
在这两种情况下,规定XSL 样式表的xslt 属性应是字W串、Reader或javax.xml.transform.Source实例?
如果var 属性存在,转换后的XML文g分配给相应的scoped变量Q作为org.w3c.dom.Document cȝ一个实例。通常Qscope属性规定这cd量分配的范围?
<x:transform> 标记q支持将转换l果存储到javax.xml.transform.Result cȝ一个实例中Q而不是作为org.w3c.dom.Document的一个实例。如果var ?scope 属性被省略Qresult对象规定作ؓresult属性的|<x:transform>标记用该对象来保存应用该样式表的l果。清?中介l了使用<x:transform> 的result属性的q两U语法的变化Q?
清单2Q用result属性来提供javax.xml.transform.Result实例Ӟ<x:transform>操作的语法变?/B>
<x:transform xml=" expression" xslt=" expression" result=" expression" xmlSystemId=" expression" xsltSystemId=" expression"> <x:param name=" expression" value=" expression"/> ... </x:transform> <x:transform xslt=" expression" result=" expression" xmlSystemId=" expression" xsltSystemId=" expression"> body content <x:param name=" expression" value=" expression"/> ... </x:transform>
无论(zhn)采用这两种<x:transform>格式中的那一U,(zhn)都必须从定制标记单独创建javax.xml.transform.Result对象。该对象自n作ؓresult属性的值提供?
如果既不存在var 属性,也不存在result属性,转换的结果将单地插入到JSP面Q作为处?lt;x:transform> 操作的结果。当样式表用于将数据从XML转换成HTML时尤其有用,如清?所C:
清单3Q在JSP面直接昄转换的XML数据
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <c:import var="rssToHtml" url="/WEB-INF/xslt/rss2html.xsl"/> <x:transform xml="${rssFeed}" xslt="${rssToHtml}"/>
在本例中Q?<c:import> 标记来读取RSS反馈和适当的样式表。样式表的输出结果是HTMLQ通过忽略<x:transform>的var和result 属性来直接昄。图1昄了实例结果:
?lt;x:parse>的systemId 属性一P<x:transform>的xmlSystemId ?xsltSystemId 属性用于解析XML文g中相关的路径。在q种情况下,xmlSystemId 属性应用于Ҏ(gu)标记?xml属性值提供的文gQ而xsltSystemId 属性用于解析根据标记的xslt属性规定的样式表中的相兌\径?
如果正在推动文g转换的样式表使用了参敎ͼ我们使用<x:param> 标记来规定这些参数。如果参数存在,那么q些标记必须?lt;x:transform> 标记M内显C。如果根据主体内容规定了要被转换的XML文gQ那么它必须先于M <x:param> 标记?
<x:param> 标记有两U必要的属?-- name ?value -- p本系?W?部分 ?W?部分中讨论的<c:param> ?<fmt:param> 标记一栗?
处理XML内容
XML文g的分解和转换操作都是Z整个文g来进行。但是,在?zhn)文件{换成一U可用的格式之后Q一应用程序通常只对文g中包含的一部分数据感兴。鉴于这一原因Qxml 库包括多个标记来接入和控制XML文g内容的各个部分?如果(zhn)已l阅M本系列第2部分( 探讨核心)Q?zhn)对q些xml 标记的名字非常熟(zhn)。它们都ZJSTL core 库相应的标记。但是,q些core 库标C用EL表达式,通过它们的value属性来接入JSP容器中的数据Q而它们在xml 库中的副本用XPath表达式,通过select属性接入XML文g中的数据?
XPath是引用XML文g中元素及它们的属性值和M内容的标准化W号。正如其名字代表的一Pq种W号与文件系l\径的表示Ҏ(gu)cMQ用短斜线来分开XPath语句的组分。这些组分对映于XML文g的节点,q箋的组分匹配嵌套的Element。此外,星号可以用于作ؓ通配W来匚w多个节点Q括号内的表辑ּ可以用于匚w属性值和规定索引。有多种在线参考资料介lXPath和它的??参考资?/A>)?
要显CXML文g的数据的一个ElementQ?lt;x:out> 操作Q它与core 库的<c:out> 标记cM?但是Q?lt;c:out> 使用名ؓvalue 和escapeXml的属性,<x:out> 的属性ؓselect 和escapeXmlQ?
<x:out select=" XPathExpression" escapeXml=" boolean"/>
当然Q两者的区别在于<x:out> 的select 属性值必LXPath表达式,?lt;c:out> 的value 属性必LEL表达式。两U标记的escapeXml 属性的意义是相同的?
清单4昄?lt;x:out> 操作的用。注意,规定用于select 属性的XPath表达式由一个EL表达式规定ؓscoped变量Q尤其是$rss。这一EL表达式根据将被求值的XPath语句来识别分解后的XML文g。该语句在此处查扑为title且父节点名ؓchannel的ElementQ从而选择它找到的W一个Element(Ҏ(gu)表达式尾部[1]索引规定)。这一<x:out> 操作的结果是昄q一Element的主体内容,关闭正在转义QEscapingQ的XML字符?
清单4Q?lt;x:out>操作来显CXML Element的主体内?/B>
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/> <x:out select="$rss//*[name()='channel']/*[name()='title'][1]" escapeXml="false"/>
除了<x:out>之外QJSTL xml 库包括以下控制XML数据的标讎ͼ
- <x:set> Q向JSTL scoped 变量分配XPath表达式的?
- <x:if> Q根据XPath表达式的布尔值来条g化内?
- <x:choose>?lt;x:when>?lt;x:otherwise>Q根据XPath表达式来实施互斥的条件化
- <x:forEach> QP代根据XPath表达式匹配的多个Elements
每个q些标记的操作与core库中相应的标记类伹{例如,清单5中显C的<x:forEach>的用, <x:forEach> 操作用于q代XML文g中表CRSS反馈的所有名为item 的Element。注意,<x:forEach>M内容中嵌套的两个<x:out> 操作中的XPath表达式与<x:forEach>标记正在q代的节点相兟뀂它们用于检索每个item element的子节点link ?title?
清单5Q?lt;x:out> ?lt;x:forEach>操作来选择和显CXML数据
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/> <a href="<x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/>" ><x:out select="$rss//*[name()='channel']/*[name()='title'][1]" escapeXml="false"/></a> <x:forEach select="$rss//*[name()='item']"> <li> <a href="<x:out select="./*[name()='link']"/>" ><x:out select="./*[name()='title']" escapeXml="false"/></a> </x:forEach>
清单5中JSPE序代码的输出结果与 清单3cMQ它??中显C。xml 库以XPath为导向的标记提供备选的样式表来转换XML内容Q尤其是当最后的输出l果是HTML的情c?
sql?/SPAN>
JSTLW?个也是最后一个操作是sql定制标记库。正如其名字代表的一P该库提供与关pL据库交互的标记。尤其是sql 库定义规定数据源、发布查询和更新以及查询和更新~组C务处理中的标记?Datasource
Datasource是获得数据库q接的工厂。它们经常实施某些格式的q接库来最大限度地降低与创建和初始化连接相关的开销。Java 2 Enterprise Edition (J2EE)应用E序服务器通常内置了Datasource支持Q通过 Java命名和目录接口( Java Naming and Directory InterfaceQJNDI)它可用于J2EE应用E序?JSTL的sql 标记依赖于Datasource来获得连接。实际上包括可选的dataSource 属性以明确规定它们的连接工厂作?javax.sql.DataSource 接口实例Q或作ؓJNDI名?
(zhn)可以?lt;sql:setDataSource> 标记来获得javax.sql.DataSource 实例Q它采用以下两种格式Q?
<sql:setDataSource dataSource=" expression" var=" name" scope=" scope"/> <sql:setDataSource url=" expression" driver=" expression" user=" expression" password=" expression" var=" name" scope=" scope"/>
W一U格式只需要dataSource 属性,而第二种格式只需要url 属性?
通过提供JNDI名作为dataSource属性|(zhn)可以用第一U格式来接入与JNDI名相关的datasource。第二种格式创建新的datasourceQ用作为url属性值提供的JDBC URL。可选的driver 属性规定实施数据库driver的类的名Uͼ同时需要时user ?password 属性提供接入数据库的登录证书?
对于<sql:setDataSource>的Q何一U格式而言Q可选的var ?scope 属性向scoped变量分配特定的datasource。如果var属性不存在Q那?<sql:setDataSource> 操作讄供sql 标记使用的缺?datasourceQ它们没有规定明的datasource?
(zhn)还可以使用javax.servlet.jsp.jstl.sql.dataSource 参数来配|sql 库的~省datasource。在实践中,在应用程序的Web.xml文g中添加与清单6中显C的cM的程序代码是规定~省datasource最方便的方式。?lt;sql:setDataSource> 来完成这一操作要求使用JSP面来初始化该应用程序,因此可以以某U方式自动运行这一面?
清单6Q用JNDI名来讄JSTL在web.xml部v描述W中的缺省datasource
<context-param> <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name> <param-value>jdbc/blog</param-value> </context-param>
提交查询和更?/SPAN>
在徏立了datasource接入之后Q?zhn)可以使?lt;sql:query> 操作来执行查询,同时使用<sql:update> 操作来执行数据库更新。查询和更新使用SQL语句来规定,它可以是使用ZJDBC的java.sql.PreparedStatement 接口的方法来实现参数化。参数g用嵌套的<sql:param> ?<sql:dateParam> 标记来规定?支持以下三种<sql:query> 操作Q?
<sql:query sql=" expression" dataSource=" expression" var=" name" scope=" scope" maxRows=" expression" startRow=" expression"/> <sql:query sql=" expression" dataSource=" expression" var=" name" scope=" scope" maxRows=" expression" startRow=" expression"> <sql:param value=" expression"/> ... </sql:query> <sql:query dataSource=" expression" var=" name" scope=" scope" maxRows=" expression" startRow=" expression"> SQL statement <sql:param value=" expression"/> ... </sql:query>
前两U格式只要求sql ?var 属性,W三U格式只要求var 属性?
var ?scope 属性规定存储查询结果的scoped 变量。maxRows 属性可以用于限制查询返回的行数QstartRow 属性允许忽略一些最开始的行数(如当l果集(Result setQ由数据库来构徏时忽??
在执行了查询之后Q结果集被分配给scoped变量Q作为javax.servlet.jsp.jstl.sql.Result 接口的一个实例。这一对象提供接入行、列名称和查询的l果集大的属性,如表1所C:
?Qjavax.servlet.jsp.jstl.sql.Result 接口定义的属?/SPAN>
属?/B> 说明 rows 一排SortedMap 对象Q每个对象对映列名和l果集中的单?/TD> rowsByIndex 一排数l,每个对应于结果集中的单行 columnNames 一排对l果集中的列命名的字W串Q采用与rowsByIndex属性相同的序 rowCount 查询l果中总行?/TD> limitedByMaxRows 如果查询受限于maxRows 属性gؓ?/TD> 在这些属性中Qrows 其方便Q因为?zhn)可以使用它来在整个结果集中进行P代和Ҏ(gu)名字讉K列数据。我们在 清单7中阐qCq一操作Q查询的l果被分配到名ؓqueryResults的scoped变量中,然后使用core 库中?lt;c:forEach>标记来P代那些行。嵌套的<c:out> 标记利用EL内置的Map 攉支持来查找与列名U相对应的行数据?记得?W?部分 Q?{row.title}?{row["title"]} 是相{的表达式?
清单7q展CZ使用<sql:setDataSource> 来关联datasource 和scoped变量Q它?lt;sql:query> 操作通过其dataSource 属性随后接入?
清单7Q?lt;sql:query>来查询数据库Q?lt;c:forEach>来P代整个结果集
<sql:setDataSource var="dataSrc" url="jdbc:mysql:///taglib" driver="org.gjt.mm.mysql.Driver" user="admin" password="secret"/> <sql:query var="queryResults" dataSource="${dataSrc}"> select * from blog group by created desc limit ? <sql:param value="${6}"/></sql:query> <table border="1"> <tr> <th>ID</th> <th>Created</th> <th>Title</th> <th>Author</th> </tr> <c:forEach var="row" items="${queryResults.rows}"> <tr> <td><c:out value="${row.id}"/></td> <td><c:out value="${row.created}"/></td> <td><c:out value="${row.title}"/></td> <td><c:out value="${row.author}"/></td> </tr> </c:forEach> </table>
?昄了清?中JSTLE序代码的实例页面输出结果。注意:清单7?lt;sql:query>操作M中出现的SQL语句为参数化语句?
?lt;sql:query> 操作中,SQL语句Ҏ(gu)M内容来规定,或者用?字符Q通过sql 属性实现参数化。对于SQL语句中每个这L参数来说Q应有相应的<sql:param> ?<sql:dateParam> 操作嵌套?lt;sql:query> 标记的主体中?lt;sql:param> 标记只采用一U属?-- value --来规定参数倹{此外,当参数gؓ字符串时Q?zhn)可以忽略value 属性ƈҎ(gu)<sql:param> 标记的主体内Ҏ(gu)提供参数倹{?
表示日期、时间或旉戳的参数g?lt;sql:dateParam> 标记来规定,使用以下语法Q?
<sql:dateParam value=" expression" type=" type"/>
对于<sql:dateParam>来说Qvalue 属性的表达式必L java.util.Date cd例的|同时type 属性值必Ldate、time或timestampQ由SQL语句需要那cM旉相关的值来军_?
?lt;sql:query> 一P<sql:update> 操作支持三种格式Q?
<sql:update sql=" expression" dataSource=" expression" var=" name" scope=" scope"/> <sql:update sql=" expression" dataSource=" expression" var=" name" scope=" scope"> <sql:param value=" expression"/> ... </sql:update> <sql:update dataSource=" expression" var=" name" scope=" scope"> SQL statement <sql:param value=" expression"/> ... </sql:update>
sql 和dataSource 属性有?lt;sql:query>相同?lt;sql:update> 语义。同Pvar ?scope 属性可以用于规定scoped变量Q但在这U情况下Q分配给scoped变量的值将是java.lang.Integer 的一个实例,昄作ؓ数据库更新结果而更改的行数?
理事务处理
事务处理用于保护作ؓ一个组必须成功或失败的一pd数据库操作。事务处理支持已l嵌入到JSTL的sql 库中Q通过相应的<sql:query>?lt;sql:update>操作嵌套?lt;sql:transaction>标记的主体内容中Q从而将一pd查询和更新操作打包到一个事务处理中也就昑־微不道了?<sql:transaction> 语法如下Q?
<sql:transaction dataSource=" expression" isolation=" isolationLevel"> <sql:query .../> or <sql:update .../> ...
<sql:transaction> 操作没有必需的属性。如果?zhn)忽略了dataSource 属性,那么使用JSTL的缺省datasource。isolation 属性用于规定事务处理的隔离U别Q它可以是read_committed、read_uncommitted、repeatable_read或serializable。如果?zhn)未规定这一属性,事务处理用datasource的缺省隔ȝ别?
(zhn)可能希望所有嵌套的查询和更新必M用与事务处理相同的datasource。实际上Q嵌套到<sql:transaction>操作中的<sql:query> ?<sql:update> 不能用于规定dataSource 属性。它?yu)自动用与周围?lt;sql:transaction>标记相关的datasource (显性或隐??
清单8昄了如何?lt;sql:transaction> 的一个实例:
清单Q?lt;sql:transaction>来将数据库更新联合到事务处理?/B>
<sql:transaction> <sql:update sql="update blog set title = ? where id = ?"> <sql:param value="New Title"/> <sql:param value="${23}"/> </sql:update> <sql:update sql="update blog set last_modified = now() where id = ?"> <sql:param value="${23}"/> </sql:update> </sql:transaction>
注意事项
JSTL的xml ?sql 库用定制标讎ͼ从而能够在JSP面上实施复杂的功能Q但是在(zhn)的表示层实施这cd能可能不是最好的Ҏ(gu)?对于多位开发h员长期编写的大型应用E序来说Q实践证明,用户接口、基本的业务逻辑和数据仓库之间的严格分离能够长期化Y件维护。广泛流行的模式/视图/控制器( Model-View-ControllerQMVCQ设计模板是q一“最佛_践”的公式化。在J2EE Web应用E序领域中,模式是应用程序的业务逻辑Q视图是包含表示层的JSP面?控制器是form handlers和其它服务器端机Ӟ使浏览器操作能够开始更Ҏ(gu)式ƈ随后更新视图? MVC规定应用E序的三个主要elements--模式、视囑֒控制?--怺之间有最的相关性,从而限制相互之间的交互到统一、精心定义的接口?
应用E序依赖XML文g来进行数据交换以及关pL据库来提供数据永久性都是应用程序业务逻辑Q也是其模式)的特征。因此,使用MVC设计模板无需在应用程序的表示层(也就是其视图Q反映这些实施细节。如果JSP用于实施表示层,那么使用 xml ?sql 库将q反MVCQ因为它们的使用意味着在表C层内暴露基本业务逻辑的elements?
鉴于q一原因Qxml ?sql 库最适用于小型项目和原型工作。应用程序服务器对JSP面的动态编译也使得q些库中的定制标记可以用于作试工兗?
l束?/SPAN>
在本pd中,我们讨论?个JSTL定制标记库的功能及它们的使用。在 W?部分 ?W?部分Q我们讨论通过El和core 库标记的使用Q?zhn)如何在许多常见情况下避免JSP脚本E序?W?部分 x使用fmt 库来本地化Web内容?在最后一部分Q我们讨Zxml ?sql 库的功能。如果?zhn)愿意接受业务逻辑包含到表C层的结果,q两个库中的标记都其能够非常轻村֜XML文g和关pL据库中的内容l合到JSP面。这两个库还展示了当集成<sql:query> ?lt;c:forEach>ӞJSTL库如何构建和集成Q以及xml 库利?lt;c:import> 操作的能力?
- (zhn)可以参阅本文在 developerWorks 全球站点上的 英文原文.
- 下蝲Weblog实例应用E序?源代?/A>?
- JSTL Web site 是深入了解JSTL不错的v炏V?
- JSTL 1.0 Specification 是EL和四个JSTL标记库最权威的参考资料?
- Jakarta Taglibs 目是JSTL 1.0参考实现的主页?
- Shawn Bayern 撰写?JSTL in Action ManningQ?002 q_地讨Z由参考实现领导编写的全部 JSTL 功能?
- David Geary 是一位很受欢q的 Java ~程斚w的作者,他还著有一部关?JSTL 的书c,名ؓ Core JSTL (Prentice-Hall and Sun Microsystems Press, 2002)?
- JSPTags.com 是一?JSP 参考资料目录,它尤其着重于定制标记库方面的内容?
- Sun?Java Web Services Tutorial的一部分也涉及到了对 JSTL 的讨论?
- 阅读James Lewin的?RSS新闻反馈?/A>? developerWorks, 2000q?1?以了解更多关于RSS的信息?
- Mark Colan 在?Putting XSL transformations to work?( developerWorks, 2001q?0?提供了XSL的介l性概q?
- 参阅Parand Tony Darugar撰写的?Effective XML processing with DOM and XPath in Java? developerWorks, 2002q??以更好地了解XPath及其与文件对象模式( Document Object ModelQDOM)的关p?
- 通过动手实践指南?使用 JDBC 构徏Z Web 的应用程?/A>? developerWorks, 2001q?2?来全面了解JDBC?
- 通过学习?Using JSPs and custom tags within VisualAge for Java and WebSphere Studio?( WebSphere Developer Domain) Q动手实?WBOnlineQ这文章演CZ如何使用 servlet、JSP 面及定制标记库
- 通过Jeff Wilson的优U文章?使用定制标记控制 JSP 面?( developerWorksQ?002 q?1 月)来学习关于定制标记库的全部内宏V?
- Noel Bergman 的文章?JSP 标记库:着意设计的更好的可用?/A>”( developerWorksQ?001 q?12 月)向?zhn)昄了声明性标记是如何帮助改善 JSP 面的可用性?
- ?developerWorks Java 技术专?可以扑ֈ数百有?Java 技术的参考资料?
关于作?/SPAN>
Mark Kolb 是一位在德克萨斯州奥斯汀市(AustinQ工作的软g工程师。他常就服务器端 Java q一主题在业界演Ԍ而且q是 Web Development with JavaServer Pages, W二?/I> 一书的合著者。可以通过 mak@taglib.com?Mark联系?/TD>
]]>
软g工程?BR>2003 q?6 ?21 ?/P>
思义QJSP 标准标记库(JSP Standard Tag LibraryQJSTLQ? core
库ؓ一些基本功能(如,理限定了作用域的变量和?URL 交互{)和基本操作(如,q代和条件化Q提供了定制标记。这些标C仅可以由面设计人员直接利用Q而且qؓ与其?JSTL 库相l合从而提供更复杂的表C逻辑奠定了基。Mark Kolb 在本文中l箋?JSTL ?core
库进行探讨,研究用标记来协助控制和 URL 理?
Z演示 EL 的用法,我们介绍?core
库中的三个标讎ͼ <c:set>
?<c:remove>
?<c:out>
?<c:set>
?<c:remove>
用于理限定了作用域的变量;?<c:out>
用于昄数据Q尤其是昄?EL 计算出的倹{在此基上,接下来本文把注意力集中在 core
库的其余标记上,q些标记可以大致归ؓ两大cdQ流控制?URL 理?
CZ应用E序
Z演示 JSTL 标记Q我们将使用来自一个工作应用程序的CZQ本pd中余下的文章都将使用此应用程序。由于基?Java ?Weblog 日渐行及ؓZ所熟?zhn)Q因此我们将Z此目的用一个简单的Z Java ?WeblogQ参?参考资?/A>以下载该应用E序?JSP 面和源代码。WeblogQ也UCؓ blogQ是一U基?Web 的简短注释的日志Q这些注释是有关 Weblog 的作者所感兴的主题Q通常带有?Web 上其它地方的相关文章及讨论的链接。图 1 中显CZ该应用程序正在运行时的抓屏?
虽然完整的实现需要二十四?Java c,但在表示层中却只涉及 Weblog 应用E序中的两个c, Entry
?UserBean
。这P对于理解 JSTL CZ而言Q只有这两个cL较重要。图 2 昄?Entry
?UserBean
的类图?
Entry
c表C?Weblog 中一个标有日期的V其 id
属性用于在数据库中存储及检索该,?title
?text
属性则表示该项的实际内宏V?created
?lastModified
属性引用了 Java 语言?Date
cȝ两个实例Q分别用来表C最初创的旉和最后编辑该的旉?author
属性引用了标识该项的创的 UserBean
实例?
UserBean
cd储了有关应用E序的已认证用户的信息,如用户名、全名和电子邮g地址。该c还包含一个用于与相关数据库进行交互的 id
属性。其最后一个属?roles
引用一?String
|q列值标识与相应用户相关的、特定于应用E序的角艌Ӏ对?Weblog 应用E序Q相关的角色是“User”(所有应用程序用户常用的~省角色Q和“Author”(该角色指定可以创建和~辑 Weblog 的用户Q?
控?/SPAN>
׃可以?EL 替代 JSP 表达式来指定动态属性|因此面创作人员无需使用脚本~制元素。因本编制元素可能是引v JSP 面中维护问题的主要原因Q所?JSTL 的主要优点就在于提供了这L单(且标准)的替代方法?/P>
EL ?JSP 容器索数据,遍历对象层次l构Q然后对l果执行单的操作。不q,除了讉K和操作数据之外,JSP 脚本~制元素的另一个常见用法是控制。尤其是Q页面创作h员常借助 scriptlet 来实现P代或条g内容。然而,因ؓq样的操作超Z EL 的能力,所?core
库提供了几个定制操作来管理流控制Q其形式?q代?条g?/A>?异常处理?
q代
?Web 应用E序环境中,q代主要用于访存和显C数据集Q通常是以列表或表中的一pd行的形式昄。实现P代内容的主要 JSTL 操作?<c:forEach>
定制标记。该标记支持两种不同样式的P代:整数范围上的q代Q类?Java 语言?for
语句Q和集合上的q代Q类?Java 语言?Iterator
?Enumeration
c)?
q行整数范围q代用到了清?1 中所C的 <c:forEach>
标记的语法?begin
?end
属性要么是静态整数|要么是可以得出整数值的表达式。它们分别指定P代烦引的初始g及P代烦引的l止倹{当使用 <c:forEach>
在整数范围内q行q代Ӟq两个属性是必需的,而其它所有属性都是可选的?
|
当出?step
Ӟ它也必须是整数倹{它指定每次q代后烦引的增量。这Pq代索引?begin
属性的值开始,?step
属性的gؓ增量q行递增Q在q代索引过 end
属性的值时停止q代。注Q如果省略了 step
属性,那么步长~省?1?
如果指定?var
属性,那么会创徏一个带有指定名U的q定了作用域的变量Qƈ每ơP代的当前索引Dl该变量。这一限定了作用域的变量具有嵌套式可视??只可以在 <c:forEach>
标记体内对其q行讉K。(我们很快讨论可选属?varStatus
的用法。)清单 2 昄了对一l固定整数D行P代的 <c:forEach>
操作CZ?
|
如图 3 中所C,上面的示例代码生成了一张表Q显C前五个偶数及其qx。这是通过?begin
?step
属性值指定ؓ 2Q而将 end
属性值指定ؓ 10 实现的。此外,?var
属性创建用于存储烦引值的限定了作用域的变量, <c:forEach>
标记体内引用了该变量。尤其是Q用了一?<c:out>
操作来显C烦引及其^方,其中索引的^Ҏ(gu)使用一个简单的表达式计得来的?
在对集合的成员进行P代时Q用C <c:forEach>
标记的另一个属性: items
属性,清单 3 中显CZ该属性。当使用q种形式?<c:forEach>
标记Ӟ items
属性是唯一必需的属性?items
属性的值应该是一个集合,对该集合的成员进行P代,通常使用 EL 表达式指定倹{如果变量名U是通过 <c:forEach>
标记?item
属性指定的Q那么对于每ơP代该已命名变量都被l定到集合后l元素上?
|
<c:forEach>
标记支持 Java q_所提供的所有标准集合类型。此外,(zhn)可以用该操作来P代数l(包括基本cd数组Q中的元素。表 1 列出?items
属性所支持的所有倹{正如表的最后一行所指出的那PJSTL 定义了它自己的接?javax.servlet.jsp.jstl.sql.Result
Q用来P?SQL 查询的结果。(我们在本系列后面的文章中详l讨一功能。)
?1. <c:forEach> 标记?items 属性所支持的集?
items 的? |
所产生?item ? |
java.util.Collection |
调用 iterator() 所获得的元? |
java.util.Map |
java.util.Map.Entry 的实? |
java.util.Iterator |
q代器元?/TD> |
java.util.Enumeration |
枚D元素 |
Object 实例数组 |
数组元素 |
基本cd值数l?/TD> | l过包装的数l元?/TD> |
用逗号定界?String |
子字W串 |
javax.servlet.jsp.jstl.sql.Result |
SQL 查询所获得的行 |
可以使用 begin
?end
?step
属性来限定在P代中包含集合中哪些元素。和通过 <c:forEach>
q行数字q代的情形一P在P代集合中的元素时同样要维护一个P代烦引?<c:forEach>
标记实际上只处理那些与烦引值相对应的元素,q些索引g指定?begin
?end
?step
值相匚w?
清单 4 昄了用来P代集合的 <c:forEach>
标记。对于该 JSP 代码D, entryList
q一限定了作用域的变量被讄成了 Entry
对象列表Q确切的_ ArrayList
Q?<c:forEach>
标记依次处理列表中的每个元素Q将其赋l一个限定了作用域的变量 blogEntry
Q然后生成两个表??一个用?Weblog 的 title
Q另一个则用于该项 text
。这些特性是通过一对带有相?EL 表达式的 <c:out>
操作?blogEntry
变量索得到的。注Q由?Weblog 的标题和文本都可能包含 HTML 标记Q因此这两个 <c:out>
标记?escapeXml
属性都被设|成?false。图 4 昄了结果?
|
不论是对整数q是寚w合进行P代, <c:forEach>
剩余的属?varStatus
所L作用相同。和 var
属性一P varStatus
用于创徏限定了作用域的变量。不q,?varStatus
属性命名的变量q不存储当前索引值或当前元素Q而是赋予 javax.servlet.jsp.jstl.core.LoopTagStatus
cȝ实例。该cd义了一l特性,它们描述了P代的当前状态,?2 中列Zq些Ҏ(gu)?
Ҏ(gu)?/B> | Getter | 描述 |
current | getCurrent() |
当前q次q代的(集合中的Q项 |
index | getIndex() |
当前q次q代?0 开始的q代索引 |
count | getCount() |
当前q次q代?1 开始的q代计数 |
first | isFirst() |
用来表明当前q轮q代是否为第一ơP代的标志 |
last | isLast() |
用来表明当前q轮q代是否为最后一ơP代的标志 |
begin | getBegin() |
begin 属性? |
end | getEnd() |
end 属性? |
step | getStep() |
step 属性? |
清单 5 昄了关于如何?varStatus
属性的一个示例。这个示例修改了清单 4 中的代码Q将 Weblog 的~号d到显C?Weblog 标题QtitleQ的表行。它是通过?varStatus
属性指定一个|然后讉K所生成的限定了作用域的变量?count
Ҏ(gu)来实现q一点的。结果显C在?5 中?
|
?<c:forEach>
以外Q?core
库还提供了另一个P代标讎ͼ <c:forTokens>
。JSTL 的这个定制操作与 Java 语言?StringTokenizer
cȝ作用怼。清?6 中显C的 <c:forTokens>
标记除了?<c:forEach>
的面向集合版本多一个属性之外,其它属性都相同。对?<c:forTokens>
而言Q通过 items
属性指定要标记化的字符Ԍ而通过 delims
属性提供用于生成标记的一l定界符。和 <c:forEach>
的情形一P可以使用 begin
?end
?step
属性将要处理的标记限定为那些与相应索引值相匚w的标记?
|
条g?/SPAN>
对于包含动态内容的 Web 面Q?zhn)可能希望不同cd的用LC同Ş式的内容。例如,在我们的 Weblog 中,讉K者应该能够阅d,也许q应该能够提交反馈,但只有经q授权的用户才能公布新项Q或~辑已有内容?/P>
在同一?JSP 面内实现这L功能Q然后用条仉辑来根据每条请求控制所昄的内容,q样做常常能够改善实用性和软gl护?core
库提供了两个不同的条件化标记 ?<c:if>
?<c:choose>
?来实现这些功能?
<c:if>
是这两个操作中较单的一个,它简单地对单个测试表辑ּq行求|接下来,仅当对表辑ּ求出的gؓ true
Ӟ它才处理标记的主体内宏V如果求出的g?true
Q就忽略该标记的M内容。如清单 7 所C, <c:if>
可以通过?var
?scope
属性(它们所L作用和在 <c:set>
中所L作用一P选择测试结果赋l限定了作用域的变量。当试代h(hun)非常高昂Ӟq种能力ؓ有用Q可以将l果高速缓存在限定了作用域的变量中Q然后在随后?<c:if>
或其?JSTL 标记的调用中索该l果?
|
清单 8 昄了与 <c:forEach>
标记?LoopTagStatus
对象?first
Ҏ(gu)一起用的 <c:if>
。如?6 中所C,在这U情况下Q只?Weblog 的W一上昄q组的创徏日期Q而不在Q何其它项前面重复该日期?
|
如清?8 所C, <c:if>
标记为条件化内容的一些简单情形提供了一U非常简z的表示法。对于需要进行互斥测试来定应该昄什么内容的情况下,JSTL core
库还提供?<c:choose>
操作。清?9 中显CZ <c:choose>
的语法?
|
每个要测试的条g都由相应?<c:when>
标记来表C,臛_要有一?<c:when>
标记。只会处理第一个其 test
gؓ true
?<c:when>
标记体内的内宏V如果没有一?<c:when>
试q回 true
Q那么会处理 <c:otherwise>
标记的主体内宏V注Q尽如此, <c:otherwise>
标记却是可选的Q?<c:choose>
标记臛_可有一个嵌套的 <c:otherwise>
标记。如果所?<c:when>
试都ؓ false
Q而且又没有给?<c:otherwise>
操作Q那么不会处理Q?<c:choose>
标记的主体内宏V?
清单 10 昄了运?<c:choose>
标记的示例。在q里Q检索请求对象而获得协议信息(通过 EL ?pageContext
隐式对象Q,q用单的字符串比较对协议信息q行试。根据这些测试的l果Q会昄相应的文本消息?
|
异常处理
最后一个流控制标记?<c:catch>
Q它允许?JSP 面内进行初U的异常处理。更切地说Q在该标记的M内容中生的M异常都会被捕获ƈ被忽略(卻I不会调用标准?JSP 错误处理机制Q。然而,如果产生了一个异常ƈ且已l指定了 <c:catch>
标记的可选属?var
Q那么会异常赋l(h面作用域的Q指定的变量Q这使得能够在页面自w内部进行定刉误处理。清?11 昄?<c:catch>
的语法(E后?清单 18中给Z个示例)?
|
URL 操作
JSTL core
库中的其余标C要是关于 URL。这些标C的第一个被适当地命名ؓ <c:url>
标记Q用于生?URL。尤其是Q?<c:url>
提供了三个功能元素,它们在ؓ J2EE Web 应用E序构?URL 时特别有用:
清单 12 昄?<c:url>
标记的语法?value
属性用来指定基?URLQ然后在必要时标记对其进行{换。如果这个基?URL 以一个斜杠开始,那么会在它前面加?servlet 的上下文名称。可以?context
属性提供显式的上下文名U。如果省略该属性,那么׃用当?servlet 上下文的名称。这一点特别有用,因ؓ servlet 上下文名U是在部|期间而不是开发期间决定的。(如果q个基本 URL 不是以斜杠开始的Q那么就认ؓ它是一个相?URLQ这时就不必d上下文名U。)
|
URL 重写是由 <c:url>
操作自动执行的。如?JSP 容器到一个存储用户当前会话标识的 cookieQ那么就不必q行重写。但是,如果不存在这L cookieQ那?<c:url>
生成的所?URL 都会被重写以~码会话标识。注Q如果在随后的请求中存在适当?cookieQ那?<c:url>
停止重?URL 以包含该标识?
如果?var
属性提供了一个|q可以同时ؓ scope
属性提供一个相应的|q是可选的Q,那么生成的 URL 赋值给q个限定了作用域的指定变量。否则,用当前的 JspWriter
输出生成?URL。这U直接输出其l果的能力允?<c:url>
标记作ؓ值出玎ͼ例如Q作?HTML <a>
标记?href
属性的|如清?13 中所C?
|
最后,如果通过嵌套 <c:param>
标记指定了Q何请求参敎ͼ那么会使用 HTTP GET h的标准表C法它们的名称和值添加到生成?URL 后面。此外,q进?URL ~码Qؓ了生成有效的 URLQ将对这些参数的名称或g出现的Q何字W适当地进行{换。清?14 演示?<c:url>
的这U行为?
|
清单 14 中的 JSP 代码被部|到一个名?blog
?servlet 上下文,限定了作用域的变?searchTerm
的D讄?"core library"
。如果检到了会?cookieQ那么清?14 生成?URL 类g清单 15 中的 URL。注Q在前面d上下文名Uͼ而在后面附加h参数。此外, keyword
参数g的空格和 month
参数g的斜杠都被按?HTTP GET 参数的需要进行了~码Q确切地_I格被{换成?+
Q而斜杠被转换成了 %2F
序列Q?
|
当没有会?cookie Ӟ生成的结果如清单 16 中所C。同Pservlet 上下文被dC前面Q?URL ~码的请求参数被附加C后面。不q,除此以外q重写了基本 URL 以包含指定的会话标识。当览器发送用q种方式重写?URL hӞJSP 容器自动抽取会话标识Qƈ请求与相应的会话进行关联。这P需要会话管理的 J2EE 应用E序无需依赖由应用程序用户启用的 cookie 了?/P>清单 16. 没有会话 cookie 时生成的 URL
|
导入内容
JSP 有两U内|机制可以将来自不同 URL 的内容合q到一?JSP 面Q?include
伪指令和 <jsp:include>
操作。不q,不管是哪U机Ӟ要包含的内容都必d于与面本n相同?Web 应用E序Q或 servlet 上下文)。两个标C间的主要区别在于Q?include
伪指令在面~译期间合ƈ被包含的内容Q?<jsp:include>
操作却在h处理 JSP 面时进行?
从本质上Ԍ core
库的 <c:import>
操作是更通用、功能更强大?<jsp:include>
版本Q好像是 <jsp:include>
“服用了兴奋剂”的Q。和 <jsp:include>
一P <c:import>
也是一U请求时操作Q它的基本Q务就是将其它一?Web 资源的内Ҏ(gu)?JSP 面中。如清单 17 中所C,它的语法非常cM?<c:url>
的语法?
|
通过 url
属性指定将要导入内容的 URLQ这个属性是 <c:import>
的唯一一个必选属性。这里允怋用相?URLQƈ且根据当前页面的 URL 来解析这个相?URL。但是,如果 url
属性的g斜杠开始,那么它就被解释成本地 JSP 容器内的l对 URL。如果没有ؓ context
属性指定|那么pLl对 URL 引用当前 servlet 上下文内的资源。如果通过 context
属性显式地指定了上下文Q那么就Ҏ(gu)指定?servlet 上下文解析绝对(本地QURL?
?<c:import>
操作q不仅仅限于讉K本地内容。也可以包含协议和L名的完整 URI 指定?url
属性的倹{实际上Q协议甚至不仅局限于 HTTP?<c:import>
?url
属性值可以?java.net.URL
cL支持的Q何协议。清?18 中显CZq种能力?
其中Q?<c:import>
操作用来包含通过 FTP 协议讉K的文档内宏V此外,q用了 <c:catch>
操作Q以便在本地处理 FTP 文g传送期间可能发生的M错误。错误处理是q样实现的:使用 <c:catch>
?var
属性ؓ异常指定一个限定了作用域的变量Q然后?<c:if>
查其倹{如果生了异常Q那么就会对那个限定了作用域的变量进行赋|如清?18 中的 EL 表达式所昄的那P该变量的值将 ?/I>会ؓI。由?FTP 文档的检索将会失败,因此会显C有兌U情늚错误消息?
|
<c:import>
操作的最后两个(可选的Q属性是 var
?scope
?var
属性会D从指?URL 获取的内容(作ؓ String
|被存储在一个限定了作用域的变量中,而不是包含在当前 JSP 面中?scope
属性控制该变量的作用域Q缺省情况下是页面作用域。如同我们在今后的文章中要看到的那PJSTL xml
库中的标记利用了 <c:import>
q种能力Q即整个文档存储在一个限定了作用域的变量中?
q要注意的是Q可以用(可选的Q嵌套的 <c:param>
标记来ؓ正在导入?URL 指定h参数。与?<c:url>
中嵌?<c:param>
标记一P必要时也要对参数名称和参数D?URL ~码?
h重定?/SPAN>
最后一?core
库标记是 <c:redirect>
。该操作用于向用L览器发?HTTP 重定向响应,它是 JSTL 中与 javax.servlet.http.HttpServletResponse
?sendRedirect()
Ҏ(gu)功能相当的标记。清?19 中显CZ该标记的 url
?context
属性,它们的行为分别等同于 <c:import>
?url
?context
属性的行ؓQ是嵌套M <c:param>
标记的结果?
|
清单 20 昄?<c:redirect>
操作Q它用一个到指定错误面的重定向代替了清?18 中的错误消息。在该示例中Q?<c:redirect>
标记的用法与标准 <jsp:forward>
操作的用法类伹{不q请回忆一下:通过h分派器进行{发是在服务器端实现的Q而重定向却是由浏览器来执行的。从开发h员的角度来讲Q{发比重定向更有效率,?<c:redirect>
操作却更灉|一些,因ؓ <jsp:forward>
只能分派到当?servlet 上下文内的其?JSP 面?
|
从用L角度来看Q主要区别在于重定向会更新浏览器所昄?URLQƈ因此影响书签的设|。{发却不这P它对最l用h透明的。这P选择 <c:redirect>
q是 <jsp:forward>
q取决于所期望的用户体验?
l束?/SPAN>
JSTL core
库含有多U通用的定制标讎ͼq大?JSP 开发h员都会用这些标记。例如,URL 和异常处理标记很好地补充了现有的 JSP 功能Q如 <jsp:include>
?<jsp:forward>
操作?include
伪指令以?page
伪指令的 errorpage
属性。P代和条g操作使得无需脚本~制元素p够实现复杂的表示逻辑Q尤其在变量标讎ͼ <c:set>
?<c:remove>
Q与 EL 相结合用时更是如此?
core
库中的几个标记?关于作?/SPAN> Mark Kolb 是一位在德克萨斯州奥斯汀市(AustinQ工作的软g工程师。他常就服务器端 Java q一主题在业界演Ԍ而且q是 Web Development with JavaServer Pages, W二?/I> 一书的合著者。可以通过 mak@taglib.com?Mark 联系?/TD> |
软g工程?BR>2003 q?5 ?27 ?/P>
JSP 标准标记库(JSP Standard Tag LibraryQJSTLQ是一个实?Web 应用E序中常见的通用功能的定制标记库集,q些功能包括q代和条件判断、数据管理格式化、XML 操作以及数据库访问。在 developerWorks 上其新系列的W一文章中QY件工E师 Mark Kolb 向?zhn)展示了如何?JSTL 标记来避免在 JSP 面中用脚本编制元素。?zhn)q将了解如何通过从表C层删除源代码来化Y件维护。最后,(zhn)将了解 JSTL l过化的表达式语aQ它允许在不必用功能齐全的~程语言的情况下?JSTL 操作指定动态属性倹{?/BLOCKQUOTE>JavaServer PagesQJSPQ是用于 J2EE q_的标准表C层技术。JSP 技术提供了用于执行计算Q这些计用来动态地生成面内容Q的脚本~制元素和操作。脚本编制元素允许在 JSP 面中包括程序源代码Q在为响应用戯求而呈现页面时可以执行q些源代码。操作将计算操作装到很?HTML ?XML 标记的标CQJSP 面的模板文本通常包含q些标记。JSP 规范只将几种操作定义成了标准Q但?JSP 1.1 开始,开发h员已l能够以定制标记库的方式创徏其自q操作了?/P>
JSP 标准标记库(JSTLQ是 JSP 1.2 定制标记库集Q这些标记库实现大量服务器端 Java 应用E序常用的基本功能。通过为典型表C层dQ如数据格式化和q代或条件内容)提供标准实现QJSTL ?JSP 作者可以专注于特定于应用程序的开发需求,而不是ؓq些通用操作“另L灶”?/P>
当然Q?zhn)可以使?JSP 脚本~制元素Qscriptlet、表辑ּ和声明)来实现此cMQ务。例如,可以使用三个 scriptlet 实现条g内容Q清?1 中着重显CZq三?scriptlet。但是,因ؓ脚本~制元素依赖于在面中嵌入程序源代码Q通常?Java 代码Q,所以对于用这些脚本编制元素的 JSP 面Q其软gl护d的复杂度大大增加了。例如,清单 1 中的 scriptlet CZ严格C赖于花括L正确匚w。如果不l意间引入了一个语法错误,则条件内容中的嵌套其?scriptlet 可能会造成严重破坏Qƈ且在 JSP 容器~译该页面时Q要使所产生的错误信息有意义可能会很困难?/P>清单 1. 通过 scriptlet 实现条g内容
<% if (user.getRole() == "member")) { %> <p>Welcome, member!</p> <% } else { %> <p>Welcome, guest!</p> <% } %>
修正此类问题通常需要相当丰富的~程l验。尽通常会由十分_N页面布局和图形设计的设计人员来开发和l护 JSPQ但是同一面中的脚本~制元素出现问题Ӟ需要程序员的介入。这U状况将单个文g中代码的责Q分担l多人,因而得开发、调试和增强此类 JSP 面成ؓ很麻烦的d。通过常用功能包装到定制标记库的标准集合中,JSTL ?JSP 作者可以减对~制脚本元素的需求,甚至可以不需要它们,q免了相关的维护成本?/P>
JSTL 1.0
JSTL 1.0 发布?2002 q?6 月,由四个定制标记库Q?core
?format
?xml
?sql
Q和一寚w用标记库验证器Q?ScriptFreeTLV
?PermittedTaglibsTLV
Q组成?core
标记库提供了定制操作Q通过限制了作用域的变量管理数据,以及执行面内容的P代和条g操作。它q提供了用来生成和操?URL 的标记。顾名思义Q?format
标记库定义了用来格式化数据(其是数字和日期Q的操作。它q支持用本地化资源束进?JSP 面的国际化?xml
库包含一些标讎ͼq些标记用来操作通过 XML 表示的数据,?sql
库定义了用来查询关系数据库的操作?两个 JSTL 标记库验证器允许开发h员在?JSP 应用E序中强制用编码标准。可以配|?
ScriptFreeTLV
验证器以?JSP 面中禁用各U类型的 JSP 脚本元素 ?scriptlet、表辑ּ和声明。类似地Q?PermittedTaglibsTLV
验证器可以用来限制可能由应用E序?JSP 面讉K的定制标记库集(包括 JSTL 标记库)?管 JSTL 最l将会成?J2EE q_的必需lgQ但目前只有数应用E序服务器包括它。JSTL 1.0 的参考实现可作ؓ Apache 软g基金会(Apache Software FoundationQ的 Jakarta Taglibs 目Q请参阅 参考资?/A>Q的一部分而获得。可以将该参考实C的定制标记库合ƈCQ何支?JSP 1.2 ?Servlet 2.3 规范的服务器Q以d?JSTL 的支持?
表达式语a
清单 2. 合ƈh时属性值的 JSP 操作
?JSP 1.2 中,可以使用静态字W串或表辑ּQ如果允许的话)指定 JSP 操作的属性。例如,在清?2 中,?<jsp:setProperty>
操作?name
?property
属性指定了静态|而用表达式指定了?value
属性。这个操作的效果是将h参数的当前D予命名的 bean Ҏ(gu)。以q种形式使用的表辑ּ被称?h时属性|request-time attribute valueQ?/I>Q这是构建到 JSP 规范中的用于动态指定属性值的唯一机制?
<jsp:setProperty name="user" property="timezonePref" value='<%= request.getParameter("timezone") %>'/>
因ؓh时属性值是用表辑ּ指定的,所以它们往往有和其它脚本元素一L软gl护问题。因此,JSTL 定制标记支持另一U用于指定动态属性值的机制。可以用化的 表达式语aQELQ而不使用完整?JSP 表达式来指定 JSTL 操作的属性倹{EL 提供了一些标识符、存取器和运符Q用来检索和操作ȝ?JSP 容器中的数据。EL 在某U程度上?EcmaScriptQ请参阅 参考资?/A>Q和 XML 路径语言QXML Path LanguageQXPathQؓ基础Q因此页面设计h员和E序员都应该熟?zhn)它的语法。EL 擅长L对象及其Ҏ(gu),然后对它们执行简单操作;它不是编E语aQ甚至不是脚本编制语a。但是,?JSTL 标记一起用时Q它?yu)p使用单而又方便的符h表示复杂的行为。EL 表达式的格式是这LQ用元W号Q?Q定界,内容包括在花括号Q{}Q中Q如清单 3 所C?
清单 3. 说明 EL 表达式定界符?JSTL 操作
<c:out value="${user.firstName}"/>
此外Q?zhn)可以多个表辑ּ与静态文本组合在一起以通过字符串ƈ|来构造动态属性|如清?4 所C。单独的表达式由标识W、存取器、文字和q算W组成。标识符用来引用存储在数据中心中的数据对象。EL ?11 个保留标识符Q对应于 11 ?EL 隐式对象。假定所有其它标识符都引?限制了作用域的变?/I>。存取器用来索对象的Ҏ(gu)或集合的元素。文字表C固定的??数字、字W、字W串、布?yu)型或空倹{运符允许Ҏ(gu)据和文字q行l合以及比较?
清单 4. l合静态文本和多个 EL 表达式以指定动态属性?/B>
<c:out value="Hello ${user.firstName} ${user.lastName}"/>
限制了作用域的变?/SPAN>
JSP API 通过<jsp:useBean>
操作允许?JSP 容器内的四个不同作用域中存储和检索数据。JSTL 通过提供用于指定和除去这些作用域中的对象的附加操作来扩展q一能力。此外,EL 提供这些对象作为限制了作用域的变量q行索的内置支持。特别地QQ何出现在 EL 表达式中但不对应于Q?EL 隐式对象的标识符Q都被自动假定ؓ引用存储在四?JSP 作用域的其中某个中的对象Q这四个作用域是Q?
- 面作用?
- h作用?
- 会话作用?
- 应用E序作用?
(zhn)可能还记得Q只有在为特定请求处理页面期间才能检索存储在该页面作用域中的对象。如果对象是存储在请求作用域中的Q可以在处理所有参与处理某h的页面期间检索这些对象(譬如在对某个h的处理中遇到了一个或多个
<jsp:include>
?<jsp:forward>
操作Q。如果对象是存储在会话作用域中的Q则在与 Web 应用E序的交互式会话期间Q可以由用户讉K的Q何页面检索它Q即Q直C该用户交互相兌?HttpSession
对象无效为止Q。可以由M用户从Q何页面访问存储在应用E序作用域中的对象,直到卸蝲 Web 应用E序本n为止Q通常是由于关?JSP 容器所_?通过字W串映射为期望作用域中的对象来将对象存储到该作用域。然后,可以通过提供相同字符串来从该作用域检索该对象。在作用域的映射中查扑֭W串Qƈq回被映的对象。在 Servlet API 中,此cd象称为相应作用域?属?/I>。但是,?EL 的上下文中,也将与属性相兌的字W串看作变量的名Uͼ该变量通过属性映的方式获得特定的倹{?
?EL 中,与隐式对象无兌的标识符被认为是存储在四?JSP 作用域中的名U对象。首先对面作用域检查是否存在这L标识W,其次对请求作用域、然后对会话作用域、最后对应用E序作用域依ơ进行这L查,然后试该标识符的名U是否与存储在该作用域中的某个对象的名称匚w。第一个这L匚w作ؓ EL 标识W的Dq回。通过q种Ҏ(gu)Q可以将 EL 标识W看作引用限制了作用域的变量?/P>
从更技术的斚w来说Q没有映到隐式对象的标识符是用
PageContext
实例?findAttribute()
Ҏ(gu)求值的Q该实例表示寚w面的处理Q在该页面上Q当前正在处理用于请求的表达式。标识符的名UC为参C递给q个Ҏ(gu)Q然后该Ҏ(gu)依次在四个作用域中搜索具有相同名U的属性。ƈ所扑ֈ的第一个匹配项作ؓfindAttribute()
Ҏ(gu)的D回。如果未在这四个作用域中扑ֈq样的属性,则返?null
?最l,限制了作用域的变量是四个 JSP 作用域的属性,q些属性具有可以用?EL 标识W的名称。只要对限制了作用域的变量赋予由字母数字l成的名Uͼ可以通过 JSP 中提供的用于讄属性的M机制来创建它们。这包括内置?
<jsp:useBean>
操作Q以及由 Servlet API 中的几个cd义的setAttribute()
Ҏ(gu)。此外,四个 JSTL 库中定义的许多定制标记本w就能够讄作ؓ限制了作用域的变量用的属性倹{?隐式对象
?1 中列Z 11 ?EL 隐式对象的标识符。不要将q些对象?JSP 隐式对象Q一共只有九(ji)个)hQ其中只有一个对象是它们所共有的?/P>
cd 标识W?/B> 描述 JSP pageContext
PageContext
实例对应于当前页面的处理作用?/TD> pageScope
与页面作用域属性的名称和值相兌? Map
c?requestScope
与请求作用域属性的名称和值相兌? Map
c?sessionScope
与会话作用域属性的名称和值相兌? 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 隐式对象提供了对p求设|的 cookie 名称的访问。这个对象将所有与h相关联的 cookie 名称映射到表C那?cookie Ҏ(gu)的
Cookie
对象?最后一?EL 隐式对象
initParam
是一个映,它储存与 Web 应用E序相关联的所有上下文的初始化参数的名U和倹{初始化参数是通过web.xml
部v描述W文件指定的Q该文g位于应用E序?WEB-INF
目录中?存取?/SPAN>
因ؓ EL 标识W是作ؓ隐式对象或限制了作用域的变量Q通过属性来实现Q解析的Q因此有必要它们{换成 Java 对象。EL 可以自动包装和解包其相应?Java cM的基本类型(例如Q可以在后台?int
强制转换?Integer
c,反之亦可Q,但大多数的标识符成为指向完整的 Java 对象的指针?l果是,对这些对象的Ҏ(gu)或Q在对象是数l和集合的情况下Q对其元素的讉K通常是o人满意的。就Z实现q种用途,EL 提供了两U不同的存取器(点运符Q?
.
Q和Ҏ(gu)可符Q?[]
Q)Q也支持通过 EL 操作Ҏ(gu)和元素?点运符通常用于讉K对象的特性。例如,在表辑ּ
${user.firstName}
中,使用点运符来访?user
标识W所引用对象的名?firstName
的特性。EL 使用 Java bean U定讉K对象Ҏ(gu),因此必须定义q个Ҏ(gu)的 getter Ҏ(gu)Q通常是名?getFirstName()
的方法)Q以便表辑ּ正确求倹{当被访问的Ҏ(gu)本w是对象Ӟ可以递归地应用点q算W。例如,如果我们虚构?user
对象有一个实Cؓ Java 对象?address
Ҏ(gu),那么也可以用点运符来访问这个对象的Ҏ(gu)。例如,表达?${user.address.city}
会q回q个地址对象嵌套?city
Ҏ(gu)?Ҏ(gu)可符用来索数l和集合的元素。在数组和有序集合(也即Q实C
java.util.List
接口的集合)的情况下Q把要检索的元素的下标放在方括号中。例如,表达?${urls[3]}
q回urls
标识W所引用的数l或集合的第四个元素Q和 Java 语言以及 JavaScript 中一PEL 中的下标是从零开始的Q?对于实现
java.util.Map
接口的集合,Ҏ(gu)可符使用兌的键查找存储在映中的倹{在Ҏ(gu)号中指定键,q将相应的g辑ּ的D回。例如,表达?${commands["dir"]}
q回?commands
标识W所引用?Map
中的"dir"
键相兌的倹{?对于上述两种情况Q都可允许表辑ּ出现在方括号中。对嵌套表达式求值的l果被作ؓ下标或键Q用来检索集合或数组的适当元素。和点运符一PҎ(gu)可符也可以递归应用。这使得 EL 能够从多l数l、嵌套集合或两者的Ll合中检索元素。此外,点运符和方括号q算W还可以互操作。例如,如果数组的元素本w是对象Q则可以使用Ҏ(gu)可符来检索该数组的元素,q结合点q算W来索该元素的一个特性(例如
${urls[3].protocol}
Q?假定 EL 充当指定动态属性值的化语aQEL 存取器有一个有的功能Q与 Java 语言的存取器不同Q,那就是它们在应用?
null
时不抛出异常。如果应?EL 存取器的对象Q例如,${foo.bar}
?${foo["bar"]}
中的foo
标识W)?null
Q那么应用存取器的结果也?null
。事实证明,在大多数情况下,q是一个相当有用的行ؓQ不久?zhn)׃了解q一炏V?最后,点运符和方括号q算W可能实现某U程度的互换。例如,也可以?
${user["firstName"]}
来检?user
对象?firstName
Ҏ(gu),正如可以?${commands.dir}
获取?commands
映射中的"dir"
键相兌的g栗?q算W?/SPAN>
EL q可以通过使用标识W和存取器,遍历包含应用E序数据Q通过限制了作用域的变量公开Q或关于环境的信息(通过 EL 隐式对象Q的对象层次l构。但是,只是讉Kq些数据Q通常不以实现许?JSP 应用E序所需的表C逻辑?/P>最l,EL q包括了几个用来操作和比?EL 表达式所讉K数据的运符。表 2 中汇Mq些q算W?/P>
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支持数值的加法、减法、乘法和除法。还提供了一个求余运符。注Q除法和求余q算W都有替代的、非W号的名Uͼ为的是与 XPath 保持一_。清?5 中显CZ一个演C算术运符用法的示例表辑ּ。对几个 EL 表达式应用算术运符的结果是该术q算W应用于q些表达式返回的数值所得的l果?/P>清单 5. 利用术q算W的 EL 表达?/B>
${item.price * (1 + taxRate[user.address.zipcode])}
关系q算W允许比较数字或文本数据。比较的l果作ؓ布尔D回。逻辑q算W允许合q布?yu)|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采用单个表辑ּ作ؓ其变量(也即Q?${empty input}
Q,q返回一个布?yu)|该布?yu)DC对表达式求值的l果是不是“空”倹{求值结果ؓnull
的表辑ּ被认为是I,x元素的集合或数组。如果参数是寚w度ؓ零的String
求值所得的l果Q则empty
q算W也返?true
??3 昄?EL q算W的优先U。正如清?5 ?6 所C,可以用圆括号对表辑ּ分组Q高于普通的优先U规则?/P>
[]
,.
()
unary -
?not
?!
?empty
*
?/
?div
?%
?mod
+
、binary-
() <</code>
?>
?<=
?>=
?lt
?gt
?le
?ge
==
?!=
?eq
?ne
&&
?and
||
?or
文字
?EL 表达式中Q数字、字W串、布?yu)值和null
都可以被指定为文字倹{字W串可以用单引号或双引号定界。布?yu)D指定?true
?false
?Taglib 伪指?/SPAN>
清单 7. 用于 JSTL core ?EL 版本?taglib 伪指?/B>
正如我们先前讨论的,JSTL 1.0 包括四个定制标记库。ؓ了演C?JSTL 标记和表辑ּ语言的交互,我们研I几个来?JSTLcore
库的标记。和使用M JSP 定制标记库一P必须在?zhn)惌使用q个库标记的M面中包?taglib
伪指令。清?7 昄了用于这个特定库的伪指o?
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
实际上,对应?JSTL
清单 8. 用于 JSTL core ?RT 版本?taglib 伪指?/B>core
库的taglib
伪指令有两种Q因为在 JSTL 1.0 中,EL 是可选的。所有四?JSTL 1.0 定制标记库都有?JSP 表达式(而不?ELQ指定动态属性值的备用版本。因些备用库依赖?JSP 的更传统的请求时属性|所以它们被UCؓ RT库,而那些用表辑ּ语言的则被称?EL 库。开发h员用不同?taglib
伪指令来区分每个库的q两个版本。清?8 昄了?core 库的 RT 版本的伪指o。但是,׃现在我们讨论的重Ҏ(gu) ELQ所以首先需要这些伪指o?
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>
变量标记
清单 9. <c:set> 操作的语?/B>
我们首先要考虑?JSTL 定制标记?<c:set>
操作。正如已l说明的Q限制了作用域的变量?JSTL 中v关键作用Q?<c:set>
操作提供Z标记的机制来创徏和设|限制了作用域的变量。清?9 中显CZ该操作的语法Q其?var
属性指定了限制了作用域的变量的名称Q?scope
属性表明了该变量驻留在哪个作用域中Q?value
属性指定了分配l该变量的倹{如果指定变量已l存在,则简单地所指明的Dl它。如果不存在Q则创徏新的限制了作用域的变量,q用该值初始化q个变量?
<c:set var=" name" scope=" scope" value=" expression"/>
scope
属性是可选的Q其~省值是page
?清单 10 中显CZ
清单 10. <c:set> 操作CZ<c:set>
的两个示例。在W一个示例中Q将会话作用域变量设|成String
倹{在W二个示例中Q用表达式来讄数|页面作用域内名?square
的变量赋gؓ名ؓx
的请求参数的值的qx?
<c:set var="timezone" scope="session" value="CST"/> <c:set var="square" value="${param['x'] * param['x']}"/>
(zhn)还可以限制了作用域的变量的值指定ؓ
清单 11. 通过M内容指定 <c:set> 操作的?/B><c:set>
操作的主体内容,而不是用属性。用这U方法,(zhn)可以重新编写清?10 中的W一个示例,如清?11 所C。此外,正如我们马上可以看到的,<c:set>
标记的主体内Ҏ(gu)w也可以使用定制标记?<c:set>
M内生成的所有内定w作Z?String
Dl指定变量?
<c:set var="timezone" scope="session">CST</c:set>
JSTL core 库包含第二个用于理限制了作用域的变量的标记 ?
清单 12. <c:remove> 操作CZ<c:remove>
。顾名思义Q?<c:remove>
操作是用来删除限制了作用域的变量的,它获取两个属性?var
属性指定待删除变量的名Uͼscope
属性是可选的Q它表示待删除变量来自哪个作用域Q缺省ؓpage
Q如清单 12 所C?
<c:remove var="timezone" scope="session"/>
输出
清单 13. <c:out> 操作的语?/B>
管<c:set>
操作允许表辑ּl果赋给限制了作用域的变量,但开发h员通常会希望只昄表达式的|而不存储它。JSTL<c:out>
定制标记承担q一dQ其语法如清?13 所C。该标记对由?value
属性指定的表达式进行求|然后打印l果。如果指定了可选属?default
Q那么,在对value
属性的表达式求值所得结果ؓnull
或空String
的情况下Q?<c:out>
打印其倹{?
<c:out value=" expression" default=" expression" escapeXml=" boolean"/>
escapeXml
属性也是可选的。它控制当用<c:out>
标记输出诸如?lt;”、?gt;”和?amp;”之cȝ字符Q在 HTML ?XML 中具有特D意义)时是否应该进行{义。如果将escapeXml
讄?trueQ则会自动将q些字符转换成相应的 XML 实体Q此处提到的字符分别转换?<
?>
?&
Q?例如Q假定有一个名?
清单 14. 带缺省内容的 <c:out> 操作CZuser
的会话作用域变量Q它是一个类的实例,该类为用户定义了两个Ҏ(gu):username
?company
。每当用戯问站Ҏ(gu)Q这个对象被自动分配l会话,但直到用户实际登录后Q才会设|这两个Ҏ(gu)。假定是q种Ҏ(gu)Q请考虑清单 14 中的 JSP 片段。在用户d之后Q这个片D将昄单词“Hello”,其后是他Q她的用户名和一个惊叹号。但是,在用L录之前,p个片D는成的内容则是短语“Hello Guest!”。在q种情况下,因ؓusername
Ҏ(gu)还有待初始化,所?<c:out>
标记{而打印出default
属性的|卛_W串“Guest”)?
Hello <c:out value="${user.username}" default=="Guest"/>!
接下来,考虑清单 15Q它使用?
清单 15. 用转义?<c:out> 操作CZ<c:out>
标记?escapeXml
属性。如果在q种情况下已l将company
Ҏ(gu)设|成 JavaString
?"Flynn & Sons"
Q那么,实际上该操作生成的内容将?Flynn & Sons
。如果这个操作是生成 HTML ?XML 内容?JSP 面的一部分Q那么,q个字符串中间的?amp;”符hl可能被解释?HTML ?XML 控制字符Q从而妨了对该内容的显C或解析。但是,如果?escapeXml
属性D|成true
Q则所生成的内容将?Flynn & Sons
。浏览器或解析器不会因在解释旉到这U内容而出问题。假?HTML ?XML ?JSP 应用E序中最常见的内容类型,所?escapeXml
属性的~省值是true
׃ؓ奇了?
<c:out value="${user.company}" escapeXml=="false"/>
用缺省D|变?/SPAN>
除了化动态数据的昄之外Q当通过<c:set>
讄变量值时Q?<c:out>
指定~省值的能力也很有用。正?清单 11 所C,用来赋给限制了作用域的变量的值可以指定ؓ<c:set>
标记的主体内容,也可以通过其值属性来指定。通过?<c:out>
操作嵌套?<c:set>
标记的主体内容中Q变量赋值就可以利用其缺省D力?清单 16 中说明了q种Ҏ(gu)。外?
清单 16. 合ƈ <c:set> ?<c:out> 以提供缺省变量?/B><c:set>
标记的行为非常简单:它根据其M内容讄会话作用?timezone
变量的倹{但是,在这U情况下Q主体内Ҏ(gu)通过<c:out>
操作生成的。这个嵌套操作的值属性是表达?${cookie['tzPref'].value}
Q它?yu)试通过cookie
隐式对象q回名ؓtzPref
?cookie 倹{(cookie
隐式对象?cookie 名称映射到相应的Cookie
实例Q这意味着必须通过对象?value
Ҏ(gu)用点q算W来索储存在 cookie 中的实际数据。)
<c:set var="timezone" scope=="session"> <c:out value="${cookie['tzPref'].value}" default=="CST"/> </c:set>
但是Q请考虑以下情况Q用hW一ơ尝试用这D代码的 Web 应用E序。结果是Q请求中没有提供名ؓ
tzPref
?cookie。这意味着使用隐式对象的查扑ְq回null
Q在q种情况下整个表辑ּ返?null
。因为对<c:out>
标记?value
属性求值的l果?null
Q所?<c:out>
标记会{而输出对?default
属性求值的l果。在q里是字W串CST
。因此,实际的结果是?timezone
限制了作用域的变量设|成用户?tzPref
cookie 中存储的时区Q或者,如果没有Q则使用~省时区CST
?
EL ?JSP 2.0
目前Q表辑ּ语言仅可用于指定 JSTL 定制标记中的动态属性倹{但 JSTL 1.0 表达式语a的一个扩展已l被提出Q会把它包括?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支持页面作者进一步减对 JSP ~制脚本元素的依赖,从而改q?JSP 应用E序的可l护性?
l束?/SPAN>
清单 17. 合ƈ <c:set> ?<c:out> 以提供缺省变量?/B>
ELQ与四个 JSTL 定制标记库提供的操作l合hQ允讔R面作者不使用脚本元素卛_实现表示层逻辑。例如,Ҏ(gu)本文开?清单 1 中的 JSP 代码和清?17 中显C的通过 JSTL 实现的同样功能。(JSTLcore
库中其余的标讎ͼ包括<c:choose>
及其子标讎ͼ在本系列的下一文章中讨论。)管昄执行了条仉辑Q但?JSTL 版本中没?Java 语言源代码,q且标记之间的关p(其是关于嵌套需求)对于M_N?HTML 语法的h都应该是熟?zhn)的?
<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极大地化了 JSP 应用E序的维护?/P>
- (zhn)可以参阅本文在 developerWorks 全球站点上的 英文原文.
- Sun ?JSP 标准标记库主?/A>是了解关?JSTL 的更多信息的良好L?
- JSTL 1.0 规范是关?EL 和四?JSTL 标记库的最l权威文本?
- Jakarta Taglibs目?JSTL 1.0 参考实现的h?
- Shawn Bayern 所著的 JSTL in Action QManning Publications Co.Q?002 q_提供了对所?JSTL 功能的精彩论qͼ作者是该参考实现的领导?
- David Geary ?Java 技术方面很受欢q的作者,他也写了一本关?JSTL 的书Q书名是 Core JSTL ?
- JSPTags.com?JSP 技术参考资料的目录Q它?yu)其专注于定制标记库?
- Sun ?Java Web Services Tutorial中包含了?JSTL 的讨论?
- ?Using JSPs and custom tags within VisualAge for Java and WebSphere Studio”( WebSphere 开发者园?/A>Q是一?WBOnline 实用论文Q它演示?servlet、JSP 和定制标记库的用?
- 通过 Jeff Wilson _ֽ的文章?使用定制标记控制 JSP 面”( developerWorksQ?002 q?1 月)了解关于定制标记库的一切?
- Noel Bergman 的文章?JSP 标记库:着意设计的更好的可用?/A>”( developerWorksQ?001 q?12 月)向?zhn)展示了声明性标记是如何帮助提高 JSP 面的可用性的?
- 有关 EcmaScript 的更多详l信息,请参?Sing Li 的?快速上?Java ~程”( developerWorksQ?001 q?7 月)?
- ?developerWorksJava 技术专?可以扑ֈ多达数百的 Java 技术参考资料?
关于作?/SPAN>
Mark Kolb 是一名在德克萨斯州奥斯汀工作的Y件工E师。他l常服务器?Java 主题在业界发表演Ԍq且与h合著?Web Development with JavaServer PagesQ第二版 一书。可通过 mak@taglib.com?Mark 联系?
]]>
板桥里h http://www.jdon.com 2005/04/28
以数据库为核心的软g时代已经q去Q数据库时代早已l束Q当我看到J2EE征途中那么多h在对象和数据库之间彷徨痛苦ing的时候,我想我该出来喊一C?/P>
其实q句话在几年前肯定有人喊q,因ؓ中间件时代的来Q实际意味着数据库时代终l,正所谓一山无二虎Q如果你重视数据库,你的J2EEpȝ无法完全OOQ只有你忽视数据库,你的pȝ才有可能完全q向OOQ至于数据库性能调优{特定功能都可交由O(jin)/R Mapping工具实现?
很多q前Q包括我自己在内的大部分企业E序员都是从数据库开始我们的职业生Q最早的是dBase/FoxProQ后来有?SQLpd数据? Oracle数据库时代推向了顶峰?/P>
每当有一个新目ӞW一步就是首先设计出数据表结?Table Schema)Q然后开始用SQL语句实现业务逻辑Q这U开发模式一直重复,是后来加入了DelPhI/VBQ他们也只是承担囑Ş昄实现Q这UC/Sl构带来最大问题是Q非帔R于维护,修改hQ迁一动百?/P>
软g的生命在于运动,当它需要发展时Q最的软g人员如果对他也束手无{,q是谁的(zhn)哀Q?/P>
现在更多人开始接受B/Sl构Q但是他们中很多没有真正明白Z么需要B/Sl构QB/S代表的多层架构才是真正目的(因此Q伪多层的B/Spȝ遍地皆是Q?/P>
多层架构实际是将以前pȝ中的昄功能、业务运功能和数据库功能完全分开Q杜l彼此的耦合与媄响,从而实现松耦合和良好的可维护性?/P>
一. 从设计上_׃实现层次完全分离Q业务运功能成ZU中间功能(中间层)Q它不依赖具体的表现层技?Jsp/Html applet{?Q也不依赖具体数据库技术(Oracle/SQL ServerQ,业务q算功能q行在J2EE应用服务器中Q当我们的业务运功能不再依赖数据库Ӟ是否意味着数据库已l不是重点?
? 当然Q多层结构带来了性能问题Q客L讉K数据库中的数据时Q通常需要经q多个层ơ,非常耗费性能Q?如何量减少数据库访问是J2EE应用pȝ首要解决的问题,使用存储q程q没有解册个问题,存储q程的执行还是属于后端,q没有羃短客Lh所要经历的坎坷路途?/P>
解决性能问题的根本解决之道是使用对象~存Q现在, 64位CPU提供的巨大内存空间ؓ单台~存计算提供了硬件基Q更重要的是Q这U缓存计是可~的Q通过集群的缓存机Ӟ如JBossCacheQ, 通过增加应用服务器的数量Q可以提高整个业务逻辑层的~存计算能力Q抛弃过去那Uؓ内存斤斤计较的老思维吧?/P>
? 在系l分析之初是否首先需要数据表设计呢?回答是否定的Q?以UMLZ表面向对象的分析设计Ҏ(gu)已经成ؓ强大工具Q随着面向模型驱动分析设计QMDAQ的普及Q?面向数据库分析方法正在逐步被抛弃,拥有深厚传统数据库分析习惯的E序员必面对和接受q种挑战?/P>
U观整个J2EEpȝ开发过E,数据库已l从q去的中心位|降ZU纯技术实玎ͼ数据库只是状态持久化的一U手D(文g是另外一U实现手D)Q什么是持久化?q是相对于内存缓存状态而言Q持久化是当内存断甉|况下能永久保存状态数据,但是如果J2EE应用服务器是7X24时集群q行Q几乎永不当机,是否有持久化的必要呢Q?/P>
很显Ӟ数据库已lZ操作pȝ中文件系l同L层面Q以它ؓ中心的时代真的结束了QIBM早期DB2数据库开源已l强烈向我们昭示q点?/P>
对于J2EE初学者来_早抛弃q去的两U媄响:q程语言~程习惯和以数据库ؓ中心的设计习惯,从全新的面向对象角度(OOA、OOD和OOP、AOP)来设计开发你的J2EEpȝQJ2EE设计开发三件宝Q?A target=_blank>Model、Patterns和Framework?/P>
以上不只是理论,而是我每天正在做的,如果你也是或赞同请广Z播,唤醒更多彷L痛苦的初学者?BR>