SitePoint 上有许多教程可以帮助您领会使用 Flex 和 AIR 创建富 Internet 应用程序(Rich Internet Applications,RIA)的重要原则。您将发现,在 Flex 中进行的大多数开发都涉及到一个与 Flex 客户端交互的后端应用程序。
我们来探讨一下 Flex 应用程序所含内容背后的一些理论和原则,然后通过一个 ColdFusion 应用程序将这些原则应用于实践。我们将假设您已经具有一定的 ColdFusion 开发经验。
请注意,文末有一个测试。前 100 位完成测试的人员将获得由我们的赞助商 Adobe 提供的 Getting Started With Flex 3 的一个副本。进行测试!
了解富 Internet 应用程序的体系结构
从较高的层次来看,Web 应用程序的常见系统体系结构通常包含 3 层。
底层为数据存储层,通常为一个关系数据库系统,比如 Microsoft SQL Server、Oracle 或 MySQL。该层提供了一个关系表模型,该模型可用于存储和检索应用程序数据。
数据存储层之上的一层称为应用服务器或中间件。这一层上的常用技术包括 Adobe ColdFusion、Java、PHP、Ruby on Rails 或 .NET。这些平台用于开发业务和数据访问逻辑。
在这一层之上,或者在嵌入中间件内部,我们会发现一个负责 HTTP 传送的层,也就是 IIS 或 Apache 等 Web 服务器。在富 Internet 应用程序中,架构师有时必须处理除 HTTP 之外的其他协议:例如,Flash Media Server 等技术支持实时流传输协议 RTMP。
在我的早期教程中展示了 Flex 应用程序如何与客户端上的其他应用程序和数据通信。现在,我们将展示 Flex 应用程序与服务器端上的业务和数据层之间的通信。
Flex 如何通信
Flex 主要通过 3 种不同方法来访问远程数据:
对交付可供 Flex 处理的数据的平面文件、XML 文件或动态 URL 的 HTTP 调用
基于 SOAP 的 web 服务调用
动作消息格式(Action Message Format,AMF)远程对象调用。
每种方法由不同的 ActionScript 类和 MXML 标记来表示。可以说,在 ColdFusion 后台上,MXML 标记语法更容易使用,因为您已经熟悉与 ColdFusion CFML 语法类似的语法了。
HTTPService:检索通过 HTTP 协议传输的数据
我们分析一下 mx:HTTPService 标记。毫无疑问,它是一个基于 HTTP 的服务,我们可以使用它来在运行时从其他地方获取数据。在 MXML 中,这类服务的声明如下:
<mx:HTTPService id="dataService" url="http://www.example.com/xmlfile.xml" />
id 属性提供了对服务对象的引用。url 属性指向一个可通过 HTTP 访问的静态 XML 文件,但它也可以指向一个本地文件,比如:
<mx:HTTPService id="dataService" url="xmlfile.xml" />
在本例中,Flex 应用程序希望找到它所在路径下的 XML 文件。
当然,可以让 ColdFusion 为我们生成某个 XML 文件。可以采用一种非常简单的方式来完成此操作:
该标记将创建的静态或动态内容存储在一个变量 xmlContent 中。我们然后使用 cfcontent 标记来重置之前创建的任何输出,指定一个 text/xml 内容-类型。然后使用一个简单的 cfoutput 标记传送 xmlContent 变量的内容。这样可以得到一个 XML 文件。
在下一页,我们将看一个使用该 XML 文件的 Flex 应用程序。
可用于这类服务调用的 Flex 应用程序如下所示:
这段程序的思路是:我们使用一个 mx:HTTPService 来获取一些数据,将来自服务的结果存储在一个 budgetData 变量中。标记上的 creationComplete 事件处理程序在创建应用程序时发送 HTTPService 请求。最后,mx:DataGrid 对象将数据显示为表。
仔细分析一下 mx:HTTPService,我们会看到它包含两个属性:result 和 fault。在 Flex 中,任何数据服务请求都是异步处理的,这意味着 Flex 应用程序将会立即广播结果事件,而不是等待响应。所有服务标记都提供了 result 和 fault 属性来处理这些结果。在这些属性中,您只是指定了希望在服务调用返回结果(或错误)时被调用的方法名称。
实际上,mx:HTTPService 实例仅能发出 GET 和 POST 请求,理论上也可以发出其他请求,但只有 HTTP 请求通过代理服务器(比如 Adobe BlazeDS 或 LiveCycle Data Services)来路由时才能使用其他请求。存在此限制的原因在于,Flash Player 的安全模型仅支持通过 HTTP 直接执行 GET 或 POST 调用。这就涉及到了另一个概念:跨域策略文件。
在正常情况下,使用 mx:HTTPService 的基于 Flash 的应用程序或基于 SOAP 的 Web 服务可能仅检索与 .swf 文件存储在同一个服务器上的服务或文件的数据。为了确定数据是否来自相同域,Flash Player 比较用于 Flash 文件的域名和用于远程数据源的域名。这意味着从 http://localhost/test.swf 加载的应用程序无法访问来自 http://127.0.0.1/data/xmlfile.xml 的 HTTP 数据,即使它们位于相同的服务器上。一个解决方案是使用跨域策略文件 crossdomain.xml,该文件位于要提供数据的服务器的 Web 根目录下。可以在 Adobe 的文档中了解关于如何使用跨域策略文件的更多信息。
接下来,我们看看 Flex 中的发送请求参数。
发送请求参数
有时需要向服务发送参数。传入参数的最简单方式是将一个 mx:request 标记添加为 HTTP 服务的一个嵌套标记。假设我们需要向一段 ColdFusion 脚本发送两个参数 dataMethod 和 userType。我们可以按照如下方式使用 mx:request 元素:
因为我们使用了 HTTP POST 方法,所以我们在此处创建的所有请求变量都将成为 ColdFusion 的 FORM 作用域中的 ColdFusion 变量。在 ColdFusion 端,我们最终将使用 FORM.dataMethod 以及 ColdFusion 模板上的 FORM.userType。如果您选择了 HTTP GET(通过指定 method="GET"),您的请求数据将变为 URL 变量:在本例中为 URL.userType 和 URL.dataMethod。
目前为止,我们了解了从 ColdFusion 模板通过 HTTP 服务返回 XML 数据的过程。这是与 HTTP 服务和 ColdFusion 交互的一种极为常用的方式,但还有其他方式,比如在某些情况下返回 HTTP 服务的格式可能更适用:
object:响应数据为 XML 格式,将被转换为一个 ActionScript 对象树(ArrayCollection、ObjectProxy)
xml:响应数据为 XML 格式,将被转换为一个类型为 XMLnode 的 ActionScript 对象——这是一种旧版格式,在这里提供它只是为了实现兼容,最好避免使用它。
e4x:响应数据为 XML 格式,将被转换为一个 ActionScript XML 对象
flashvars:响应数据为一个键/值对链:name1=value1&'name2=value2 等
text:响应数据为文本,不会进行转换。
resultFormat="object" 为默认的格式,通常也是正确的交互方式。如果希望使用 XML,而不是 ArrayCollections 和 ObjectProxy,那么 e4x(面向 XML 的 ECMAScript)是首选的结果格式——xml 使用 Flex 中包含的一组不再受支持的 API 类只是出于兼容性原因。
通过 ColdFusion 提供服务
我们已经花了大量篇幅来探讨 HTTP 服务和服务的一般结构。既然我们理解了这些服务的工作原理,那么讨论 Web 服务和远程对象就会比较轻松。
下面的 ColdFusion 组件提供了一个简单的 echo 方法,我们尝试构建一个 Flex 客户端来连接该 CFC:
ColdFusion 提供了两种将该组件的方法向调用者公开的方式:作为一种基于 SOAP 的Web 服务或者作为一个远程对象。我们分别尝试每种方法。
SOAP
首先看看 SOAP web 服务,我们已经通过设置 cffunction 标记中的 access="remote" 属性,将 echo 方法发布为一种 web 服务。同时,此设置将支持以远程对象的形式调用该方法。我们想要以 WSDL 格式检索数据,这可以通过向 URL 末尾添加 ?WSDL 来完成。
要在 Flex 中获取该 WSDL 文件,我们首先使用结构与 mx:HTTPService 及其相似的
借助 web 服务,您通常会发现服务提供了多个方法,并且您希望为每个服务指定一个结果或错误处理程序方法。这可以使用 mx:operation 来完成:
向 Web 服务调用提供参数的方式与向 HTTP 服务调用提供参数的方式类似,都是通过 mx:request 实现的,但是前者也可以使用 Java 或 C++ 开发人员熟悉的语法来完成:
dataWS.echo("Hello")
动作消息格式
现在,我们尝试使用动作消息格式(Action Message Format,AMF)来公开方法。AMF 是一种已经诞生很久的协议,AMF3 的规范由 Adobe 于 2007 年 12 月公布。在服务器端,需要一个启用了 AMF3 的服务——幸运的是,ColdFusion 开发人员可以轻松地提供这种类型的服务。
在 Flex 中,我们可以使用 mx:RemoteObject 标记来与远程对象通信:
比较此代码与 Flex 中类似的 Web 服务声明,将会发现一些细微区别:我们现在使用的是一个名为“ColdFusion”的目标,而且 mx:operation 已经更改为 mx:method。
当在 Flex Builder 中首次设置用于 ColdFusion 的 Flex 项目时,设置向导将询问大量与 ColdFusion 服务器位置、服务器端口、URL 和上下文根目录相关的问题。在编译 Flex 应用程序时,这些信息将用于向 Flex 提供您的 AMF URL 细节。这种方法很有效,能够轻松处理简单数据类型(比如字符串或布尔值),或者甚至内置的 ColdFusion 类型(比如数组和结构)。
您可能希望从应用程序的业务域处理所有对象,并来回传输它们。有一种设计模式(称为数据传输对象或值对象)描述了这类过程,将此方法与 ColdFusion 组件结合使用非常简单。Flex 中的服务配置在绝大部分情况下会保持相同,但是不会向远程对象调用发送或从其接收简单类型,它将是一个域对象:表示客户、购物车、员工或者您计划处理的任何实体的对象。要让 Flex 处理这类复杂的对象类型,ColdFusion 必须了解它们,而且 ColdFusion 中还需要有一个等效组件。以下是描述一个用户的 CFC:
在下面这个精简的 ActionScript 3 类中,我们还描述了一个 User 对象应该包含的内容
元数据标记 [Bindable] 支持在 Flex 数据绑定中使用 User。[RemoteClass(alias="example.User")] 将服务器端的 CFC 类型 example.User 映射到 ActionScript 中的这个 User 类。
结束语
目前为止,我们了解了哪些内容?如果仅使用 ColdFusion,将 RemoteObjects 用于这些项目类型会更简单。如果拥有一个包含多项技术的混合环境,深入了解 Web 服务和用于加载 XML 的 HTTP 服务调用可能很有用。无论如何,您现在已具备了处理这些情况的能力。可以稍微放松一下了!
本文来自:http://www.sitepoint.com/article/flex-app-coldfusion-power/