编辑注:本文讲述了在WebLogic Portal 8.1中进行底层Ajax编程的细节。这与当前的WebLogic Portal 9.2 beta版无关。
摘要
Ajax是一种异步编程范型,借助于它,开发人员可以创建高度交互式的Web站点,从而在提高用户效率的同时减轻服务器的负载。Ajax结合了Web services、JavaScript和动态HTML编程技术,可以创造丰富的客户端体验,并提高本地应用程序的可用性。本系列文章的第一篇介绍了这些相关概念以及在BEA WebLogic Portal中实现一个Ajax解决方案所涉及的架构考虑事项。
本文是此系列文章的最后一篇,提供了一组复杂的示例portlet,从一些基本的查找portlet开始,再到一个使用动态表作为前端数据库表的高级例子,最后以一个有趣的例子结尾,最后这个例子在没有使用<object>或<iframe>标签的情况下把一些页面动态嵌入到另一个页面中。
所有例子均给出了完整的源代码,并包括安装脚本和文档。
关于示例Portlet
本文在这里给出了各种支持Ajax的portlet,并逐行对其源代码(在本文的下载部分中可以找到)进行了解释。本文还包括了一个可重用Java servlet的源代码,这个servlet可用于降低Mozilla Firefox和Microsoft Internet Explorer (IE)中固有的安全限制级别。这个servlet实现了第1部分中描述的代理设计模式。
有一点需要指出,我在代码中使用了最简单的Ajax库,因为我想说明整个过程到底是怎么回事。还有大量可用的库可以极大地减少需要编写的代码量。我在一些代码中使用了Sarissa库,主要用于处理一些跨浏览器的问题。参见Ajax简介,可以了解有关Ajax库的更多信息,比如DWR。当设计和构建自己的生产应用程序时,我不建议您使用这里给出的底层构件。本文中使用的Ajax库可以很好地处理跨浏览器的问题和Ajax绑定(wiring)。
本文的余下部分逐个描述了每个示例portlet。我们鼓励您浏览源代码,从而更深入地了解这些portlet是如何实现的。
Zip Code Lookup
Zip Code Lookup(区号查找)portlet说明了两个可用于调用远程Web服务(例如,一个与Web服务器位于不同计算机上的Web服务)的方法。这两个方法(direct和proxy)是通过使用两个直接命名的按钮Direct和Proxy来调用的。Direct方法直接从Web浏览器调用Web服务,这通常会导致违反Internet Explorer中的安全规则,而在Firefox中则根本无法使用。Proxy方法使用了本文稍后将会描述的Java代理servlet。
图 1:调用远程Web服务的Zip Code Lookup portlet
注意Zip Code标签旁边的输入栏。我们在这一栏中获得输入值,然后把它传递给后端的Web服务。当我们从该Web服务获得城市和州的信息时,就会把这些信息放在City和State标签右边的相应位置上。
为了能够引用JavaScript代码中的元素,我们需要为每个元素指定一个惟一的ID。下面给出了zipcode.jsp的相关HTML代码:
<body style="font-family:helvetica;font-size:10pt;">
<p>Type in a 5-digit zip code to get information on that zip code.</p>
<form name="zipcode" method="post" action="">
<table cellspacing="0" cellpadding="4" frame="box" bordercolor="#dcdcdc" rules="none" style="border-collapse: collapse;">
<tr>
<td>Zip Code</td>
<td><input type="text" size="5" name="zipcode_USZip" id="zipcode_USZip"></td>
<td><input type="button" onclick="zipcode_updateDirect();" value="Direct"/></td>
<td><input type="button" onclick="zipcode_updateProxy();" value="Proxy"/></td>
</tr>
</table>
</form>
<hr color="blue"/>
<table>
<tr>
<td>City</td>
<td><div id="zipcode_city" style="color:blue;"></div></td>
</tr>
<tr>
<td>State</td>
<td><div id="zipcode_state" style="color:blue;"></div></td>
</tr>
<tr>
<td colspan="2">
<form>
<button onclick="zipcode_showResults();">Returned XML <span id="zipcode_status" style="color:blue;"></span>
</button>
</form>
</td>
</tr>
</table>
</body>
注意,所有ID标签都使用了portlet名称作为前缀。这是一个相当好的最佳实践,您必须将其深植到您的编码风格中。为什么这很重要呢?因为当BEA WebLogic Portal呈现一个门户页面时,它会把所有的portet HTML拷贝和粘贴到一个聚合页面上。所以,如果您有两个portlet,而每个portlet都有一个ID为“mylabel”的元素,那么呈现出来的门户页面中将会有两个元素具有相同的惟一ID。当使用JavaScript/DOM函数getElementById('mylabel')时,返回的元素将会是文档中“mylabel” ID的第一个实例,而这很可能不是您所期望的结果!
还要注意使用<div>标签作为动态内容的占位符。这是一个样式选择问题,但是我发现,<div>标签具有成为任何内容的容器的巨大潜力,而<td>标签的限制就要严格得多。更多地使用CSS绝对有助于减少使用嵌入的样式标签,但这将会是留给读者的一道练习题。但是,我要指出的是,明智地使用CSS样式可以极大地减少最终要编写的JavaScript数量。记住,CSS可以用于改变一个元素的颜色、位置、可见性、透明度以及其他许多可视化特性。简单的样式交换通常可以让图形化用户界面变得更加具有交互性。在Employee Listing portlet中,当变化被提交给数据库之后,我使用了这项技术来通知用户。
在这个portlet中,我们将从文本栏中获得输入,调用一个Web服务查找与区号相关的城市和州信息,然后使用该Web服务返回的信息动态更新City 和State <div>元素。页面不会刷新——只有City和State元素会更新。