级别: 初级 Jeffrey Liu (jeffliu@ca.ibm.com), 软件开发人员, 多伦多实验室,IBM Lawrence Mandel (lmandel@ca.ibm.com), 软件开发人员, 多伦多实验室,IBM
2004 年 3 月 01 日 本文章阐述了如何使用自顶向下的方法来设计和编码您的 Web 服务,这样将具备 Web 服务一个最大的优点:互操作性。文章将向您演示如何使用 WebSphere Studio V5.1 中的 Web 服务工具,包括 WSDL 编辑器和验证器。
本文章阐述了如何使用自顶向下的方法来设计和编码您的 Web 服务,这样将具备 Web 服务一个最大的优点:互操作性。文章将向您演示如何使用 WebSphere Studio V5.1 中的 Web 服务工具,包括 WSDL 编辑器和验证器。
引言
许多被 Web 服务激发起兴趣的开发人员早就开始编写一些简单的服务作为组织之间或者个人使用。这些开发人员由于不熟悉 Web服务技术与开发的复杂性,在大部分服务代码实现上都要依赖于工具。在这样的情况下,Web 服务的开发和使用全部都是由一名开发人员或一个小组完成。服务运行正常,不过由于编码生成工具存在一些问题,所以达不到 Web 服务的基本目标:互操作性。本文将讨论自顶向下 Web 服务开发的优点,同时还将向您演示如何使用 IBM WebSphere Studio V5.1工具来创建 WSDL 文档,并从这些文档生成可互操作的 Web 服务,然后对您的 Web 服务进行单元测试。
什么是 WSDL 及如何使用 WSDL?
WSDL(有时发音为 wiz-dul)或者 Web服务描述语言(Web Services Description Language),是一种 XML 元语言,用来描述关于Web服务的每件事情,从连接到服务的方法再到服务将返回的信息的类型。WSDL文档详细地指定了客户端可以用来与服务及服务的访问点进行交互的操作。WSDL 文档所允许的内容要受到
WSDL 规范的约束。这个描述文档为想要使用特定的服务来获取关于该服务的所有信息的客户端提供了一种标准方法。要找到使用 Web服务的方法并不用与发布 Web服务的组织联系,所有信息都可以从与服务相关的 WSDL 文档中获得。WSDL文档甚至还可以用来为将要使用服务的客户端生成框架代码。
由来自许多不同组织或公司(包括 Sun,Microsoft,Oracle 和 IBM)的人员所组成的一个协会
Web服务描述工作组管理着 WSDL规范。这个组的目标就是维护和发展 WSDL开放标准,从而提供一种平台独立的方法来描述 Web 服务。
Web服务互操作性(WS-I)组织在其基本概要文档中为创建可互操作的 Web服务提供了最佳实践。基本概要包含了一些编写描述可互操作的 Web服务的 WSDL 文档的指导原则。确保您的 Web服务是可互操作的的最好方法就是首先创建一个遵守基本概要的描述文档,然后从遵守基本概要的 WSDL文档中生成您的服务。
自顶向下的 Web 服务开发的好处
自底向上的方法是开始开发 Web服务的最快也是最简单的方法。通过使用自底向上的方法,开发人员可以用任何高级编程语言(比如 Java
TM和 C#)编写服务实现,他们还可以获得一些工具来生成描述服务的WSDL文档并将服务部署到服务器上。这种方法普遍用在一些自己组织内部有遗留系统及应用程序并且想让它们相互通信的公司之中。Web服务构建在现有基础构架的顶层,因而在组织内公开。在这种情况下,快速的自底向上的方法可以工作良好。一个公司既创建服务同时又使用服务,而且由于服务的所有客户端都是已知的,所以开发环境是可控的。由于服务和客户端都可以使用同一组工具来创建并且在同一个平台上运行,所以就没有必要那么担心互操作性方面的问题了。
当使用自底向上方法所开发的 Web服务因供运行在不同平台上的其他公司和消费者外部使用而公开时,或者当一家公司收购了另一家公司并且现在必须将第二家公司的系统与自己公司的系统合并时,互操作性问题就开始显现了。在这些情况下,当创建服务时并不知道该服务的所有可能的客户端,因而这种变化就引起互操作性问题。互操作性问题源自生成 WSDL 文档的工具。由于 WSDL规范中的模糊,所生成的 WSDL文档中可能会包含文档中所允许的特定于平台的信息。根据定义,特定于平台的 WSDL文档是不可互操作的,并且违背了 Web 服务的真正目标。
Web服务要达到其基本目标,做到无愧于对它的吹捧并且进入计算主流,那他们就必须是可互操作。为了实现这一目标,开发人员就必须舍弃用工具生成 WSDL文档的方便性。在使用自顶向下的方法时,开发人员首先做的是编写一个 WSDL文档。一旦编写好了服务的描述,就可以由开发工具来生成服务的存根代码。接着,开发者就编写 Web服务的实现,并创建到任何现有体系结构的连接。通过您亲自编写 WSDL文档,而不依赖于有平台倾向性的工具,您就可以完全控制 WSDL文档,并且文档可以以标准的方式进行编写,这样它就能够为任何 Web 服务平台所理解。由于 WSDL文档是平台独立的,所以接着就可以生成任何语言的存根代码(前提是有工具可以这样做)。WSDL2Java 就是 Apache Axis中的一种可用的工具,它可以从 WSDL 文档创建 Java存根代码。
由于自顶向下方法消除了 Web服务中互操作性问题的主要根源,因此它是非常有利的。按照这种方法来开发 Web 服务需要我们努力去实现 Web服务实现之间的真正互操作性。下面的部分示范一个场景,在这个场景中,使用自底向上方法创建的服务存在互操作性问题,而使用自顶向下方法创建的同一个服务却没有这样的问题。
比较自顶向下和自底向上的 Web 服务开发的用况场景
由开发工具生成的 WSDL文档存在的问题就是,源于工具的错误会传播到Web 服务的顾客中去。服务的 WSDL文档就是它与它的客户端之间的契约。它定义了 Web 服务的术语及其使用。WSDL文档中的错误在期待的行为方面会误导 Web服务的顾客。这个用况场景对采用自底向上方法开发的地址簿 Web服务与采用自顶向下方法开发的同一个 Web 服务的互操作性进行了比较。
使用自底向上方法开发 echo 消息 Web 服务
由四个 Java 类组成:
EchoMessage.java、
Message.java、
RequestMessage.java和
PhoneNumber.java。它们分别如图1,2,3,和4中所示:
图 1. EchoMessage.java
图 2. Message.java
图 3. RequestMessage.java
图 4. ResponseMessage.java
EchoMessage.java有一个方法 getClassName。此方法接受消息实例作为输入,然后返回该实例的全限定 Java 类名作为输出。 Message.java本身就是一个抽象类,它有两个具体的实现。这两个实现阿分别是 RequestMessage.java 和 ResponseMessage.java。因此,方法 getClassName所期待的结果就是
com.example.RequestMessage或者
com.example.ResponseMessage。图 5 展示了描述 echo 消息 Web 服务的相应 WSDL文档,它是使用 Apache Axis 1.0 生成并部署的。
图 5. 使用自底向上方法创建的 WSDL 文档
在 WSDL 文档的 XML Schema 类型定义部分,有一个为
com.example.Message定义的抽象复杂类型。其中并没有
com.example.RequestMessage和
com.example.ResponseMessage这两个派生类型的定义。缺少这两个派生类型是一个互操作性问题,因为抽象类型是不能出现在 XML实例文档中的。抽象类型必须由它们的派生类型来代替。使用像Microsoft Visual Studio .NET 甚至 Apache Axis 本身这样的工具所创建的 Web服务客户端在调用这个 Web服务时就会存在问题,因为由于他们并不知道派生类型是什么。使用自底向上方法创建的echo 消息 Web 服务不是可互操作的,因为它的WSDL 文档不够完整。
使用自顶向下方法开发 echo 消息 Web服务
使用自顶向下创建的就不会存在上一部分所阐述的互操作性问题了。全部所需的 XMLSchema类型定义都可以通过创建 WSDL 文档来指定。使用如图 6 所示的 WSDL文档就可以创建相同的 echo 消息 Web 服务。 echo 消息 Web服务使用这个描述文档与其他 Web服务客户端很好地互操作。图 7展示了一个样本请求和响应消息。
图 6. 使用自顶向下方法创建的 WSDL 文档
图 7. echo 消息 Web 服务中的样本请求和响应消息
下一部分将演示如何使用 WebSphere Studio 5.1 工具来编写 WSDL文档,再从 WSDL 文档构建一个 Web 服务,然后测试该Web 服务。
创建 WSDL 文档
只要您是用 WebSphere Studio进行开发,您的第一步就是要创建一个项目:
- 选择
File => New => Project。
- 选择左侧的
Web和右侧的
Dynamic Web Project,然后单击
Next。
- 输入
AddressBookWeb的项目名并单击
Finish。如果系统提示您切换到 Web透视图,单击 OK。
- 使用自顶向下方法创建 Web 服务的第一步就是创建我们的 WSDL 文档。
选择
AddressBookWeb项目,右键单击它,就会出现一个上下文菜单,选择
New => Other
选择左侧的
Web Services和右侧的
WSDL。单击
Next。
将名称更改为
AddressBook.wsdl并单击
Next。
将
namespace更改成
http://example.com/AddressBook以及将
Definition名更改为
AddressBook。
确保 WSDL 和 XSD 前缀被选中,选择
soap Prefix并单击
Finish。
- 现在 WSDL编辑器就随着新创建的WSDL 文档一起打开了。选择
Graph tab
- 我们将首先定义该服务。在
Services下右键单击并选择
Add child => service。命名
GetInfoByNameService服务并单击
OK。
我们必须创建定位服务的端口。右键单击
GetInfoByNameService并选择
Add Child => Port。命名
SOAPPort端口并单击
OK。
图 8. 创建服务
- 我们需要为服务设置具体的绑定信息。我们首先仅设置绑定,以后再填写其详细内容。图 9展示了 Specify Binding 向导。
右键单击
Port并单击
Set Binding。将绑定名改成
GetInfoByNameBinding并单击
Finish.
图 9. 创建新的绑定向导
- 绑定需要引用操作的抽象定义。操作是包含在 portType中的,因此我们需要为绑定设置 portType。
选择位于顶部
Show Bindings按钮(在 WSDL编辑器右上角)。
现在绑定将会显示在 graph 视图中。
右键单击
GetInfoByNameBinding并选择
Set PortType。确保
Create a new Port Type被选中,并将端口类型命名为
AddressBookPortType。
单击
Finish。
- 我们现在能够根据所给名称指定操作来获取地址簿信息。右键单击
AddressBookPortType并选择
Add Child=> Operation。
将操作命名为
GetInfoByName并单击
OK。
- 我们将指定这个操作的输入。这是请求输入所请求的地址信息的名称的地方。
右键单击
GetInfoByName并选择
Add Child=>Input。
- 现在我们能够指定需要输入操作的信息。单击
Input并选择
Set Message。确保
Create a new message被选中,将消息名设置为
GetInfoByNameRequest并单击
Finish。
右键单击
GetInfoByNameRequest并选择
Add Child => part。将该部分命名为
Name并单击
OK。
- 现在我们将为操作添加输出或返回信息。右键单击 portType 操作
GetInfoByName并选择
Add Child => Output。
- 我们需要设置返回的输出。右键单击
Output并选择
Set Message。确保
Create a new message被选中,将消息名设置为
GetInfoByNameResponse并单击
Finish。
右键单击
GetInfoByNameResponse并选择
Add Child=>part。将该部分命名为
AddressBookInfo并单击
OK。
- 现在我们准备创建一个单向操作来将信息添加到我们的地址簿。这是一个需要输入但是不输出任何东西的操作。右键单击
AddressBookPortType并选择
Add Child=>operation。将该操作命名为
SaveInfo并单击
OK。
- 我们需要添加一个输入。右键单击
SaveInfo并选择
Add Child=>input。
- 右键单击
SaveInfo下的
input 并选择
Set Message。确保
Create a new message被选中,将消息名称设置为
SaveInfoRequest并单击
Finish。
右键单击
SaveInfoRequest并选择
Add Child=>part。将该部分命名为
AddressBookInfo并单击
OK。
您的 WSDL 文档(带有隐藏的绑定)现在应该看起来如图 10 所示。
图 10. 带有隐藏的绑定的当前 WSDL 文档
- 现在,我们将创建自定义元素,这些元素用作我们操作中的输入和输出参数。在
Types下单击并选择
Add Child=> Add Schema。
图 11. 将 Schema 添加到文档中
- 双击 Types 部分 Schema 旁边的箭头,这将会打开 Schema 编辑器。
图 12. 选择 Schema 旁边的箭头来编辑它
- 首先,我们将创建一个复杂类型来控制地址信息。右键单击
schema element并选择
Add Complex Type。将元素名更改成
Address。右键单击
Address并选择
Add Complex Content。
右键单击
complex content并选择
Add Element。将元素名更成
Street。
按照先后顺序为
City, Province, PostalCode和
PhoneNumber添加元素。
图 13. 添加一个全局复杂类型
- 接下来我们将要创建一个复杂类型来控制名称信息。右键单击
Complex Types并选择
Add Complex Type。将复杂类型的名称更改为
Name。
右键单击
Name并选择
Add Complex Content。
右键单击
complex content并选择
Add Element。将名称更改为
FirstName。
添加第二个元素并将名称更改为
LastName。
- 我们现在需要一种具体方法来引用我们的复杂类型。我们将在Schema中创建全局元素。我们需要的第一个元素就是我们的姓名。右键单击
Schema并选择
Add Global Element。
将元素的名称更改为
Name.
通过下拉菜单,将元素类型更改为
tns:Name。
图 14. 添加全局元素
- 我们需要的第二个全局元素是为包含姓名及地址的地址簿信息所创建的。
右键单击
Global Elements并选择
Add Global Element。
将新元素的名称更改为
AddressBookInfo。
单击
AddressBookInfo并选择
Add Local Complex Type。
单击
complex type并选择
Add Element.
将该元素命名为
Name并选择类型
tns:Name。
为复杂类型创建第二个元素。将该元素命名为
Address并选择类型
tns:Address。
- 现在我们有了所需的全不元素。单击编辑器右上角的箭头返回到 WSDL编辑器。
- 现在我们需要设置消息的各个部分来使用刚在 Schema 中定义的元素。图 15展示了Specify Element 向导。
右键单击
GetInfoByNameRequest
的
tns:Name部分。选择
Set Element。选择一个现有的元素。选择
tns:Name并单击
Finish。
将其他两个部分的元素设置为
tns:AddressBookInfo。
图 15. 为消息指定元素
- 现在我们所要做的就是填写绑定信息。Generate Binding向导如图 16 所示。
从
WSDLEditor菜单中选择
Generate Binding Wizard。确保现有绑定的 Generate 内容被选中。选择
GetInfoByNameBinding。再选择
tns:AddressBookPortType。选择
Protocol: SOAP并将 SOAP Binding Options 设置为
document literal。确保 Overwrite existing bindinginformation 被选中并单击
Finish。
图 16. 在绑定向导中设置绑定信息
- 我们应该检查一下 WSDL 文档是否有效。保存 WSDL 文档,然后在 Navigator 视图中单击它,从上下文菜单中选择
Validate WSDL File。您应该看到如图 17 所示的对话框,它表明 WSDL 文件是有效的。
图 17. 验证成功后的消息窗口
祝贺您!您的服务定义已经完成了。
您可以在此查看所完成的 WSDL 文档.
构建并测试 Web 服务
- 调出向导选择对话框。从菜单中
File=>
New=>
Other.
- 启动 Web 服务创建向导。选择左侧菜单中的
Web Services和右侧列表中的
Web Service,然后单击
Next。
- 图 18 展示的是 Web 服务创建向导。选择
Skeleton Java bean Web Service作为 Web 服务类型,取消选定
Start Web service in Webproject复选框并选中
Overwrite files without warning复选框。单击
Next。
图 18. Web 服务创建向导
- 接受服务部署配置页面中的缺省设置。地址簿 Web 服务将会部署到 WebSphere V5.0.2 单元测试环境中的 IBM WebSphere V5.0.2 Web 服务引擎上。单击
Next。
- 图 19 展示的是 Web服务选择页面。单击
Browse按钮找到 AddressBook.wsdl 所在位置。单击
Next。
图 19. Web 服务选择页面
- 接受 Web 服务框架 Java bean 配置页面的缺省设置。单击
Finish。这样将会生成基于 AddressBook.wsdl的 Java 框架代码。
- 在调用地址簿 Web 服务之前,我们必须填入 Java 框架的执行。在编辑器中打开 /AddressBookWeb/JavaSource/com/example/GetInfoByNameBindingImpl.java 。如图 20所示修改这个 Java 框架。保存并关闭编辑器。
图 20. GetInfoByNameBindingImpl.java
- 如有必要打开服务器视图。单击菜单
Window=>
Show View=>
Other...在 Show View 对话框中,展开服务器选项卡,选择
Servers节点并单击
OK。
- 在服务器视图中,右键单击
server,这样就部署了地址簿 Web 服务,选择菜单项
Start。
- 我们将使用 Web Service Explorer 来测试地址簿 Web 服务。要启动 Web Service Explorer,可以右键单击 /AddressBookWeb/WebContent/wsdl/com/example/AddressBook.wsdl,然后选择菜单项
Web Services=>
Test with Web Services Explorer。
图 21. Web 服务浏览器
- 单击
SaveInfo操作保存地址。输入如图 22 所示的值并单击
Go。
图 22. SaveInfo 操作
- 要检索在上一步中保存的地址,可以在 Web Service Explorer 的导航器窗格中单击
GetInfoByName节点。输入
John作为名,输入
Doe作为姓。单击
Go调用操作。图 23 显示了包含调用操作结果的Status 面板。
图 23. 包含调用 GetInfoByName 操作结果的 Status 面板

 |

|
结束语
互操作性是 Web 服务想要打开主流计算大门的钥匙。Web 服务的互操作性从描述关于服务的每件事情的 WSDL文档开始。自底向上 Web 服务开发的方法很快捷、很容易,但是会产生一些存在互操作性问题的服务。保持互操作性最好的办法就是遵循自顶向下 Web 服务开发的方法,并且从编写您的描述文档开始开发工作。WebSphere Studio 5.1 提供了一些用于编写 WSDL 文档的工具,可以从这些文档生成可互操作的服务并且对您新创建的服务进行单元测试。
参考资料
作者简介  | |  | Jeffrey Liu 是 IBM 多伦多实验室 WebSphere Studio Application Developer Web
服务工具小组中的一名软件开发人员。 |
 | |  | Lawrence Mandel
是 IBM 多伦多实验室 WebSphere Studio Application Developer XML 工具小组的一名软件开发人员。Lawrence
同时还是 Eclipse Web Service Validation Tools 项目的一名委员。 |
对本文的评价
|