Domino 8 在万众瞩目中已正式发布,其除了在邮件、服务器管理灵活性、性能改进、安全性增强等方面有了长足的进步之外,在软件设计中赋予系统更多的开放性和互操作性。面对业界流行的 SOA、Web 2.0 等新技术,Domino 8 是融入这些流行的趋势中,还是停步观望;特别对于 Domino 开发人员来说,所使用的平台和技术是否有广泛的前景且值得深入呢?
答案是积极的,Domino 8 在程序设计方面有巨大的增强,特别在 Web 程序设计方面,表现为:
- Domino 8 既作为 Web 服务的使用者,又作为 Web 服务的消费者,这意味着 Domino 8 应用程序将能够调用驻留其它平台的 Web 服务;
- 对 DB2 备选数据存储的通用支持,这方面涉及的查询视图等期待的功能,现都可用在 Web 程序中;
- 在互联网上所熟悉的 Blog、Wiki、RSS、ATOM、Ajax、XML、JSON、Mashup 等概念或技术都可以在 Domino 8 上得到体验实现,其 @Formula、LotusScript Language 都在这些方面有所加强。
对于 Ajax 的讨论和在 Domino 上实现的方法,已经有多篇文章涉及,感兴趣的读者可以参考 相关资源。本文将通过一组 Domino 8 技术来构建一个示例 Mashup 应用,这组技术包括 JavaScript、Ajax、@Formula、JSON 和 Google 地图 API。本文不会详细介绍 JSON 和 Mashup,也不会介绍详细介绍 Domino 的设计方法,本文的读者需要对 Domino 开发有一定的经验。
JSON(JavaScript Object Notation)是一种更轻、更友好的 Web services 客户端的格式引起了 Web 服务供应商的注意。
XML——这种用于表示客户端与服务器间数据交换有效负载的格式,这种标记语言已经在广阔的软件应用领域中占据了主导地位。XML 与生俱来的语言无关性使之在软件架构师心目中占据着独特的地位,但即便最著名的 XML 权威也不得不承认:在某些环境中,XML 的使用已经超出了它自身能力的极限。很多 Web 应用程序更新通常是通过 REST 风格 Web services 获得 XML 数据,一旦被用户的浏览器接收到,就需要整合到 HTML 页面的总体布局之中,我们处理 XML 数据通常是使用 DOM 实现的,采用 DOM 的复杂性源于其基于函数的根,这使得对数据树的简单修改或访问都需要进行无数次方法调用。此外,众所周知,DOM 在各种浏览器中的实现细节不尽相同,这一过程带来更为复杂的编程模式,其跨浏览器兼容性出现问题的可能性也大大增加。显而易见:如何使一种标记语言轻松地集成到 HTML 页面中以满足简便开发的要求?问题的答案就是:利用所有主流浏览器中的一种通用组件——JavaScript 引擎。
让我们通过一个 Domino 视图数据,说明 XML 和 JSON 展现的不同结构,我们在服务器上建立一个名为 Mashupdemo 数据库,在该数据库中我们创建一个名为 homedata 表单,其作用为输入人员的地理位置信息,然后创建一个展现信息的视图 vHomedata:
图 1. 创建数据表单和标准视图
我们通过以下的 Domino URL 命令
http://hostname/map/mashuodemo.nsf/vHomedata?ReadViewEntries&Count=1 |
访问 vHomedata 视图,获得一行数据的 XML 输出:
<?xml version="1.0" encoding="UTF-8" ?>
<viewentries toplevelentries="4">
<viewentry position="1" unid="175C4B37CAFA54164825732C002EFB9D"
noteid="97A" siblings="4">
<entrydata columnnumber="0" name="locationx">
<number>24.55</number>
</entrydata>
<entrydata columnnumber="1" name="locationy">
<number>116.1</number>
</entrydata>
<entrydata columnnumber="2" name="dname">
<text>John</text>
</entrydata>
</viewentry>
</viewentries>
|
这是大家比较熟悉的 Domino XML 格式数据,通过 Domino URL 命令 ReadViewEntries 输出视图 vHomedata 为 XML 格式,里面内容包括每行数据的位置(viewentry position="1"),文档标识符(unid="175C4B37CAFA54164825732C002EFB9D"),列的位置和列值(<entrydata columnnumber="2" name="dname">)、数据类型和值(<text>Samon</text>),我们在解析它的时候一般用 DOM。Domino 8 扩展了 ReadViewEntries 命令的功能,其中加入了 Outputformat=JSON 这个参数,使视图数据可以输出为 JSON 这种格式,例如通过以下的 Domino URL 命令:
http://hostname/map/mashuodemo.nsf/vHomedata?ReadViewEntries&outputformat=JSON&Count=1 |
此命令把视图 vHomedata 第一行数据输出成 JSON 格式的文件,内容为:
{"@toplevelentries": "4",
"viewentry":
[{"@position": "1",
"@unid": "175C4B37CAFA54164825732C002EFB9D",
"@noteid": "97A",
"@siblings": "4",
"entrydata":
[{"@columnnumber": "0",
"@name": "locationx",
"number": {"0": "24.55"}
},
{"@columnnumber": "1",
"@name": "locationy",
"number": {"0": "116.1"}
},
{"@columnnumber": "2",
"@name": "dname",
"text": {"0": "John"}
}
]}]}
|
我们可以看出 XML 格式数据:
<entrydata columnnumber="2" name="dname">
<text>John</text>
</entrydata>
|
在 Domino 8 中转换 JSON 格式数据,表现为
{"@columnnumber": "2",
"@name": "dname","text": {"0": "John"}
}
|
在语法层面上,JSON 与其他格式的区别在于分隔数据的字符,JSON 中的分隔符限于单引号、小括号、中括号、大括号、冒号和逗号。乍看上去,使用 JSON 的数据分隔符的优点可能并不那么明显,但它们简化了数据访问。使用这些数据分隔符时, JavaScript 引擎对数据结构(如字符串、数组、对象)的内部表示恰好与这些符号相同,那我们访问 JSON 中数据就可以使用类似语法:homedata@dname[0]。
Mashup 是一种令人兴奋的交互式 Web 应用程序,它利用了从外部数据源检索到的内容来创建全新的创新服务。它们具有第二代 Web 应用程序的特点,也称为 Web 2.0。在本篇中我们通过地图 mashup 的集成应用展现 DOMINO 8 如何方便地融入到 Web 2.0 的世界里,在具体应用中人们搜集大量有关事物和行为的数据,二者都常常具有位置注释信息。所有这些包含位置数据的不同数据集均可利用地图通过令人惊奇的图形化方式呈现出来。mashup 蓬勃发展的一种主要动力就是 Google 公开了自己的 Google Maps API。这仿佛打开了一道大门,让 Web 开发人员可以在地图中包含所有类型的数据。
本例中,我们首先到 Google Map 站点 上申请一个 API 授权码及设置对应的信任站点名称 www.huangym.com。我们在数据库 mashupdemo.nsf 中建一个 ajaxgooglemap 表单,如图:
图 2. 建立 ajaxgooglemap 表单
可以看到主要在 HTML 首页内容的代码:
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/> <title>Google Maps JavaScript API Example</title> <script src=\"http://ditu.google.com/maps?file=api&v=2&key= ABQIAAAAVxSMinjdZ7dEstMKHhPv7xSbs7nheOJkgjePpEsLSD4Lw3tvbRRGAvRVSkqG2_NcPTCYffaL_Bc9ng\" type=\"text/javascript\"></script>" |
其申明了 ditu.google.com 的授权号 key, 表单启动触发 onload() 方法。
我们在 JS Header 里面加入下列几个方法:
function load()
{
var stringURL=
'http://www.huangym.com/map/mashupdemo.nsf/vHomedata?readviewentries&outputformat=json';
oXHR = new ActiveXObject("Microsoft.XMLHTTP");
oXHR.onreadystatechange = loadmap;
oXHR.open('GET', stringURL, true);
oXHR.send(null);
}
|
该方法在网页打开时会被自动调用,主要的功能是向保存“homedata”的服务器发出 ajax 请求,同时设定方法“loadmap”响应请求的结果。
在代码我们可以发现,所定义的 stringURL 是获取“homedata”的 URL,其中加入了“outputformat=json”,这样 Domino 是返回结果的时候就不是返回 XML,而是返回 json 结果。
有关 ActivexObject("Microsoft.XMLHTTP") 的更多信息,请参考 Ajax 相关的文章。在这里只给出代码的概要解释:
oXHR = new ActiveXObject("Microsoft.XMLHTTP");
// 新建 ActiveObject 对象,为发起 ajax 请求做准备
oXHR.onreadystatechange = loadmap;
// 指定回调函数的名字为 loadmap,当服务器返回结果时由 loadmap 方法进行响应。
// 有关 loadmap 方法的具体实现在下面进行解释
oXHR.open('GET', stringURL, true);
// 定义 ajax 请求的目标,就是以上定义好的 stringURL
oXHR.send(null);
// 发送 ajax 请求
function loadmap() {
if (oXHR.readyState == 4) {
if (oXHR.status == 200) {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GScaleControl());
eval("dataobj="+oXHR.responseText+";");
for (j=0;j<dataobj.viewentry.length;j++) {
locationx[j]=dataobj.viewentry[j].entrydata[0]["number"]["0"];
locationy[j]=dataobj.viewentry[j].entrydata[1]["number"]["0"] ;
distext[j]=dataobj.viewentry[j].entrydata[2]["text"]["0"];
}
map.openInfoWindow(map.getCenter(),document.createTextNode("myhome"));
switchlocation();
}
} else {
alert("server error");
}
}
}
|
方法 loadmap 作为回调函数响应 ajax 请求的返回结果。主要功能是对返回结果进行判断,如果返回结果不是错误消息则对结果进行解析,将返回结果转换成数组,供 googlemap 对象显示时使用。最后调用 switchlocation 方法,开始循环显示返回结果中的不同地点。有关 switchlocation 方法在下面详细解释。
在 loadmap 方法中的前三行是对返回结果进行判断。
从 map = new GMap2(document.getElementById("map")); 这一句开始对返回结果进行处理。
其中 GMap2 是 googlemap 定义好的类名,document.getElementById("map") 是获取当前网页中的 "map" 对象,这一对象是在 Domino 表单中指定的。
在 googlemap 对象生成后,则通过 addControl 方法对 googlemap 对象添加控件,如地图的控制器等:
map.addControl(new GSmallMapControl()); map.addControl(new GScaleControl()); |
然后通过 eval 方法将 domino 返回的 json 结果转变为对象。
eval("dataobj="+oXHR.responseText+";"); |
注意,这里的 eval 方法是在 java script 中与 json 结合的最好方法,该方法的作用是将参数中提供的字符串作为一句 javascript 语句解释运行。这样我们就可以通过字符串操作动态生成 javascript 代码。如以上这句就是将 oXHR.responseText 这个 Domino 返回的 Json 字符串转换成为名为 dataobj 的对象。
此后对 dataobj 对象进行遍历,分别将第 1 列,第 2 列 , 第 2 列转换成数组 locationx,locationy,distext。
最后调用 switchlocation() 方法开始循环显示地图。
function switchlocation() {
map.setCenter(new GLatLng(Number(locationx[i]), Number(locationy[i])), 7);
map.openInfoWindow(map.getCenter(),document.createTextNode(distext[i]));
if(i>=locationx.length-1) {
i=0;
} else {
i++;
}
window.setTimeout(switchlocation,7000);
}
|
方法 switchlocation 主要是通过“window.setTimeout”方法实现定时调用,每 7 秒种调用一次 switchlocation。显示不同的地点。其中变量 i 用于记录当前显示的行数,i 每循环都加 1,指向下一条记录,当 i 大于等于数组长度时,则将 i 至零,重新从第一行开始显示。显示过程中使用的方法有 map.setCenter()用于指定地图中心的经纬度。还有 map.openInfoWindow() 用于在地图中心显示文本信息。
最后,如上所述,通过调用 window.setTimeout(switchlocation,7000) 设置定时器,在 7 秒种后重新调用方法 switchlocation。作到这里我们的 Google Map 的应用雏形基本可以完工了,通过注册的 Google 信任站点www.huangym.com访问我们的 Domino 表单 ajaxgooglemap,URL 为:http://www.huangym.com/map/mashupdemo.nsf/ajaxgooglemap?OpenForm。效果如图:
图 3. 效果
这样我们视图记录的信息就在 Google Map 轮流显示出来了。
Domino V8 提供给我们开发人员强大快速开发平台,加入 Web 2.0 等因素,我们就可以开发出许多赏心悦目的应用来,本文涉及了 Ajax、JSON、Mashup 及 Domino Web 开发等知识,希望此篇能给大家借鉴一下,以此能加快您的开发进度和应用功能。
-
开始了解 IBM Lotus Notes and Domino V8 技术内容。
-
阅读 developerWorks 文章“使用 Ajax 操纵 Lotus Notes 文档”。
-
阅读 developerWorks 文章“如何在 Domino 上使用 Ajax 框架 Dojo”。
-
阅读 developerWorks 文章“Mashups:Web 应用程序新成员”。
-
Mashup 资源:developerWorks 上所有有关 Mashup 的相关资源的汇总。
-
Ajax 技术资源中心:developerWorks 上所有有关 Ajax 的问题都可以在这里找到解答。
-
订阅 Ajax 相关文章和教程的 RSS 提要:获得即将发表的 Ajax 相关文章和教程的通知(查看developerWorks 内容 RSS 提要了解更多的信息)。
黄运敏,现是 IBM Lotus 软件产品部门的售前技术支持工程师,曾开发多个 Domino 应用,曾在 IBM Lotus 售后部门从事 Lotus 售后支持工作。您可以通过huangym@cn.ibm.com与他联系。