内容


使用 Macromedia Flex 开发 Web 服务客户端

Comments

引言

开放式标准被企业用作降低高整合及维护费用的主要手段。现实中的各种异构软件系统使得我们必须使用一些涉及开放式标准的策略,而 Web 服务很快就成为了解决这个难题的方法的一个重要部分。直到现在,要构造一个界面友好的 GUI 客户端来与这些系统进行交互还是非常的单调乏味。这个问题的一个部分就是 Web 服务描述语言(Web Services Description Language ,WSDL)正趋向于成为服务端点的唯一描述语言,这有时使得遵守起来变得非常困难,尤其是对组织中的设计人员和用户接口开发人员。Flex 是 Macromedia 开发的一个 Rich Internet Application 平台,它在用户接口设计人员和更多传统服务器端开发人员之间搭了一座桥。传统的后台程序员可以利用大量的吸引人的可视控制、效能、布局、及现有的 Flash 组件,加上他们对服务端点的深厚知识,从而装配出一个诱人的客户端应用程序。在任何时候不管有什么类型的资源在您的项目中可用,最后的结果都是可以容易地创建一个高交互及诱人的应用程序,它在 Web 服务中整合了您的投资。

理解 WSDL

为了在不同的 SOAP 服务端点间交换消息(在 Flex 中,SOAP 消息被限制成只能使用 HTTP 协议传输机制),Flex 通过引用 WSDL 文档的 URL 来使用现有的 WSDL 定义。下表列举了经常会在 WSDL 文档中出现的元素:

表 1. 常见的 WSDL 元素
元素名描述
types定义了 Web 服务消息可以使用的数据类型。
message定义了 Web 服务操作中要传输的数据格式。
portType定义了一个 Web 服务要提供的一个或多个操作。
operation定义了输入、输出及错误消息的组合。
input指出了 Web 服务客户端要(例如 Flex 应用程序)发生给 Web 服务的消息。
output指出了 Web 服务要发送给客户端(例如 Flex 应用程序)的消息。
fault指出了处理消息出错时返回来的错误值。
binding指出了与 Web 服务进行通信时使用的网络协议。现有 SOAP 绑定包括 HTTP GET、HTTP POST、以及 MIME 协议。Flex 现在只指出 SOAP 绑定。
service定义端口集。每一个 service 元素对应一个 portType 元素,从而指定了访问定义在 portType 元素中的操作的不同方法。
portWeb 服务端点,指出了绑定和网络地址间的关联。

这些可以帮助我们对这些元素怎样在 WSDL 文档共同定义不同的 Web 服务有一个统一的理解。 然而,Flex 设法隐藏了开发人员对 Web 服务定义的复杂性,而且对大多数人来说,能大概知道服务要提供哪些功能就已经非常足够了。

还有一点非常重要,WSDL 提供了两种截然不同的方式来描述服务操作:远程过程调用(Remote Procedure Call,RPC)及面向文档(document-oriented)的方式。对于一个 RPC 服务操作的 Flex 调用,它会发送一个 SOAP 消息来指出要调用的操作及操作所需要的参数。而对于一个面向文档式操作的 Flex 调用,它会发送一个封装成 XML 文档的 SOAP 消息。Flex 对这两种方式都提供了,但是由于它们使用了专门的标记,这暗示了这两种方式之间有细微的差别。在文章的后面,作者会通过各种实例来详细地解释这两种方式的使用。

在 Flex 中使用 Web 服务

在您的 Flex 应用程序中,声明 Web 服务最基本的原则就是使用 <mx:WebService> MXML 标记(以 mx为前缀的 XML 标记是 MXML 命名空间的一部分,并用来构成一个 MXML 文件)。比较典型的用法是,在这个标记上使用一个wsdl 属性,通过它来指出要引用的 WSDL 文档 URL。Flex 提供了一个专门的服务构想,用来移动这些声明的某些标记到 flex-config.xml 文档的专门块中。Flex 文档包含了这个专门服务的更详细介绍。为了在整个 MXML 应用程序中都能指向它,可以在 <mx:WebService> 标记中使用 id 属性来指出服务 ID。

<mx:WebService id="serviceID" wsdl="http://somehost/someService/service.wsdl">
	<mx:operation name="someOP" result="someResultHandler()"fault=
	"someFaultHandler()">
		<mx:request>
			<!-- parameters -->
		</mx:request>
	</mx:operation>
</mx:WebService>

相应的 ActionScript serviceID.send() 现在调用了这个 Web 服务功能。但有一点非常重要的是,当不带参数地使用 send() 方法时,所有的参数绑定都应该在实际的 Web 服务定义中定义。换句话说,参数绑定应该使用 <mx:request> 标记中的一个 XML 数据模型来隐含关联起来。

<mx:WebService id="serviceID" wsdl="http://somehost/someService/service.wsdl">
	<mx:operation name="someOP" result="someResultHandler()"fault=
	"someFaultHandler()">
		<mx:request>
			<param1>{input1.text}</param1>
			<param2>{input2.text}</param2>
		</mx:request>
	</mx:operation>
</mx:WebService>

另一个绑定参数到这个服务调用的方法就是明确地传送这些参数。一个明确地绑定这些参数的调用应该看上去像 serviceID.send(input1.text, input2.text) ,通过这个方法,我们不需要像前面描述的那样使用 MXML 声明中的 XML 数据模型。

您现在已经看见了从 Flex 应用程序中调用 Web 服务的机制,但是您怎样处理这些调用结果呢?让我们来更仔细地看看前面的声明,您可以注意到了 <mx:operation> 标记上的 resultfault 属性。这些引用 ActionScript 方法来处理调用结果和服务调用中可能发生的错误。这里要强调的是上面描述的对您的 Web 服务的调用是一个异步调用。这是一个要非常注意的不同点,因为您可能已经习惯了这样的一种情况——一个方法调用返回后就意味着该方法正确执行完毕了。然而在您的 Flex 应用程序中,在 send() 方法后的语句会被马上执行,而不必等待 Web 服务执行的返回。当 结果(result)处理器(在 operation 属性中被引用)被通知 Web 服务已经执行完毕后,应用程序能处理服务调用的结果。而如果服务调用中出现了错误,则相关联的fault 处理器会被通知。

如果顺利的话,您正在对怎样使通过使用 Flex 环境来整合您的 Web 服务能没有那么单调变得更清晰。 后面我们来看一些实例,它们描述了在 Web 服务声明中的 WSDL 专门的 MXML 表明,这个我们在这部分没有提及到。

WSDL 到 Flex 映射实例

关于这个实例

下面的实例覆盖了使用 WSDL 来定义基于 SOAP 的 Web 服务的不同方法,以及 WSDL 定义怎样映射到 MXML 的 Web 服务构造中。我们在前面部分提到了 Web 服务可以在 MXML 中使用参数绑定进行声明。这意味着操作的参数可以作为 Web 服务声明(在一个 XML 数据模型中)的一部分包含进来,如下:

<mx:WebService>
	<mx:operation>
		<mx:request>
			<!--parameters here-->		
		</mx:request>
	</mx:operation>
</mx:WebService>

<mx:operation> 元素中的 <mx:request> 元素包含了 XML 和 Flex 绑定的混合体,它们是构造消息 SOAP 体内容的必要部分。

在这个实例中使用的 WSDL 文件是通过 IBM® WebSphere® Application Developer V5.1 Web 服务向导(这个向导和 WebSphere Application Server 的 Web 服务支持都是基于 JSR 109 规范的)自动产生的。这个向导生产了 WSDL 文件、类型映射、序列化器及部署 Web 服务到 WebSphere Application Server V5.X(我们这里使用的是 V5.1)上需要的配置条目。虽然使用 WSDL 时有多种方法来声明 Web 服务,但是下面的实例重点放在 WebSphere 工具生产的 WSDL 定义集上。

我们首先描述 WSDL 定义和 MXML Web 服务声明(该声明对任何 WSDL 文件都是通用的)之间的映射。这些包括了 MXML 元素和相应的属性,这些属性的值不依赖于专门的 SOAP 绑定设置。然后,我们解释更复杂的映射,它们依赖于操作方式(文档还是 RPC)、使用的编码机制(文字还是编码)、参数的类型(简单还是复杂)、以及参数的数量。

公共映射

使用 MXML 描述 Web 服务的第一步是选择 Web 服务的 WSDL 定义文件。您可以通过设置 <mx:WebService> 元素的 wsdl 属性为 WSDL 文件的 URL 来完成(在更新的 Flex 版本中,您可以使用服务的名称来查询 WSDL 的 URL)。然后您通过设置 <mx:WebService> 元素的 serviceport属性来选择目标服务和端口。图 1 向您展示了在 WSDL 定义的什么地方找到这些属性的值。

图 1:服务和端点映射。顶部:WSDL 文件,底部:MXML 文件
服务和端点映射。顶部:WSDL 文件,底部:MXML 文件
服务和端点映射。顶部:WSDL 文件,底部:MXML 文件

这些属性是可选的。对于 service 属性,它的值缺省为第一个 <wsdl:service> 元素(前缀为 wsdl的 XML 标记表示属于 WSDL 命名空间,并且用来构成一个 WSDL 文件)的name属性值。对于port 属性,它的缺省值是第一个包含在选定的 <wsdl:service> 元素中的 <wsdl:port> 元素的 name 属性值。为了避免混乱,如果 WSDL 定义包括了多个 <wsdl:service><wsdl:port> 元素,最好明确设置这些属性值。

从 WSDL 定义中选定了要使用的服务和端口后,为将要调用的每一个操作都添加一个 <mx:operation> 元素到 <mx:WebService> 元素中。每一个 <mx:operation> 元素的 name 属性都会对应到 <wsdl:operation> 元素(它定义了 Web 服务调用)的 name 属性。选中的 <wsdl:operation> 必须是 <wsdl:service><wsdl:port> 目标的一部分。 图 2向您展示了在 WSDL 定义的什么地方能定位name 属性值。

图 2:操作映射 顶部:WSDL 文件,底部:MXML 文件
操作映射 顶部:WSDL 文件,底部:MXML 文件
操作映射 顶部:WSDL 文件,底部:MXML 文件

<mx:operation> 元素还有其他一些属性,它们的值不依赖于 WSDL 定义,但是也非常值得注意。其中 resultfault 属性是 ActionScript 事件处理器。它们分别包含了 SOAP 响应和 SOAP 错误到达时要执行的 ActionScript 代码。

请求映射

在选中 Web 服务操作后,Flex 的参数绑定机制被用来声明这些操作的参数。正如下列代码所示,每一个 <mx:operation> 元素都包含了一个 <mx:request> 元素,这个元素使用 ‘{}’ 包括了 XML 和 Flex 绑定的混合体。

<mx:WebService>
	<mx:operation>
		<mx:request>
			<node1>{var1}</node1>
			<node2>{var2}</node2>
		</mx:request>
	</mx:operation>
</mx:WebService>

一般来说,映射到 WSDL 或 Schema 的 XML 元素和 MXML 绑定引用到了 <mx:WebService> 元素范围内的变量。

决定 <mx:request> 元素的内容是有一定困难的,因为这需要 WSDL 的 SOAP 绑定规则的知识。尤其是,基于不同的操作方式(document 或 RPC)和编码机制(literal 或 encoded), <mx:request> 元素的内容会映射到不同的 WSDL 元素。

公共映射

面向文档 - 文字

在 WSDL 定义的 SOAP 绑定部分决定了 SOAP 消息体的结构,它再其中设置了使用的操作方式和编码机制。操作方式是通过在 WSDL 定义绑定中的 <soap:operation> 元素(以 soap作为前缀的 XML 标记表示它属于 SOAP 绑定命名空间,并且使用在 WSDL 定义中)的style属性来指定的。它的值可以是document,表示面向文档的操作,或者是rpc,表示 RPC 操作。在一个面向文档的操作中,在 SOAP 体中交换的 XML 文档不会有任何其他封装元素。而且一个 RPC 式的操作中,SOAP 体被结构化来表示一个过程调用。它包含了一个根据操作命名的元素,而这个元素又按顺序包含了一组根据操作参数命名的元素及数据。表 2 举例说明了这两种方式产生的 SOAP 体的不同点。

表 2. 文档及 RPC 方式之间的语义差别
文档方式RPC 方式
<soap:Body>
  <node1>
	  <node2>
	    <node3>data</node3>
	    <node4>data</node4>
	  </node2>
	  <node5>data</node5>
  </node1>
	...
</soap:Body>
<soap:Body>
  <operation_name>
	  <parameter1>data</parameter1>
	  <parameter2>
	    <complex_element>
	      <value1>data</value1>
	    </complex_element>
	  </parameter2>
		...
  </operation_name>
</soap:Body>

编码机制是由绑定中的 <soap:body> 元素的 use属性来决定的。它的值可以是literal,表示是一个 Literal/non-Encoded 消息,或者是encoded,表示这个消息是通过已定义好的一组编码规则来生产。

下面的一组实例通过文档-文字方式来使用一个带 3 个操作的 Web 服务。在这些操作件不同点是它们的参数的数量和复杂度不一样。图 34、及5 举例说明了 <mx:request> 元素的内容是怎样映射到定义在这个 Web 服务的 WSDL 定义中的元素中。

图 3:一个文档-文字式的服务调用的一个操作参数映射
一个 Document-Literal 式的服务调用的一个操作参数映射
一个 Document-Literal 式的服务调用的一个操作参数映射
图 4:一个文档-文字式的服务调用的多个操作参数映射
一个 Document-Literal 式的服务调用的多个操作参数映射
一个 Document-Literal 式的服务调用的多个操作参数映射
图 5:一个文档-文字式的服务调用的一个复杂操作参数映射
一个 Document-Literal 式的服务调用的一个复杂操作参数映射
一个 Document-Literal 式的服务调用的一个复杂操作参数映射

操作请求部分的 <wsdl:message> 元素包含了一个 <wsdl:part> 元素,并使用 element 属性指向模式定义的元素。在文档-文字式的操作请求中,part 指向的元素直接出现在 SOAP 体中,而没有任何其他的封装。因此, <mx:request> 元素的 XML 内容映射到 消息部分指向的模式定义的元素。

面向 RPC - 文字

下面的实例使用了带 3 个操作的 Web 服务,而且这三个操作的参数跟前面实例中的一样,只是在 WSDL 中定义为了 RPC-文字式操作。因为这些原因, <wsdl:message> 元素包含了一个或多个 <wsdl:part> 子元素。每一个 <wsdl:part> 元素通过它的 type属性的值来指向一个模式定义的类型。 图67、及8 说明了在这种情况下 <mx:request> 元素的内容是怎样映射到 WSDL 定义中的元素的。

图 6: RPC-文字服务调用的单参数映射操作。
RPC-Literal 服务调用的单参数映射操作。
RPC-Literal 服务调用的单参数映射操作。
图 7: RPC-文字服务调用的多参数映射操作。
RPC-Literal 服务调用的多参数映射操作。
RPC-Literal 服务调用的多参数映射操作。
图 8:RPC-文字服务调用的复杂参数映射操作。
RPC-Literal 服务调用的复杂参数映射操作。
RPC-Literal 服务调用的复杂参数映射操作。

在一个面向 RPC 的请求中,SOAP 消息体按顺序包含一组元素,它们是按照 <wsdl:part> 元素进行命名的,所有这些元素又被一个按照每一个目标 <wsdl:part> 元素进行命名的元素所封装。每一个按照 <wsdl:part> 命名的元素都属于由 type 属性指定的类型。结果,在 <mx:request> 元素中的顶级 XML 元素都映射为 <wsdl:part> 元素的名称。每一个这些 XML 元素的内容都依赖于相关的 <wsdl:part> 元素的类型。如果是复杂模式类型,如图 8 所示,这些内容可以是其他映射到模式定义元素的 XML 元素。

面向 RPC - 编码

在 RPC - 编码操作调用中, <mx:request> 元素的内容映射到 WSDL 结构的方式跟前面 RPC-文字实例的一样。唯一不同的一点是,SOAP 消息体的内容包含一些额外的类型信息,这是由编码机制生成的。有一点要特别注意,WS-I Basic Profile 1.0 规范推荐中没有包括使用编码机制。它更要求使用 literal(非编码式的)XML。

其他情况

这些实例中使用的 WSDL 定义是由 WebSphere Studio Application Developer V5.1 Web 服务向导自动生产的。因此,生成的 WSDL 定义的文档结构遵守基于操作样式值所表示的协定。 尤其是,对于 Document-style 操作,每一个 <wsdl:message> 元素包含一个 <wsdl:part> 元素,用来指向一个模式元素。对于 RPC 式的操作,每一个 <wsdl:message> 元素按顺序包含一组 <wsdl:part> 元素,用来指向模式类型。在一个 Literal 消息中,SOAP 体的内容依赖于 <wsdl:part> 是指向一个元素还是类型。表 3 列举了可能的结合,并解释了相应的消息体(阴影单元代表了上面实例的情况)。

表 3. 当使用文字 XML 时可能的消息部分定义和相应的消息体
操作方式Part 指向SOAP Body
Documentelementpart 指向的元素出现在消息体内
typepart 指向的类型被用作消息体的模式类型(不能处理多个 part)
RPCelementpart 指向的元素出现在根据 part 命名的封装元素内
Typepart 指向的类型被用作根据 part 命名的封装元素的模式类型。

结果映射

直到现在,我们都集中在定义调用一个 Web 服务操作所需要的 MXML 元素。现在我们讨论一下怎样处理从 Web 服务调用后接受到的结果。正如上面所提到的,Flex 把所有的 Web 服务调用都当作异步处理,这意味着客户端不会因为等待 Web 服务的响应而阻断,而是继续执行,而且一旦收到结果消息就触发一个事件。 <mx:operation> 标记的 result属性指向在结果消息一旦被接受后要执行的 ActionScript 代码。Flex 将把 SOAP 响应反序列化为 ActionScript 对象的一张图。operation对象的result成员是对该图的引用。结果对象的全限定名如下所示:

<value of WebService id>.<value of operation name>.result

ActionScript 中的点号(.)被用来更深层次地浏览结果对象,但这个需要您知道在响应 XML 中result对象代表了什么。映射 Web 服务请求到 WSDL 文件的规则,被相同地应用到了映射result 对象到 WSDL。

结束语

组织迅速采用包括 Web 服务在内的策略的转移,对于充分掌握开发环境以创建使用这些环境的应用程序来说,是很有好处的。此外,既然 WSDL 一般来说是唯一的 Web 服务描述语言,为了开发整合了现有服务的应用程序,这可能是非常乏味而耗时的。Macromedia Flex 是一个 Rich Internet Application 平台,它完全定位于解决这些需求问题。通过利用大多数系统在 Web 服务上的巨大投资,设计人员和服务器端开发人员一样可以很容易地开发出交互式的可视化应用程序。我们已经示范了只需一点点 WSDL 定义结构的知识以及了解它们如何与 Flex 的 <mx:WebService> 声明相关联,就能快速地开发出强大而诱人的使用 Web 服务的应用程序,从而使快速开发使用 Web 服务的应用程序变成实实在在可以完成的需求。

获得本文中使用到的工具

如果您是 developerWorks 的订户,您拥有单用户的使用许可,已使用 WebSphere Studio Application Developer 及其他 DB2®、Lotus®、Rational®、Tivoli®,以及 WebSphere 产品 -- 包括基于 Eclipse 的 WebSphere Studio IDE -- 来开发、测试、评估以及演示您的应用程序。


相关主题


评论

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=23122
ArticleTitle=使用 Macromedia Flex 开发 Web 服务客户端
publish-date=09012004