扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
您现在想要编写 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 设计元素部分
该屏幕与新建代理时打开的窗口(参见图 2)很相似。在 Web Services Properties 框中,设置新 Web 服务的名称 —— 本示例中使用 EchoTestService —— 然后关闭该框。稍后我们将讨论 Properties 框中的各个字段。
图 2. 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 方法获取字符串作为参数并返回相同的字符串。现在看一下它是否是有效的 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 附签
对 Basic 附签上的字段说明如下:
框中的第二个附签是 Security 附签(参见图 4)。
图 4. Web Service Properties 框中的 Security 附签
对 Security 附签上的字段说明如下:
框中的第三个附签是 Options 附签(参见图 5)。
图 5. Web Service Properties 框中的 Options 附签
对 Options 附签上的字段说明如下:
如您所见,可以设置很多属性,尽管其中只有 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 服务中都是作为类方法使用的,并带有以下限制:
相反,可以在 Web 服务类方法中使用以下内容作为参数或返回值:
将用户定义的类是一种复杂的数据类型,我们将在下一篇文章中进行讨论。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 |
以上代码浅显易懂,不过对于各种方法,请注意以下内容:
但是,请记住如果既没有将方法声明为 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 服务进行测试的步骤:
soapui.bat
文件(Windows 操作系统下)或 soapui.sh
文件(其他操作系统下)来打开 soapUI。
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 的基本步骤:
虽然 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.x | MSSOAP 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 服务:
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(); } } } |
对于喜欢使用 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 文档示例
注意:如果 Web 服务是在本地机器的数据库中,则需要从本地安装的 PHP 服务器上运行该页面(再次说明,可以很方便地设置和使用 WAMP 服务器),并且需要确保本地 PHP 服务器未使用端口 80(因此不会干扰本地的 Notes HTTP 服务)。
用于 Domino SOAP 消息跟踪的 SoapLog
可以考虑使用的另一个工具是 SoapLog DSAPI Filter。这是一个 DLL 文件和 Notes 数据库(可以复制到服务器),并且它记录了发送到服务器上 Web 服务的 SOAP 消息。在撰写本文的时候,DLL 仅用于 Windows 服务器,而且还没有免费版的 SoapLog DSAPI Filter。
可以按照以下步骤来安装 SoapLog 工具:
SOAPLOG_DBNAME=SoapLog.nsf |
装入过滤器后,服务器上 Web 服务的所有 SOAP 消息请求将在 SoapLog.nsf 数据库中创建新的日志文档(参见图 12 和 13)。
图 12. SoapLog request 附签
图 13. 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 服务,这些服务使用了复杂数据类型,可以发送和接收文件附件或生成定制错误。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者