内容


IBM Lotus Domino 7 中的实用 Web 服务,第 2 部分

编写和测试简单的 Web 服务

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: IBM Lotus Domino 7 中的实用 Web 服务,第 2 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:IBM Lotus Domino 7 中的实用 Web 服务,第 2 部分

敬请期待该系列的后续内容。

您现在想要编写 Web 服务。太棒了!如果您阅读了我们的第一篇文章,“IBM Lotus Domino 7 中的实用 Web 服务:什么是 Web 服务以及它们为何如此重要”,那么您已经对什么是 Web 服务以及它们为何如此重要有了很好的理解。通过 IBM Lotus Domino V7.0,您可以很方便地创建自己的 Web 服务,其他客户机或系统可以使用这些 Web 服务。在某种程度上,它就像编写代理一样容易。

IBM Lotus Domino Designer 允许使用 LotusScript 或 Java 来编写 Web 服务,但本文中所有的示例都是使用 LotusScript 编写的。不过,本文的示例数据库(请参阅 下载 部分)有用 LotusScript 和 Java 两种语言编写的示例 Web 服务以供参考。

背景知识简介

Lotus Domino V7.0 在 Lotus Domino Designer 中引入了新的 Web 服务设计元素。如果在 Lotus Domino Designer V7.0 客户机中打开数据库,就可以看到 Web Services 条目正好位于常见的设计元素树的 Shared Code 部分的 Agents 条目下(参见图 1)。

Lotus Domino 负责处理所有的 WSDL 创建和 SOAP 操作,因此您所要做的事情就是在 Web 服务设计元素中编写代码,就像为代理编写代码一样。一旦指定哪一个类用作服务的接口类,Lotus Domino 就可以发布 WSDL 文件、将引入的 SOAP 请求转换为类上的方法调用以及返回方法的结果(如果有的话)作为 SOAP 响应。

从编写代码的立场上看,您所做的一切就是编写 LotusScript 或 Java 类。Lotus Domino 完成了其余工作!

编写一个简单的 Web 服务

现在我们来编写一个简单的 Web 服务。为了新建一个 Web 服务,在 Lotus Domino Designer 中打开数据库,转到数据库设计的 Web Services 部分,然后单击 New Web Service 按钮(参见图 1)。

图 1. Lotus Domino Designer 中的 Web Service 设计元素部分
Lotus Domino Designer 中的 Web Service 设计元素部分
Lotus Domino Designer 中的 Web Service 设计元素部分

该屏幕与新建代理时打开的窗口(参见图 2)很相似。在 Web Services Properties 框中,设置新 Web 服务的名称 —— 本示例中使用 EchoTestService —— 然后关闭该框。稍后我们将讨论 Properties 框中的各个字段。

图 2. Lotus Domino Designer 中的 Web Service 设计元素
Lotus Domino Designer 中的 Web Service 设计元素
Lotus Domino Designer 中的 Web Service 设计元素

现在应该看到一个与编写 LotusScript 代理时所使用的窗口很相似的屏幕。单击 LotusScript 事件中 Objects 附签的 (Declarations) 以编写类(必须始终在 (Declarations) 部分中定义类)。将下列代码输入到 IDE:

清单 1. 一个非常简单的返回字符串的 Web 服务
Class EchoTest
	Public Function Echo (txt As String) As String
		Echo = txt
	End Function
End Class

该代码进行以下工作:

  • 创建类 EchoTest。
  • 在类中定义方法 Echo,该方法接受字符串作为参数并返回字符串作为结果(类中的函数和 sub 被称为方法)。

EchoTest 中的 Echo 方法获取字符串作为参数并返回相同的字符串。现在看一下它是否是有效的 Web 服务。尝试保存并关闭该服务。将收到下面的错误:

The Web Service has been saved, but is not valid: 
Please specify which class exposes your Web service interface(s), 
using the 'PortType class' field of the Web Service properties panel.

若要避免此错误,请打开 Web Service Properties 框,然后指定要使用的类。因为 Web 服务代码中可能定义了多个类,所以必须仅选择其中一个作为 Web 服务的接口。接口类就是具有 Public 方法的类,Web 服务客户机可以调用 Public 方法。

在 Properties 框中,在第一个附签的 PortType class 字段中输入 EchoTest(您刚刚编写的类名)。关闭该框,然后再次尝试保存并关闭 Web 服务。这次一切正常。现在您有了一个正常运转的 Web 服务!

Web Service Properties 框

下面再次打开 Web service 和 Web Service Properties 框。框中的第一个附签(Basics 附签)如图 3 所示。

图 3. Web Service Properties 框中的 Basics 附签
Web Service Properties 框中的 Basics 附签
Web Service Properties 框中的 Basics 附签

对 Basic 附签上的字段说明如下:

  • Name(必需的):Web 服务的名称,是客户机访问 WSDL 文件或服务的方法时所使用的名称。
  • Alias:除 Name 之外的另一名称,用户使用该名称可以访问服务。
  • Comment:有关 Web 服务的信息数据的字段(通常,该字段的信息不超过一句话;有关 Web 服务的较长描述或信息应写在代码的注释中)。
  • Warn if the WSDL interface is modified:该选项警告您对代码所做的更改是否修改了由 Web 服务产生的 WSDL 文件。这对于确保 WSDL 文件的一致很有用,但是应该意识到,如果选中了该选项,则您将无法保存带有已修改的 WSDL 文件的服务。
  • PortType class(必需的):用作 Web 服务接口的类的名称。换句话说,它就是 Web 服务代码中带有用户可访问的 public 方法的类。

框中的第二个附签是 Security 附签(参见图 4)。

图 4. Web Service Properties 框中的 Security 附签
Web Service Properties 框中的 Security 附签
Web Service Properties 框中的 Security 附签

对 Security 附签上的字段说明如下:

  • Run as web user:该选项使 Web 服务代码能够在调用 Web 服务的用户的安全性上下文中运行(默认情况下,它将在 Lotus Domino Designer 中最后签名 Web 服务的那个 ID 的安全性上下文中运行)。
  • Run on behalf of:该字段允许指定用户,如果想让 Web 服务代码运行在特定用户的安全性上下文中,而不是 Lotus Domino Designer 中最后签名 Web 服务的那个 ID 的安全性上下文中。
  • Allow remote debugging:该选项允许远程调试 Web 服务(有关远程调试的信息,请参阅 Lotus Domino Designer 帮助主题 “Using the Remote Debugger”)。
  • Profile this web service:该选项将在 Web 服务运行时使其生成分析信息(有关分析的信息,请参阅 Lotus Domino Designer 帮助主题 “Profiling agents and Web services”)。
  • Set runtime security level:设置为 1,允许大多数 LotusScript 和 Java 操作正确运行;对于读/写文件、创建 COM 对象或执行网络操作等,根据需要,设置为 2 或 3(有关更多信息,请参阅 Lotus Domino Designer 帮助主题 “Restricted LotusScript and Java agent operations”)。
  • Default access for this web service:该选项允许控制哪些用户可以访问 Web 服务,并超出了使用数据库 ACL 所能进行的控制(如果 Anonymous 用户无法访问 Web 服务,则当用户尝试进行连接时,将收到错误 401 Access Denied 或 404 Not Found)。
  • Allow Public Access users to use this web service:该选项使得仅拥有数据库 ACL 中 “Read Public Documents” 访问权的用户可以使用该 Web 服务,当不想为大量用户授予完全的 Reader 访问权限(或更高级别)时,这点很有用。

框中的第三个附签是 Options 附签(参见图 5)。

图 5. Web Service Properties 框中的 Options 附签
Web Service Properties 框中的 Options 附签
Web Service Properties 框中的 Options 附签

对 Options 附签上的字段说明如下:

  • Programming model:可用选项是 RPC 或 Message(大多数情况下使用 RPC)。
  • SOAP message format:在该字段中,为此 Web 服务选择 SOAP 消息格式(有关格式的更多信息,请参阅下一节)。Lotus Domino V7.0 中的默认格式是 RPC/encoded。
  • Include operation name in SOAP action:该选项要求操作名称存在于外来请求的 SOAP 动作标头中(很少需要)。
  • Port type name:默认情况下,该字段值与 Basics 附签上 PortType class 字段的值相同(尽管您可以使用任何想用的名称)。生成 WSDL 文件时使用该值。
  • Service element name:默认情况下,该字段值是 PortType 名称加上单词 Service(尽管您可以使用任何想用的名称)。生成 WSDL 文件时使用该值。
  • Service port name:默认情况下,该字段值是 Domino(尽管您可以使用任何想用的名称)。生成 WSDL 文件时使用该值。

如您所见,可以设置很多属性,尽管其中只有 Web service name 和 port type class 是必需的。其他所有属性都是可选的或是有适当的默认值。

SOAP 消息格式

在 Web Service Properties 框中,有很多不同的 SOAP 消息格式可以选择,所以不易决定到底应该使用哪一个。各种格式将创建略有不同的 WSDL 文件,反过来会产生略有不同的 SOAP 请求和响应。

从编写代码的立场看,您不会注意到这些不同,因为无论使用哪一种格式,所编写的 Web 服务是完全相同的。但是,这会使调用 Web 服务的用户客户机有所不同。

通常,RPC/encoded 格式是较早的 Web 服务客户机技术(如 Apache SOAP 和 MSSOAP)广泛支持的格式。Doc/literal 由 Microsoft .NET 客户机和服务器默认使用,并在过去的几年中渐受欢迎。

消息格式的选择依赖于调用服务的客户机所使用的技术以及哪一种 SOAP 格式最易于使用该客户机技术。如果不能控制调用服务的客户机,则 RPC/encoded 和 Doc/literal 都是很好的选择。

有关不同格式以及其如何影响 WSDL 结构和 SOAP 消息的详细说明,请参阅经常被提到的 developerWorks 文章 “Which style of WSDL should I use?”。

使用简单数据类型的 Web 服务

现在回过头来编写 Web 服务代码。我们知道用来公开 Web 服务的 LotusScript 代码需要作为类进行编写。实际上,通常用 LotusScript 编写的任何函数或 sub 在 Web 服务中都是作为类方法使用的,并带有以下限制:

  • 不要使用原生 LotusScript 类(如 NotesDatabase、NotesDocument 等)作为参数或返回值。
  • 不要使用变量或货币数据类型作为参数或返回值。
  • 不要使用列表或数组作为参数或返回值(可以使用数组,不过必须使用稍后在本文中所描述的一种特定数据类型)。
  • 不要使用定制类型作为参数或返回值。

相反,可以在 Web 服务类方法中使用以下内容作为参数或返回值:

  • 简单的数据类型(字符串、整数等)
  • 定制的用户定义的类
  • lsxsd.lss 文件中定义的特殊类(该文件包含在 Lotus Notes/Domino V7.0 客户机和服务器文件中)

将用户定义的类是一种复杂的数据类型,我们将在下一篇文章中进行讨论。lsxsd.lss 文件(可以在本地的 Notes 程序目录中找到)中的类是很有用的,允许传递字符串数组、文件和数据。稍后本文将对其中一些类进行讨论,其余的类将在下一篇文章中进行讨论。

现在先来看一些在类中使用简单数据类型的示例。考虑下面的类:

清单 2. 带有多个方法的 LotusScript Web 服务
Class DatabaseInfo
	Private session As NotesSession
	Private db As NotesDatabase
	
	Public Sub New ()
		Set session = New NotesSession
		Set db = session.CurrentDatabase
	End Sub
	
	Public Function GetDbName () As String
		GetDbName = db.Title
	End Function
	
	Public Sub UpdateFTIndex ()
		Call db.UpdateFTIndex(True)
	End Sub
	
	Public Function GetUserRoles (userName As String) As String
		GetUserRoles = Join(getRoles(userName), ",")
	End Function
	
	Private Function getRoles (userName As String) As Variant
		Dim acl As NotesACL
		Dim entry As NotesACLEntry
		Dim sep As String
		
		Set acl = db.ACL
		Set entry = acl.GetEntry(userName)
		
		If (entry Is Nothing) Then
			Dim returnArray(0) As String
			getRoles = returnArray
		Else
			getRoles = entry.Roles
		End If
	End Function
End Class

以上代码浅显易懂,不过对于各种方法,请注意以下内容:

  • New:方法 New 是可选的,且不能用于那些调用 Web 服务的客户机。如果需要的话,仅用于初始化代码。同时,如果编写 New 方法,那么它必须是 sub 且没有任何参数。
  • GetDbName:方法 GetDbName 没有任何参数。这是规定的。
  • UpdateFTIndex:方法 UpdateFTIndex 没有任何参数且不返回值。这也是规定的。
  • GetUserRoles:方法 GetUserRoles 将调用其他方法来执行大部分工作。也可以调用其他函数和 sub(类以外的),甚至可以使用 Use 语句引用 script 库,从 script 库中调用类、函数和 sub。这很有用,因为这样不仅可以保持 Web 服务代码的简洁,而且有助于从已有的任何业务逻辑代码中分离出 Web 服务代码。
  • getRoles:方法 getRoles 声明为 Private,因此类中的其他方法可以使用该方法,但是,不能用于那些调用 Web 服务的客户机。将一些方法声明为 Private 是一个很好的做法,以便保持代码和逻辑位于类中,同时不允许用户直接调用方法。

    但是,请记住如果既没有将方法声明为 Public,也没有将其声明为 Private,则该方法将作为 Public 方法使用。

到目前为止,实际上没有什么复杂的东西。由您决定用户可以调用的函数/sub,然后将其作为方法包含在类中。如果已经编写了所需的代码或逻辑,那么您还可以从 script 库中引用其他类、函数和 sub。

返回数组

您可能已注意到方法 GetUserRoles 在返回值前,将 getRoles 方法返回的字符串数组转化为单一的一个分隔的字符串。这是因为不能直接从 Web 服务作为数组或变量返回 LotusScript 数组。

但是,通过返回 lsxsd.lss 文件中其中一个 ARRAY_HOLDER 类的实例,可以返回数组。将 ARRAY_HOLDER 类(STRINGARRAY_HOLDER、INTEGERARRAY_HOLDER 等)作为值返回时,这些类将自动转换为支持 SOAP 的数组。

为了举例说明,可以将 %INCLUDE "lsxsd.lss" 行添加到 Web 服务的 (Options) 部分,然后重写 GetUserRoles 方法,如下所示:

清单 3. 在 LotusScript Web 服务中返回字符串数组
	Public Function GetUserRolesArray (userName As String) As STRINGARRAY_HOLDER
		Dim returnArray As New STRINGARRAY_HOLDER
		Dim roles As Variant
		Dim i As Integer
		
		roles = getRoles(userName)
		Redim returnArray.Value(Ubound(roles))
		For i = 0 To Ubound(roles)
			returnArray.Value(i) = roles(i)
		Next
		
		Set GetUserRolesArray = returnArray
	End Function

就用户的客户机而言,GetUserRolesArray 方法将返回常规的字符串数组,而不是特定的 STRINGARRAY_HOLDER 对象。这是因为访问服务时,Domino Web 服务在后台完成了 STRINGARRAY_HOLDER 和字符串数组之间的转化。还需要做一些额外工作将 getRoles 数组的元素添加到 STRINGARRAY_HOLDER 的 Value 成员中(因为不能直接将 Value 设置为等于另一个数组),不过这只是几行代码的事。

当然,字符串数组不是惟一可以接受或返回的数组类型,INTEGERARRAY_HOLDER、LONGARRAY_HOLDER、和 lsxsd.lss 文件中定义的类似的类也可以为其他原生数据类型提供相同的功能。有关更多信息,请参阅 Lotus Domino Designer 帮助或 lsxsd.lss 文件。

返回数组的另一种选择是将数组作为复杂数据类型的组成部分返回,该技巧我们将在下一篇文章中进行讨论。

使用 InOut 参数返回多个值

当仅希望使用简单数据类型时,另一种可以使用的方法是 InOut 参数。有些参数既可以接收输入值,也可以返回输出值。例如,考虑下面的类:

清单 4. 在 LotusScript Web 服务中使用 InOut 参数
Class InOutTest
	Public Sub AddOne (inout As INTEGER_HOLDER)
		inout.Value = inout.Value + 1
	End Sub
	
	Public Function SwapAndAdd (inout1 As INTEGER_HOLDER, _
	inout2 As INTEGER_HOLDER) As Integer
		SwapAndAdd = inout1.Value + inout2.Value
		inout1.Value = inout2.Value
		inout2.Value = SwapAndAdd - inout2.Value
	End Function
End Class

第一个方法 (AddOne) 使用整数作为输入参数。方法中的代码为传递的值增加 1 —— 因为它是 INTEGER_HOLDER —— 并将新值返回到 SOAP 响应中。

这是 lsxsd.lss 文件中所定义的 HOLDER 类的特殊属性。将该类用作方法参数时,它们将变成 SOAP 请求/响应中的 InOut 参数,因此可以接收并返回值。

方法 AddOne 并不是一个很实际的示例,因为通常只需接收常规整数作为参数,并且作为能返回修改的整数的函数编写此方法。但是,如果有一个或多个 InOut 参数作为方法返回值,那么就可以在方法响应中返回多个独立的值而不是单个值。

现在看一下第二个方法 SwapAndAdd。该方法有两个 InOut 值作为参数,并返回整数。在用户客户机上,它们生成 SOAP 请求用来作为参数发送两个整数值,并且接收 SOAP 请求,该 SOAP 请求的响应具有三个整数值:其中两个作为参数进行传递(并且通过方法进行修改),另一个是结果。

不可否认,InOut 参数不那么常见,因为返回多个值通常是通过返回复杂数据类型来处理的,但这仍是个值得注意的好方法。再次说明,我们将在本系列的下一篇文章中讨论复杂数据类型。

使用日期和时间

您需要使用的最后一个简单数据类型是日期/时间对象。下面的示例演示了使用参数中的日期/时间并返回对象:

清单 5. 在 LotusScript Web 服务中使用日期和时间
Class DateTester
	Public Function getCurrentTime () As XSD_DATETIME
		Dim dt As New NotesDateTime(Now)
		Set getCurrentTime = New XSD_DATETIME
		Call getCurrentTime.SetValueFromNotesDateTime(dt)
	End Function
 	
	Public Function getLocalDateFormat (xdt As XSD_DATETIME) As String
		Dim dt As NotesDateTime
		Set dt = xdt.GetValueAsNotesDateTime()
		getLocalDateFormat = dt.LocalTime
	End Function
End Class

lsxsd.lss 类再次发挥了作用。可以只接收或返回 XSD_DATETIME(变成了 SOAP dateTime 元素)类型变量并在它与 NotesDateTime 对象之间进行转换。

但是,应注意到时间值的时区处理会比较困难,因为服务器和客户机可能正确也可能会不正确地添加或解释 SOAP dateTime 元素的时区偏移。最新的 W3C Note 对该问题的某些方面进行了讨论。通常,首先应试着彻底测试 Web 服务客户机。

测试 Web 服务

已经编写了 Web 服务之后,肯定想对它进行测试。为了访问 Web 服务的 WSDL,必须使用 Web 服务的完整 URL 路径,该路径以 ?WSDL URL 命令结尾。

例如,可以对 DNS 名为 mydomino.example.com 的服务器上的 WSTest.nsf 数据库的 Web 服务 MyNewWebService 使用下面的 URL:

http://mydomino.example.com/WSTest.nsf/MyNewWebService?WSDL

有很多可用于测试 Web 服务的测试工具 —— 既有免费工具,也有商业工具 —— 可以很方便地编写较长的文章或教程来描述各种测试方法。

下面是几个测试工具可用于测试和调用 Web 服务,每个测试工具都有一段简短描述。熟悉每个工具的详细信息是留给读者的练习。

soapUI

测试 Web 服务时,最易于使用的工具之一是 soapUI,可从 soapUI Web 站点 获得。SoapUI 是用 Java 编写的免费的桌面程序,因此可以在不同操作系统上运行。下面是使用 SoapUI 对 Web 服务进行测试的步骤:

  1. 请确保在本地机器上正确安装了 Java 1.5 或更高版本。
  2. 下载 soapUI program 并将其解压缩。
  3. 在解压缩文件的 /bin 目录中,运行 soapui.bat 文件(Windows 操作系统下)或 soapui.sh 文件(其他操作系统下)来打开 soapUI。
  4. 选择 File - New WSDL Project,然后根据提示,输入项目名称。
  5. 在左侧导航栏中,右键单击属性列表中的新项目,然后选择 “Add WSDL From URL” 选项。
  6. 输入测试服务的 URL(例如,http://localhost/DWSTest.nsf/EchoTestService?WSDL),如果提示要为所有操作创建默认请求,则单击 Yes。
  7. 现在,可以在左侧完全展开新项目并查看可用于调用的每个 Web 服务方法的条目。如果双击方法名称下的 Request 条目,将看到预构建的 SOAP 请求,可以将其作为一个测试进行发送(参见图 6)。
    图 6. soapUI 接口
    soapUI 接口
    soapUI 接口
  8. 对于图 6 中的 EchoTest 服务,有一个简单 SOAP 请求用于发送。如果想测试该服务,则在请求 envelope 的 <TXT> 节点中输入文本,然后单击位于 SOAP 请求文本上方的工具栏中的绿色箭头按钮。这将发送请求到服务并在右侧窗格中显示得到的 SOAP 响应。

SoapUI 允许您构造测试套件,适于对 Web 服务进行单元测试。这样,就可以创建一套测试,当修改了 Web 服务后,可以运行预先编写的测试来确保各方面仍正确运行。

其缺点是所有事情都必须通过原始 XML SOAP 请求和响应来执行。如果您习惯使用 XML 和 SOAP,就不会觉得很难,因为最难的部分(首先要编写 SOAP 请求)已经替您完成了,并且您可以查看 SOAP 响应。但是,如果您更喜欢在较抽象的层面上工作 —— 在程序中使用简单的 API 或函数 —— 那么该工具对于您来说就过于低级了。

Eclipse 和 Web Tools Platform (WTP)

如果已经安装了 Eclipse(或者需要理由来使用 Eclipse),有一个非常好的包 Web Tools Platform (WTP) 为测试 Web 服务提供了更高水平的接口。不需要使用原始 SOAP 请求,WTP 可以为每个 Web 服务方法创建窗体,您只需在窗体中输入值,然后发送请求。

下面是安装和使用 WTP 的基本步骤:

  1. 下载并安装 Eclipse platform
  2. 安装 WTP 组件。对于 Eclipse 3.2 之前的版本,请参阅 WTP Web 站点上的安装指南。对于 Eclipse 3.2 或更高版本,这些指南是 “Web and J2EE Development” 下的 Callisto toolkit 的一部分。进行以下操作:
    1. 选择 Help - Software Updates - Find and Install。
    2. 在下一个屏幕上,选择 “Search for new features to install2”,然后单击 Next。
    3. 请确保选中了 Callisto Discovery Site 选项,然后单击 Next。
    4. 在要安装的包列表的 Callisto Discovery Site 部分下,选择 “Web and J2EE Development” 项(也选择了该项下的所有项)。然后单击 “Select Required” 按钮以获取所有其他所需组件,并单击 Next 进行安装(参见图 7)。安装过程需要几分钟的时间。
    图 7. Eclipse 中的 WST 包安装
    Eclipse 中的 WST 包安装
    Eclipse 中的 WST 包安装
  3. 完成安装后,重新启动 Eclipse。从主 Workbench 页面,选择 Run - Launch the Web Services Explorer。
  4. 在 Web Services Explorer 视图中,单击 WSDL Page 按钮,将 WSDL Main 添加到 Navigator 窗格(参见图 8)。
    图 8. WST 中的 WSDL Explorer
    WST 中的 WSDL Explorer
    WST 中的 WSDL Explorer
  5. 可以在 Actions 窗格中输入 WSDL 路径。输入测试服务的 URL(例如,http://localhost/DWSTest.nsf/EchoTestService?WSDL),然后单击 Go 按钮。
  6. 找到 WSDL 文件后,在 Navigator 窗格的 WSDL Main 条目下应该有一个树状结构,列出了 Web 服务中的所有方法。
  7. 双击 WSDL 树中的任一方法名,将在 Actions 窗格中出现窗体,允许您在该窗体中输入方法的每个参数值,并将值发送到 Web 服务。响应将显示在底部的 Status 窗格中(参见图 9)。
    图 9. WST 中的 SOAP 请求
    WST 中的 SOAP 请求
    WST 中的 SOAP 请求
  8. 如果您想查看由 Web 服务调用发送和接收的原始 XML SOAP 消息,则单击 Status 窗格中的 Source link。

虽然 Eclipse WTP 的初始设置比 soapUI 工具更复杂,但它提供了更友好的用户接口(用窗体代替了原始请求)。如果需要底层的细节,仍可以查看发送和接收的原始消息,不过一些人发现使用基于窗体的方法更易于创建和发送请求。

MSSOAP toolkit

很多使用 Windows 平台的 LotusScript 编程人员已经成功使用 MSSOAP toolkit 来调用 Web 服务。虽然该 toolkit 不再受支持也不再由 Microsoft 更新(已经被 Microsoft .NET 框架取代),但它仍是一个通用的技术,因此在这里值得一提。

MSSOAP 是一个 DLL 文件,可以从 Microsoft 下载或作为标准 Windows 安装的一部分安装在工作站上。使用 LotusScript,可以将 DLL 作为 COM 对象进行调用,如下所示:

清单 6. 来自 LotusScript 的简单 MSSOAP 调用
Dim Client As Variant
Set Client = CreateObject("MSSOAP.SoapClient")
Call Client.MSSoapInit("http://localhost/DWSTest.nsf/EchoTestService?WSDL")
Print "Echo said " & Client.Echo("echo")

显然,需要对所使用的 Web 服务中的方法、参数和数据类型有一些了解。如果调用另一个 Web 服务,可以手动读取并解释 WSDL 文件(可能很麻烦),也可以使用类似 soapUI 或 Eclipse WTP 的工具来解释所有事情。

不幸的是,我们发现在 Windows 操作系统上使用的 MSSOAP 版本一般是 1.x 版,只能使用 RPC/Encoded Web 服务,该服务使用简单数据类型作为参数。当返回复杂数据类型时,通常是 IXMLDOMNodeList 对象,但将复杂数据类型作为参数进行传递时,需要创建新的 IXMLDOMNodeList 对象且不易处理。一般情况下,MSSOAP 1.x 也无法理解使用了枚举的 Web 服务(将在本系列的下一篇文章中进行讨论)。

如果您可以控制使用 MSSOAP 库的服务器或工作站,那么可以选择下载并安装 SOAP Toolkit 版本 3.0,它允许您调用更广泛的 Web 服务。安装该 toolkit 后,您可以将上述代码由 CreateObject("MSSOAP.SoapClient") 更改为 CreateObject("MSSOAP.SoapClient30") 以便使用较新版本的库。表 1 列出了两个版本之间的差别。

表 1. MSSOAP 1.x 和 3.0 之间的差别
MSSOAP 1.xMSSOAP 3.0
默认情况下,在大多数使用 Windows XP/2000 的机器上必须 下载 并安装
CreateObject("MSSOAP.SoapClient")CreateObject("MSSOAP.SoapClient30")
仅适用 RPC/Encoded Web 服务RPC/Encoded、RPC/Literal、Doc/Literal、来自 LotusScript Web 的 Wrapped
不能解释枚举可以解释由 LotusScript Web 服务返回的枚举,但有可能不能正确解释从 Java Web 服务返回的枚举

MSSOAP 允许动态调用 Web 服务(这很方便),关于使用 MSSOAP(在 LotusScript 和 Visual Basic 中,后者可以方便地转换为 LotusScript)有大量的代码示例。因此,如果您从使用 Windows 的机器上调用 Web 服务,这是个很好的选择。

Apache Axis

在 Lotus Notes 环境中,Apache Axis 框架是调用 Web 服务的另一种很好的选择。Axis 是一个非常成熟的 Java 包,多年来一直用于在不同平台上创建、提供和使用 Web 服务。实际上,Axis 是允许 Lotus Domino V7 提供 Web 服务的底层技术!

如果使用 Axis 作为客户机来调用 Web 服务,通常基于服务的 WSDL 文件会使用 Java 命令行工具(随 Axis 提供的)wsdl2java 来创建调用 Web 服务的 stub 文件。这些 stub 文件是用作复杂代码的包装程序的 Java 类,这些复杂代码是访问和使用 Web 服务时所需要的,因此所有您需要做的事情就是使用 stub 类来调用方法并返回响应。虽然您必须为要调用的任何 Web 服务完成生成 stub 文件的前端工作,但这将减少后续麻烦,即必须了解错综复杂的 Web 服务(消息格式、名称空间、响应解析等)。

如果要在 Lotus Notes 中使用 Apache Axis 来编写代码以便调用 Web 服务,比较好的起点是 developerWorks 文章 “通过 Lotus Domino Java 代理消费 Web 服务” 和开源 Stubby 数据库,该数据库可从 OpenNTF Web 站点获取。作为示例,下面演示了如何使用 Stubby 来创建 Axis 代码以调用 EchoTest 服务:

  1. 从 OpenNTF.org 下载 Stubby 数据库 并在 Lotus Notes V7 客户机中打开。
  2. 单击 Create New Doc 按钮,在数据库中创建新文档,并在窗体的 WSDL File 字段输入 EchoTest 服务的 URL (http://localhost/DWSTest.nsf/EchoTestService?WSDL) (参见图 10)。
    图 10. Stubby 数据库文档
    Stubby 数据库文档
    Stubby 数据库文档
  3. 单击窗体上的 Generate Stub Files 按钮,创建 Axis stub 文件。同时创建了 JAR 文件,包含了所有已编译的且可以使用的 stub 文件。创建的所有文件附在 Stubby 文档的 generated files 附签的字段中。
  4. 将 generated files 附签上的 JAR 文件(在本例中为 EchoTestService.jar)移至本地文件系统。
  5. 使用 Lotus Domino Designer V7 在数据库中创建新的 Java 代理,然后使用 Edit Project 按钮附上前一步中的 JAR 文件。
  6. 从 Stubby 文档的 sample code 附签上,复制所生成的示例代理代码,然后粘贴到代理中。还需要添加一行代码用来调用 Web 服务的 Echo 方法。得到的代理代码类似清单 7 中所示(为了简洁,删除了注释和空行):
    清单 7. 在 Lotus Notes Java 代理中使用 Apache Axis stub 文件
    import lotus.domino.*;
    import DefaultNamespace.*;
    public class JavaAgent extends AgentBase {
        public void NotesMain() {
            try {
                EchoTestServiceLocator locator = new EchoTestServiceLocator();
                EchoTest service = locator.getDomino();
                System.out.println("Echo said " + service.ECHO("echo"));
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
  7. 现在您可以在任何 Lotus Notes/Domino V7 客户机或服务器上运行该代理以访问 Web 服务。

对于喜欢使用 LotusScript 的编程人员,Stubby 数据库中还有很多示例使用 LS2J 调用以 LotusScript 编写的 Web 服务 stub 代码。有关 LS2J 的更多信息,请参阅 Lotus Domino Designer 帮助。

PHP nuSOAP

测试 Web 服务时,您可以尝试的另一个有趣的事情是 PHP nuSOAP 库。它不仅可以很方便地用于使用 Web 服务,而且可以提供一种很好的方式,用于显示有关 Domino Web 服务的信息。

例如,您有一个可用的 PHP 服务器(或者有一个本地的 PHP 安装,如 WAMP server),那么您可以将 nuSOAP 库复制到该服务器上并创建以下页面:

清单 8. 使用 PHP nuSOAP 来获取有关 WSDL 文件的详细信息
<?php
$wsdlURL = $_POST["wsdlurl"];

if ($wsdlURL) {
	// MODIFY THIS -- make sure the path below is set correctly 
	require_once('../nusoap/lib/nusoap.php');
	
	$wsdlURL = urldecode($wsdlURL);
   	$wsdl = new wsdl($wsdlURL);
	
	$wsdlerror = $wsdl->getError();
	if ($wsdlerror) {
		echo 'There was an error getting the WSDL file at ' .
		htmlspecialchars($wsdlURL) . ':<br>' . $wsdlerror;
	} else {
		echo $wsdl->WebDescription();
	}
} else {
	$htmlPage = '<html>
<head>
<title>nuSoap WSDL Documentation Generator</title>
</head>
<body>
<h3>nuSoap WSDL Documentation Generator</h3>
This page uses the 
<a href="http://sourceforge.net/projects/nusoap/">PHP nuSOAP</a> 
library to generate a nice description of a given WSDL file
and all of its available methods.<p>
<form method="post" action="' . $_SERVER['PHP_SELF'] . '">
Please enter the URL of your WSDL file below:<br>
<input type="text" size="75" name="wsdlurl"><p>
<input type="submit" value="submit" name="submit"><br />
</form>
</body>
</html>';
	
	echo $htmlPage;
}

?>

如果您将该页面保存到 PHP 服务器并在浏览器中打开它,将提示您输入 WSDL 文件的 URL 位置。输入 URL 并单击 Submit 按钮后,您将看到一个页面,描述了 Web 服务的每个 public 方法(参见图 11)。

图 11. PHP nuSOAP WSDL 文档示例
PHP nuSOAP WSDL 文档示例
PHP nuSOAP WSDL 文档示例

注意:如果 Web 服务是在本地机器的数据库中,则需要从本地安装的 PHP 服务器上运行该页面(再次说明,可以很方便地设置和使用 WAMP 服务器),并且需要确保本地 PHP 服务器未使用端口 80(因此不会干扰本地的 Notes HTTP 服务)。

用于 Domino SOAP 消息跟踪的 SoapLog

可以考虑使用的另一个工具是 SoapLog DSAPI Filter。这是一个 DLL 文件和 Notes 数据库(可以复制到服务器),并且它记录了发送到服务器上 Web 服务的 SOAP 消息。在撰写本文的时候,DLL 仅用于 Windows 服务器,而且还没有免费版的 SoapLog DSAPI Filter。

可以按照以下步骤来安装 SoapLog 工具:

  1. 下载 SoapLog 并将其解压缩到本地工作站。
  2. 将 soaplog.dll 文件复制到 Domino 服务器上的 Notes program 目录中。
  3. 将 SoapLog.nsf 数据库复制到 Domino 服务器上的数据目录中,然后根据需要调整 ACL(主要确保服务器可以写入)。
  4. 将 SOAPLOG_DBNAME 变量添加到服务器的 Notes.ini 文件,指向 SoapLog.nsf 数据库。例如,如果 SoapLog.nsf 数据库位于根数据目录中,则将下面一行代码添加到 Notes.ini 文件:
    SOAPLOG_DBNAME=SoapLog.nsf
  5. 在 Domino Directory 中打开服务器文档。在 Internet Protocols - HTTP 附签上,将在右侧页面中部看到 DSAPI。在该字段中添加 soaplog.dll 条目(如果该字段中已经有条目,则在添加 soaplog.dll 条目前,先新添一行)。
  6. 在 Domino 服务器上重新启动 HTTP 任务。应看到一条消息,指明已装入 SoapLog DSAPI。

装入过滤器后,服务器上 Web 服务的所有 SOAP 消息请求将在 SoapLog.nsf 数据库中创建新的日志文档(参见图 12 和 13)。

图 12. SoapLog request 附签
SoapLog request 附签
SoapLog request 附签
图 13. SoapLog response 附签
SoapLog response 附签
SoapLog response 附签

还可以设置其他的 Notes.ini 参数以便进一步过滤日志。有关如何操作的更多信息,请参阅 SoapLog.nsf 数据库中的 Using This Database 文档。

结束语

本文简单介绍了在 Lotus Domino V7 中创建和测试一个简单的 Web 服务的步骤。在 Domino V7 平台上可以很方便地创建和提供 Web 服务,使用的代码与您为 LotusScript 或 Java 代理编写的代码很相似。虽然在 Lotus Notes 中测试和调用 Web 服务并不像提供服务一样自然,但还是有很多很好的方法可用来编写能够与服务进行交互的 Web 服务客户机。

这种做法最大的优点在于您的企业中使用其他(非 Domino)Web 服务的系统仍可以方便地访问和使用您所编写的 Web 服务,这使得 Lotus Domino 被广泛应用于 SOA 环境中。

本系列的下一篇文章将着重介绍如何编写更复杂的 Web 服务,这些服务使用了复杂数据类型,可以发送和接收文件附件或生成定制错误。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus, SOA and web services
ArticleID=185110
ArticleTitle=IBM Lotus Domino 7 中的实用 Web 服务,第 2 部分: 编写和测试简单的 Web 服务
publish-date=12262006