摘要
门户应用程序非常适用于从多个源提取信息以及为包含门户web应用程序的portlet提供应用服务。对于用户,portlet应用程序是独立的实体,类似于桌面上的窗口应用程序。如果在一个窗口应用程序中执行一项操作会导致其他所有应用程序中的内容被刷新,那又会怎么样呢?这就是当前大多数门户的情况。在一个portlet中通过页面流进行转移会导致整个web页面被刷新,包括该页面上的其他所有portlet。
为了避免出现这种有时不希望有的行为,人员采用了所谓ajax-风格的编程方法。ajax即异步java和xml(asynchronous java and xml),它是一个技术的集合,包括用于创建交互式web应用程序的xhtml、css、javascript、dom和xmlhttprequest对象。本文将说明在bea weblogic portal环境中使用ajax编程方法的基本原理,并提供了一些最佳实践和建议,以避免新手ajax程序员经常会犯的许多错误。
ajax简介
考虑一个基于一些用户标准(比如街道地址、城市和州,)来绘制街道地图的web应用程序。这类应用程序在用户界面中已经存在很多年了,并且很少有所改变。用户输入一个地址,然后单击一个按钮,页面中心就会显示周边区域的地图。用户通常需要缩小和放大以更清楚地显示周围区域,或者需要把地图向左或向右稍作移动,以找到一些能够帮助他们进行定位的主要街道或地界标。访问maps.yahoo.com或mapquest.com,便可以获得这种体验。来吧,试试这个地址:100 east wacker drive chicago, il
最终,您将看到一幅芝加哥市区的地图,中心是wacker和michigan大街。在右方,您将看到一系列缩放级别,您可以从中选择一个。当选定一个缩放级别之后,会出现什么情况呢?整个页面将会刷新,这会花费相当长一段时间。现在,当您把地图向左或向右移动时,又会出现什么情况呢?您不可避免地会刷新整个页面,而整个地图需要再次下载。页面大小通常是75到100k,而平均的返回时间大约是3到10秒钟,这取决于您的网络连接速度。
现在使用google maps进行同样的尝试,这是一个完全使用ajax技术的站点。输入地址,然后单击search。页面将完全显示出来。现在进行缩放。注意,地图之外的页面内容不会刷新。下面列出了这背后所发生的事情:
注意,地图上没有指示东西南北的箭头。用户如何与地图进行交互呢?只需像在一个滚动窗口中那样进行拖拉即可。试着单击地图的中心,然后把地图向左方拖动。注意拖动地图时地图是如何响应的!下面列出这背后所发生的事情:
下面是使用ajax技术所带来的好处:
上面对于ajax风格的用户界面的演示令人印象深刻。(如果在使用google maps数天之后,您还不相信其竞争对手已经恼羞成怒,那么您就不必阅读本文下面的内容了。)
有关ajax的完整介绍,请阅读an introduction to ajax(中文版,dev2dev,2005年11月)。
ajax所解决的门户问题
考虑那些大量使用java applet而且希望利用其现有资产创建门户的潜在客户。把现有applet和其他页面流包装到portlet容器中是一件很简单的事情,但是也要考虑到进行门户测试时会出现哪些问题。例如,某个porlet中的一个动作会导致刷新以及随后的重新加载,并重新初始化页面上其他所有基于applet的portlet。如果所讨论的applet具有后端连接,那么portlet的重新初始化将导致服务器丢弃现有连接,然后强制applet重新进行连接,这不仅加重了服务器的负担,而且会使门户用户看到几秒钟的“静止时间”,在这段时间内,基于applet的portlet必须保持灰色,一直到它们完成初始化为止。
这显然是一个潜在的瑕疵。告诉客户们重写所有的applet,因为基于jsp的应用程序并非有用的响应,尤其是对于已经在现有资产中投入大量资源的客户来说。此外,门户必须帮助客户包装现有的应用程序,而不是强迫他们重写整个系统。
我们需要一种让单个portlet在不引起页面刷新的情况下进行操作或获得新数据的方法。虽然这显然存在一些不利之处(我将在本文后面讨论这些),但是在这种情况下,把避免页面刷新作为使用门户的进入屏障是完全有必要的。
注:对于这个问题,一个可行的解决方案是iframes,也就是inline frames,一种基于浏览器的机制,它可以使屏幕的一块区域变为独立的实体,当页面重新加载时它不会刷新。使用类似于ajax编程中所使用的技术,我们可以使用xml-rpc进行服务器调用,从而获取数据并将其加载到dom文档中。apple的开发者web站点上有一篇文章非常好地总结了这种方法的优点和缺点。我确信,关于为什么iframes更好或ajax更好,双方的支持者已经进行过精彩的辩论,但是ajax已经流行开来,而iframes则没有。因此,本文只介绍了ajax,而没有就iframes进行讨论。
用例
在下列情形下,ajax技术很有用处:
示例架构
ajax技术的核心是web浏览器对一些负责提供信息的web服务的调用。如何为该解决方案设计架构呢?有3种值得考虑的架构。第一种架构使用web浏览器作为集成点,出于随之而来的安全考虑和浏览器方面的问题,该架构存在问题。第二种解决方案使用代理来获取分布的资源,这消除了安全问题,但是添加了一个单点故障。第三种架构使用企业服务总线(enterprise service bus,esb)来消除单点故障,并为web服务和ajax技术的蓬勃发展提供了最适宜的环境。
以浏览器为中心
在以浏览器为中心的架构中,web浏览器成为联系远程系统的中心点,如图1所示。数据从各个远程系统中获得,然后在浏览器处的javascript中进行整理和排序。
图 1.以浏览器为中心的架构
这种架构是最自然的设计,它具有多处设计缺陷:
代理服务
如图2所示,代理服务消除了第一种架构的所有缺陷,但是它也有自己的不足之处。它导致出现了一个系统单点故障。当然,web服务器可以作为带有硬件负载平衡器的集群的一部分。这无疑可以解决这个问题。
图 2. 代理服务架构
尽管这种架构比起以浏览器为中心的架构已经有了巨大的改进,还可以做得更好。我们已经为人员提供了一个非常好的环境,但是这很可能为后端系统开发人员带来不便。对远程系统进行身份验证以及数据整理仍然是必要的,但是至少后端程序员应该有更多可使用的工具来迎接挑战。
企业服务总线
图3与前面的两幅图又有所不同,因为企业服务总线(esb)架构是一种逻辑架构。服务可以位于网络上的任意位置,数据源可以被抽象到(可插入到esb中的)服务中。esb为后端系统开发人员处理了他们通常必须做的工作,比如服务身份验证、数据转换、协议转换和可靠性特征。esb可以扩展到带有硬件负载平衡器的计算机集群上,这提供了代理服务架构所具有的优点。
图 3.企业服务总线
为了说明在门户中对ajax应用程序使用esb的优点,考虑对于每次ajax调用都要引用一个web服务的情况。对于小型门户来说,web服务的数量可能相对较少,譬如说几十个。但是随着门户的增长,将会引入更多的web服务。大量web服务的添加与ajax没有关系,但是与soa的实现有着密切的联系。这是一个esb的经典用例。尽管从严格意义上来说,它对于ajax实现的操作不是必要的,但是它还是带来了几个好处:
在这里的例子中,我之所以使用了以浏览器为中心的架构和代理服务架构,是因为作为例子来说,它们比较简单,但是我希望能够使您相信,ajax是体现esb优点的非常不错的方式。
对门户使用的影响
当在门户内采用ajax编程方法时,出现了几个问题。这些问题中的大多数与门户的生命周期以及如何/何时挑选用户信息有关。具体来说,门户要使用诸如用户在哪里单击之类的信息来决定向其显示何种类型的相关信息。weblogic portal具有一种叫做campaign的特性,它允许门户设计人员基于用户个人信息指定对用户的有目的广告宣传。用户个人信息中包括用户的页面历史,即,用户过去点击过的页面。门户在页面刷新时收集这类信息,所以如果用户从未刷新页面,门户就无法(容易地)自动收集用户信息。
考虑ajax编程可能对门户产生的以下副作用:
使用适当的编码风格可以防止这些问题的发生,比如给所有变量和函数取独有的名称,或者使用cookies来保存portlet中使用的当前数据。
一种最佳实践是在所有脚本中使用独有的变量和函数名称,具体做法是在每个变量和函数的名称前加上包含它们的portlet的名称。
浏览器战争尚未结束,专有浏览器和基于标准的浏览器之间的战争仍在延续。ajax相当有趣的一点是,其中有一半是标准(xhtml、xslt、javascript/ecmascript、dom和web services)驱动的。但是其核心技术——xmlhttprequest对象——来自微软。
下面列出了在进行跨浏览器的ajax编程时要注意的一些重要的常见错误,以及如何避免这些陷阱。
安全性
xmlhttprequest对象直接把浏览器连接到一台远程主机,要么是加载页面的web服务器,要么是从另一个完全不同的服务器。正如您所想像的,这里为恶意软件提供了大量的机会。例如,一段恶意的javascript可能等着用户输入口令字段,然后把口令传递给一个远程浏览器,而用户却不知道,甚至还没有单击页面上的提交按钮。如果把口令换为信用卡号码,事情就变得更加有趣了。
为了避免这种风险,mozilla拒绝到为web页面提供服务的主机之外的任意主机的连接。用户不会看到错误消息,因为它根本就不会运行!
internet explorer (ie)采用另一种方法。当要求连接到远程主机时,将使用一个对话框通知用户,而用户可以决定执行什么操作。但是要注意,该对话框不会告诉用户要连接到哪个站点,所以用户缺乏可以用于做出决策的信息。
图 4. 没有有用的信息!
这个问题的解决方案是使用一个java servlet作为到web服务的代理。该servlet获得所有的参数,并把它们传递给远程服务,接着将响应返回给web站点。通过让servlet运行在创建web页面的web服务器上,mozilla就会认为服务是本地的。注意,这是企业服务总线(比如aqualogic service bus)的一个绝好用例。
使用xmlhttprequest对象
包含xmlhttprequest对象的xmlhttp库最初是随internet explorer 4一起发行的activex控件。mozilla包含一个兼容的函数库,所以没有什么好担心的。我仍然推荐使用一个开源库,比如sarissa或dwr。然而,它们在将xml数据传递到对象的方式上存在着细微的区别。
更新dom节点
mozilla和ie之间最令人恼火的区别就是web页面中对dom(document object model,文档对象模型)的处理。大多数函数的工作方式是一样的(至少在dom level 2上),但是仍然有很多值得注意的地方。下面给出两个例子。
innerhtml与innertext的使用
当使用新的动态内容更新<div>标签时,ie用户有两个选择:可以更新节点的innertext或innerhtml。二者的区别很细微,但是却能在信息的显示方面造成很大的差别,尤其是当要显示的文本是xml格式或者包含html实体(比如尖括号或&符号)时。使用innerhtml时假定内容与标签是一起放入的(不管内容是什么)。假设我们试着把以下文本放入一个节点中:
var txt = <b>this is a test</b> document.getelementbyid('mydivtext').innertext = txt; document.getelementbyid('mydivhtml').innerhtml = txt;
<div id="mydivhtml">部分在浏览器中看起来如下:
this is a test
<div id="mydivtext">部分看起来则是下面这样:
<b>this is a test</b>
基本上,innertext节点对输入字符串进行转义,这样显示在用户面前的就是内容原来的样子。但是mozilla在dom节点上不支持innertext属性,所以更好的方法是用户亲自对文本进行转义,并始终使用innerhtml。sarissa有一个帮助器函数用于实现这一项功能:
document.getelementbyid('mydivtext').innerhtml = sarissa.escape("<b>this is a test</b>")
我们将得到同样的结果,如下:
document.getelementbyid('mydivtext').innertext = "<b>this is a test</b>")
在门户中使用独有名称
当某个门户页面由weblogic portal(或任何门户)进行解析时,每个portlet均作为完整的web页面放在html文档中,包括<body>标签(有时甚至包括<html>标签)。因此,如果在每个portlet中始终以相同的id来命名<div>标签(理论上来说,这似乎是使编程标准化的一种良好方法),那么将获得不正确的结果。考虑如果有两个id为“result_data”的元素,那么解析后的门户页面将会是什么样子。
// outer portal shell <html> // first portlet ... <div id="result_data"></div> ... // second portlet ... <div id="result_data"></div> ... </html>
现在,进行一次如下的调用:
document.getelementbyid('result_data').innertext = "stuff";
哪个元素将被更新呢?答案基本上会随浏览器的不同而不同,但是一般的答案就是“第一个”。
因此,这里的最佳实践是使用portlet名称作为html标签中所有id的前缀。
结束语
传统的web应用程序已经无法满足客户的要求。由于google之类的公司提供了更新、更快和交互性更强的web站点,客户的期望值变得越来越高。构建使客户可以提高工作速度和效率的用户界面始终是一项战略性挑战。
ajax编程是web应用程序交互方面的新的事实标准,它为紧密耦合的数据和应用程序筒仓提供了部分解决方案。特别是在与bea weblogic平台结合使用时,ajax代表了web编程的未来方向,并预示着构建具有高度的交互性和响应灵敏度的web站点的新潮流。
在本系列的第二部分中,我将使用具体的例子说明如何在weblogic portal环境中使用ajax。具体来说,我将演示大量portlet,以说明如何从javascript调用web服务以及使用结果更新页面、如何实现代理servlet来处理对外部web服务的调用、如何使用ajax把web页面嵌入到另一个web页面中,以及如何更新您自己的可更新数据库表小构件。
新闻热点
疑难解答
图片精选