摘要:
本文将介绍创建、配置、发布Web Service的主要技术:从Web Services Markup Language (WSDL), Simple Object access Protocol (SOAP), 到 Universal Description Discovery and Integration (UDDI) 注册。本节你将学会如何手工创建一个WSDL接口。
基于Web的分布式交互应用软件的思想由来已久,早在B2B电子商务得到重视之前电子数据交换就已经出现。随着B2B市场的流行,交互能力成为数据交换最重要的要求。
任一在线电子商务都有大量的商业服务,每个都提供自己的服务(称为Web Service)。如今的电子商务还没有一种让一个商业服务自动发现其潜在合作伙伴的服务的机制。被称为下一代的网络将提供这样的自动发现功能。
一.什么是WSDL
下一代的网络需要一种能够描述服务(Web Service)细节的解决方案,这意味着你需要一种格式或某种语法你可以用来描述下列问题的答案:
● 你的在线交易提供了什么服务?
● 如何调用你的服务?
● 当用户调用你的服务时你需要用户的什么信息?
● 用户如何提供你要的信息?
● 服务将返回给用户的信息是什么格式的?
值得高兴的是WSDL提供了做这些事情的机制。
二.WSDL和SOAP
为了更好的理解WSDL是如何工作的,我先描述一下SOAP和HTTP是如何与WSDL工作的。WSDL是用来描述Web Service。交易之间通过交换WSDL文件来了解各自的服务。当你了解和使用合作伙伴的服务时就要用到SOAP了。你可以把通过SOAP访问的服务看作对象。
很可能你是通过互联网或是电子邮件和潜在的伙伴交流的。互联网使用HTTP,电子邮件使用SMTP, 使得HTTP和SMTP成为SOAP最佳的传输服务载体。
三.WSDL的撰写
下面介绍如何为Web Service撰写WSDL。撰写WSDL的目的是将已经存在的Web Service 发布出去。你可能处于下面的某一种情形
● 你已经拥有服务准备将其发布出去。
● 你有WSDL准备根据WSDL中准备发布出去的功能实现Web服务。(有人觉得这不太可能。但是UDDI的指纹技术使得者成为可能。)
● 你什么都没有准备开始做。
四.撰写WSDL的四个步骤:
我将把撰写WSDL分为四个简单的步骤。一步步做下去你的Web Service就可以发布了。
1. 服务接口
我们将创建一个简单的移动电话零售店的服务接口(我将称其为MobilPhoneService)作为例子。这个公司销售几种不同的型号的移动电话,因此Web Service的后端数据库只有一张有两个字段-——modal number, price。通过WSDL你将发布你的服务的两个方法:
● getListOfModels()
● getPrice(modelNumber)
getListOfModels方法返回一个包含移动电话型号的字符串数组。getPrice方法根据型号查询价格。WSDL将这些方法称为操作。现在可以开始创建WSDL接口文件了。
WSDL文件的根结点都是<definitions>,在
根节点中必须提供服务的完整描述。在<definitions>节点中首先得提供各种名称空间的宣告。你必须声明的三个外部名称空间是WSDL,SOAP和XSD(XML Schema Definition). 对于
MobilPhoneService还有一个名称空间:TNS(这意味着TNS——TNS是targetNamespace的缩写——将包含你在MobilPhoneService中定义的所有节点和属性的名称). 但是WSDL将是你创建的WSDL文件中使用的主要名称空间。在这个系列的文章中我将提及其他名称空间的用法。
值得注意的是WSDL广泛的使用了名称空间的概念。因此建议您访问W3C的官方网站学习更多名称空间的知识。名称空间满足了电子数据交换的轻量灵活的要求,WSDL正是这种思想的一个实现。
<definitions>节点包含一个或多个<portType>节点,每个<portType>节点实际上就是你准备发布的一个操作集。当然你也可以把单个的<portType>节点看作类中的一组方法。例如,假设你一系列的管理解决方案需要客户和服务商之间相互操作,你很可能独立的定义两者交互操作的功能,这就意味着你要为客户和服务商各自定义一个portType.每个portType都可以称为一个服务,那么完整的WSDL文件就是一个服务集。
每个服务必须有一个名字。在这个例子中,我们只有一个服务,所以我们必须使用portType节点的name属性给我们的移动电话销售服务命名。
每个服务中可以包含多个方法(或称为操作),在WSDL中用<operation>标识。在这个例子中要发布
getListOfModels和getPrice这两个方法。因此需要两个<operation>节点,每个节点都有名称。我们必须使用<operation>节点的name属性命名每个操作。
此时的WSDL文件就如下图所示:
Listing 1: Defining operations
|
2.参数
定义了操作(或方法)之后,我们需要指定传入操作的参数和操作的返回参数。在WSDL中,所有的参数都称为消息。这有助于我们把操作想象为我们发送消息然后获得返回消息。
方法调用就是一个接收消息然后返回结果消息的过程。
回到第一步,我们有两个需要发布的操作。第一个操作getListOfModels没有参数之返回一个版汉移动电话型号的字符串数组。因此,我们定义一个包含一个字符串数组的<message>节点。
在图Listing 2中我们可以看到有几个<message>节点。第一个<message>节点有一个值为ListOfPhoneModels(消息的逻辑名)的name属性,和一个name属性为models的<part>节点。这说明ListOfPhoneModels消息只有一个名为models的port节点。在消息节点中你可以定义多个part节点,只要各个part节点拥有不同的名称即可。
在<port>节点中还有一个type属性,它可以看作C++或Java中的数据类型。我已经定义了models的数据类型是tns:Vector.(我们在<definitions>节点中定义的名称空间中有一个就是tns).这涉及到MobilPhoneService的名称空间。这就意味着你可以在WSDL文件中创建你自己的名称空间。你可能会问:为什么?如何创建?
我们以getListOfModels操作返回的字符串数组为例讲解一下为什么要使用自己创建的名称空间。WSDL使用XML Schema Definition(XSD)定义的简单数据类型。在消息中,你可以直接使用这些简单数据类型,也可以使用这些数据类型构件的复杂类型。这就是你在使用复杂类型时必须定义自己的名称空间的原因了。在本例中你就需要为字符串数组定义一个复杂类型。
你可以使用XSD来创建你自己的名称空间。因此我们就必须在<types>节点中使用xsd:complexType元素来定义Vector数据类型。Vector使用两个简单数据类型:string(节点数据)和int(节点数)。从而Vector就成为该名称空间的一部分,并且可以在名称空间的别名tns下使用。
在图Listing 2中,我还定义了另外两个消息:PhoneModel和PhoneModelPrice。这两个消息之使用了XSD名称空间下的简单数据类型,因此无需为之定义复杂类型。
你可能已经注意到:在创建<message>节点时无需指定参数是传入参数还是返回值。这些是在<portType>j节点的<operation>节点中定义的。正如你在图Listing 2种看到的,我在两个<operation>节点中都添加了<input>和<output>节点。<input>节点定义了操作调用时哟努需要提供的参数。与此类时,<output>节点定义了操作的返回值。
Listing 2: Defining parameters
|
3.消息和传输
我抽象的定义了操作和消息,但是并没有涉及其实现的细节。事实上,WSDL就是用来定义和描述Web Service,以便于给外部框架在定义WSDL用户如何到达这些服务的实现时一个参考。你可以把框架看作是WSDL的抽象定义和实现的一个绑定。
当前最流行的绑定技术是使用Simple Object Access Protocol(SOAP).WSDL将会详细说明一个可以访问你的服务的SOAP,以后就由这个SOAP负责将用户从WSDL文件连接到WSDL的实现。SOAP将是我本系列文章的下一个话题,因此暂时我会避免介绍SOAP的细节以便于集中注意于WSDL的撰写。
撰写WSDL的第三步就是描述将SOAP绑定到WSDL文件的方法。你需要在<definitions>节点中加入<binding>节点。<binding>节点有name和type这两个属性。name属性用来标识<binding>节点,而type属性用来标识与该绑定相关的portType(操作集)。在图Listing 3中,你可以看见<binding>节点的type属性值就是<portType>节点的name.
WSDL的绑定节点包含一个在绑定中使用的外部技术的声明。由于你使用了SOAP,你就要使用SOAP的名称空间。在WSDL的属于中,外部名称空间的使用被称为拓展节点(extensibility element)。
在图Listing 3中,你可以看到一个空的绑定节点(<soap:binding/>)。这个节点是用来宣告你将使用SOAP作为绑定和传输服务。
<soap:binding>节点有两个属性:style 和transport。style是一个可选属性,用来描述绑定节点中操作的种类。transport属性指定该绑定将使用HTTP作为底层的传输服务。
SOAP客户端将从WSDL文件中读取SOAP结构与SOAP服务进行同步,因此必须重视协同工作的能力。细节部分我将在本系列的第三部分讲述。
在空的<soap:binding/>节点之后有两个WSDL<operation>节点,每个<operation>节点都是在第一步中生成的。每个<operation>节点都各自提供了绑定的细节。因此,我使用了另一个拓展节点<soap:operation/>(operation节点中的一个空节点). <soap:operation/>节点有一个SOAP客户端用来创建SOAP请求的soapAction属性。
在第二步中,getListOfModels操作只有输出没有输入,因此你必须为该操作提供一个<output>节点。这个<output>节点包含一个<soap:body/>节点(<output>节点中的一个空姐点)。SOAP客户端需要这些信息来创建SOAP请求。<soap:body/>节点的名称空间属性的值必须跟你将在SOAP服务中发布的服务名一致。
你即将结束第三步。只需要拷贝一下下一个操作,你就跟图Listing 3一样了。
Listing 3: Adding SOAP support
|
4.总结
你已经完成了一个完整描述你的服务的接口的WSDL文件了。WSDL还要求为WSDL文件创建一个摘要。WSDL称为执行文件。当你使用UDDI注册(将在本系列的第四部分介绍的)发布Web Service时需要用到该执行文件。图Listing 4就是一个WSDL执行文件。其主要特性如下:
● 根结点<definition>跟图Listing 3中一样,除了执行文件的targetNamespace不同
● 在<import>节点中引用了接口文件(Listing 3)及其名称空间。
● 有一个含有服务逻辑名称的<service>标签。在<service>节点中有一个引用你在Listing 3中创建的SOAP 绑定的port节点。
Listing 4: WSDL implementation file
|
五.使用 IBM的Web Service 工具撰写WSDL
这个Web Service就可以发布了。我已经展示了如何手工创建这些文件。这些文件同样可以使用Web Service撰写工具如IBM的WSTK生成。
WSTK可以通过向导生成这些文件。用户可以生成我上面演示的两个方法的WSDL文件,比较一下两者的区别。
你会发现以下的不同点:
● WSTK使用逻辑规则创建所有的名称属性,而我在例子中自己根据需要定义名称。
● WSTK为每一个操作至少生成一个input标签,即使该操作没有任何输入。就像ListAllPhoneModels操作没有输入,但如果你用WSTK生成WSDL文件就会包含一个空的input节点。
● WSTK会在这两个文件之外生成第三个文件。这第三个文件是SOAP发布描述符,SOAP引擎在服务发布时会用到。
在这部分,我演示了手工创建WSDL接口和执行文件,并与用IBM的WSTK工具生成的文件做了比较。在本系列的下一个部分,我将讨论将这个WSDL服务发布到SOAP服务上。