Spring ActionScript 开发教程


郭少瑞原创教程 www.richbox.net/blog Spring ActionScript 开发教程 作者:郭少瑞 博客:http://www.richbox.net/blog 郭少瑞原创教程 www.richbox.net/blog 目录 Spring ActionScript开发教程 ............................................................................................................ 1 Spring ActionScript入门教程(1)-简介 .............................................................................................. 4 Part1:介绍Spring ActionScript ............................................................................................... 4 Part2:安装Spring ActionScript Framework ............................................................................ 4 Part 3: 使用Spring ActionScript中的XML配置 ........................................................................ 5 Part 4: 使用容器载入配置文件 ............................................................................................ 10 Spring ActionScript入门教程(2)-一个简单的实例 ........................................................................ 11 准备工作 ................................................................................................................................. 11 开始 ......................................................................................................................................... 11 Spring ActionScript入门教程(3)-Spring和Cairngorm的结合使用[上] ........................................... 15 准备知识: ............................................................................................................................. 16 实现项目:RSS阅读器 ................................................................................................................... 16 Part1 新建项目 ...................................................................................................................... 16 Part2 配置libs ........................................................................................................................ 17 Part3 实现SpringActionScriptCairngormDemoLib ................................................................. 17 3.1 构建MVC目录结构 .................................................................................................. 18 3.2 实现model ............................................................................................................... 18 3.3 创建自定义事件 ...................................................................................................... 20 3.4 构建视图 .................................................................................................................. 21 3.5 实现代理 .................................................................................................................. 22 3.6 实现Command ......................................................................................................... 24 3.7 实现工厂类 .............................................................................................................. 26 3.8 实现工具类ApplicationViewAssembler .................................................................. 28 Spring ActionScript入门教程(3)-Spring和Cairngorm的结合使用[下] ........................................... 29 Part4 实现主项目SpringActionScriptCairngormDemo .......................................................... 29 4.1 配置编译参数 .......................................................................................................... 29 4.2 写配置XML .............................................................................................................. 30 4.3 实现IoC容器载入 .................................................................................................... 33 如何使用Spring ActionScript中的EventBus ................................................................................... 34 使用Spring ActionScript的时候编译所需类的 6 种方式 .............................................................. 38 问题 ................................................................................................................................. 38 解决方案(根据你的需要选择一种方式) ................................................................. 38 Spring ActionScript对于Module的支持 ......................................................................................... 47 Spring ActionScript一些有用的小技巧 .......................................................................................... 50 Spring ActionScript Operation API入门教程[一]:简介 ................................................................... 55 Operation API简介 .................................................................................................................. 55 Operations, commands, services and tasks ............................................................................ 56 Operation(操作) .............................................................................................................. 56 Command(命令) ............................................................................................................. 57 Service(服务) ................................................................................................................... 58 Task(任务) ....................................................................................................................... 60 Spring ActionScript Operation API入门教程[二]:实例 ................................................................... 65 郭少瑞原创教程 www.richbox.net/blog 郭少瑞原创教程 www.richbox.net/blog Spring ActionScript 入门教程(1)-简介 这是一个系列文章,总共 3 篇,RIAMeeting将在这 3 篇文章中为大家讲述Spring ActionScript的基本概念以及使用方法,通过学习这 3 篇文章,开发者可以创建 出一个简单的Spring ActionScript的应用,并体会到Spring ActionScript带来 的优势和便捷性。 当然,基本上所有的框架的最大价值在于它给你的结构上的规范和指导意义,所 以我们在使用框架的时候,应当尽量去体会框架对于自己编程思想的提升,如 果 只是为使用框架而是用框架,就会感觉框架繁琐而且加大工作量,增加编码体积, 实际上框架的最大优势都是在后期才体现出来的(比如当项目趋于扩大化时的维 护,管理和团队协作)。 Part1:介绍 Spring ActionScript 首先,我们先来介绍一下 Spring ActionScript,如果你来自 Java 社区,应该 对 Spring 并不陌生,实际上在 Java 社区中 Spring 作为替代 J2EE 的一个轻量级 的框 架有着非常广泛的应用。Spring 包含两个方面的重要功能:IoC 和 AOP, 大家用到 Spring 最多的地方实际上也是 IoC。另一个方面 AOP 面向切 面在 AS 中不被支持。简单的说,Spring ActionScript 是 Spring 在 ActionScript 中的 实现。 名词解释: IoC:控制翻转(inverse of control),Spring 通过一种称作控制反转(IoC) 的技术促进了松耦合。当应用了 IoC,一个对象依赖的其它对象会通过被动的方 式传 递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为 IoC 与 JNDI 相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象 请求就 主动将依赖传递给它。 DI:Dependency Injection (DI),即依赖注入。 Part2:安装 Spring ActionScript Framework 在这里以 Flash Builder4 为例说明如何安装 Spring ActionScript Framework。 Flash Builder 是 Flex Builder 的最新版本(从 4 的版本开始更名为 Flash Builder)目前还是 Beta 版,但它从各方面来说都比 Flex Builder3 提升了不少, 所以我们这里使用 Flash Builder4 以提升编程的效率。 言归正传,如果我们需要安装为 Flash Builder 安装 Spring ActionScript Framework,需要遵循以下的步骤: 郭少瑞原创教程 www.richbox.net/blog 1. 安装Flash Builder4,你可以从Adobe的网站(http://labs.adobe.com)下载 Flash Builder4 的安装文件,这个过程非常简单,界面也非常容易使用,因为Flash Builder是基于 Eclipse的。 2. 创建一个新项目,或者导入原有的 Flex Builder3 的项目 3. 下载Spring ActionScript Framework的SWC文件,下载地址在本文的最底部 4. 下载依赖的第三方 SWC 文件,因为这个项目依赖了很多第三方的类库,所以需要你 把这些依赖的类库也都下载下来,这些类库包 括:as3commons-reflect.swc , as3commons-lang.swc , as3commons-logging.swc , flexunit.swc,这些都在最底部的压 缩文件中被包含,下载即可 5. 将所有下载的 SWC 文件移动到你的项目的 Libs 目录,然后你需要修改编译参数,将 这些类库编译到 SWF 中去,步骤是:打开项目属性面板,定位到 Flex Compiler 选项, 找到 additional compiler arguments,输入类似于下面的语句:-locale en_US -default-background-color #000000 -include-libraries ../libs/spring-actionscript.swc ../libs/as3commons-reflect.swc ../libs/as 3commons-lang.swc ../libs/as3commons-logging.swc ../libs/flexunit.swc 参见图片说明,点击查看大图: 在上面我们稍感麻烦的一点是还要手工把所有的依赖的 SWC 编译进去,否则运行 时会找不到依赖的库,一旦项目依赖的库比较多,这个配置代码就会很长,也会 给部署的人带来麻烦,针对这种情况,Maven 有非常好的解决方法,参见 RIAMeeting 关于 Maven 的介绍文章: 1. http://www.riameeting.com/node/445 2. http://www.riameeting.com/node/446 3. http://www.riameeting.com/node/447 Part 3: 使用 Spring ActionScript 中的 XML 配置 Spring ActionScript 允许你使用 XML 描述文件来定义你需要在应用中使用的实 例以及它们之间的相互依赖关系。这个 XML 文件可以是一个外部的 XML 文档,也 郭少瑞原创教程 www.richbox.net/blog 可以是一个内嵌的 XML(嵌入到 Flex 的 MXML 中作为元数据存在)。这两种方式 都被支持,只是在使用上稍有区别。 非常需要注意的是在 Flex 中使用 Spring,必须要保证被依赖的类被编译到 SWF 中,否则会报运行时错误(无法找到所需的类),解决方法参加 Part2 的编译器 参数部分。 下面我们来讨论如何编写 Spring 的配置文件,这个配置文件遵循 XML 结构,我 们先来看一个典型的配置文件,你可以打开你的 Flash Builder4,然后新建一 个文本文件,命名为"application_context.xml",然后粘贴下面的代码片段到 这个文件中: 1. 2. //行 1 3. //行 2 4. //行 3 5. //行 4 6. //行 5 7. //行 6 8. 9. 对于熟悉 XML 的朋友,这段配置非常容易理解,主要包含以下几个方面: 1. 支持导入 xml 文件(参加行 1,2,3),就是说,我们可以按照一定的规则拆解 XML 中的内容到不同的文件,以便于管理和维护,方法是使用 import 标签 2. 实例化一个对象,使用 object 标签(参见行 4,行 5),其中有两个必须的属性,即 id 和 class,id 代表对这个 object 的引用,class 代表这个 object 对应的类,注意要写全 类名和包路径,比如:class="mx.containers.Panel" 3. 使用 property 属性定义这个 object 的依赖(参见行 6),比如这个 object 需要的一些字 符串类型的数据,以及对另外一个对象的引用等等,如果是直接赋值,使用 value, 引用则使用 ref 我们还可以使用定义外部变量(常量)的方式,将一些配置方面的信息以变量或 常量的形式定义在外部,以便于部署和维护时候的修改,通常我们会建立一个类 似于 prop.properties 这个的一个文本文件,然后使用下面的变量声明方式来声 明变量: 1. s1=First string 郭少瑞原创教程 www.richbox.net/blog 2. s2=Second string 在 XML 中引用,使用${s1}的方式来引用: 1. 2. 3. 4. 5. 6. 7. 8. 9. 还可以在一个对象的内部使用内联对象,举例: 1. 2. 3. 4. 5. 6. 7. 8. 下表是在配置文件中常用的一些标签以及相关的说明和用法 术语 说明 代码示例 ${变量名} 你可以把一些变量分离出来写在单 独的文本文件中,然后在配置中引 用这些变量,这样最大的好处是你 可以把配置信息比如 Server 端的连 接地址放在单独的文件中,方便修 改和维护 新建 global.prop 文本文件,写入: variable1=10 在配置中引用: ${variable1} object 在 XML 配置中,每一个对象用 Object 来表示,然后分别用 id 和 class 代表 唯一标示和类的名称 property 你可以使用 property 为对象的属性 复制,这也是 IoC 的精髓,即从这里 把依赖注入到对象。name 就是属性 的名称,而 value 就是你要赋予的具 体的值 郭少瑞原创教程 www.richbox.net/blog ref 除了可以直接赋值,你也可以通过 使用 ref 在属性中引用别的对象 constructor-ar g 如果你的对象实例化的时候需要从 构造函数中传入参数,那么可以使 用这个属性,将所需的参数传递进 去 anotherExampleObject factory-meth od 工厂方法,含义是不使用 new 对这 个 Object 进行实例化,而是调用这 个类的静态方法,可用于单例模式 的实现 dictionary 相当于 AS3 中的 Dictionary,你可以 在配置中声明一个 Dictionary 对象 development dx array 同样,你可以在配置中声明一个数 组对象 ssnce array-collectio n 对应 Flex 中的 ArrayCollection,当然 只有 Flex 的应用才可以使用这个配 置方式 ssnce depends-on 定义依赖关系,含义就是先初始化 它的依赖,然后初始化自己 depends-on="manager,accountDao" lazy-init 如果值为 true,则不马上初始化,而 是在第一次调用的时候才初始化 autowire 自动装配,Spring ActionScript 支持自动装配, 含义就是你只要声明某个对象 郭少瑞原创教程 www.richbox.net/blog 为自动装配,它就会按照规则自 动去寻找这个对象的依赖并注 入给它,而不需要手工操作。 默认是 no,可以选择 byName,byType,constructor,a utodetect 来自动装配对象的 依赖。使用自动装配时,应当权 衡利弊,合理的与 ref 的方法相 结合,尽量在降低工作量的同 时,保证应用的可维护度 singleton 一个布尔量,对一个对象而言,这 个属性的设置为 True 则只创建一个 实例,false 则每次调用都创建新的 实例 init-method 初始化方法,含义是创建实例后, 调用实例的这个方法进行初始化 init-method="init" method-invoc ation 调用对象的方法 abstract 定义继承关系,你可以将一个对象 的 abstract 属性设置为 true,然后在 另一个对象中定义 parent=这个对 象,含义就是继承原对象的所有的 属性 template 你可以将重复性的设置工作定义为 模板,然后其它对象就可以使用这 个模板 郭少瑞原创教程 www.richbox.net/blog application Flex 专属属性,你可以通过配置下面 这个对象:,然 后就可以在其他的配置中使用 application 这个变量,使用方式 是: ${application.url} • application.frameRate • application.historyManagementE nabled • application.pageTitle • application.resetHistory • application.scriptRecursionLimit • application.scriptTimeLimit • application.url • application.url.protocol • application.url.host • application.url.port • application.usePreloader • application.viewSourceURL Part 4: 使用容器载入配置文件 上面我们讨论如何编写一个配置文件,然后我们看一下如何在 Flex 中载入并解 析这个文件。 首先需要了解的是,我们如果要在 Flex 中使用 DI 注入对象,需要使用一个 IoC 容器来做这件事。 FlexXMLApplicationContext 或 XMLApplicationContext 是 Spring 关于 IoC 的基础容器。两者基本相同,第一个只是增加了对 Flex 的支持, 比如 ArrayCollection。一般也认为这是程序的入 口,我们写代码的开始会用 到这两个类,用于载入和分析配置文件(XML)。 使用容器载入配置的代码示例: 1. var applicationContext:XMLApplicationContext 2. = new XMLApplicationContext(); 3. applicationContext.addConfigLocation("application-co ntext.xml"); 4. applicationContext.addEventListener(Event.COMPLETE, handleComplete); 5. applicationContext.load(); 在下一个章节,我们将来讲述使用 Spring ActionScript 创建一个简单的实例, 而在第三个章节,我们则会引入 Cairngorm。 郭少瑞原创教程 www.richbox.net/blog Spring ActionScript 入门教程(2)-一个简单的 实例 上一篇:对Spring ActionScript的简介 在这个部分,我们来使用前一章学到的知识,建立一个简单的 Spring ActionScript 的应用。你可以认为这是学习 Spring ActionScript 的一个类似 于“Hello World”的例子,在这个例子里,我们将创建一个简单的列表,来显 示一些模拟的数据,好,让我们开始下一步的操作。 图 1:实例界面截图 准备工作 1. 安装 Flex Builder 2. 准备好 XML 编辑工具,因为 Spring ActionScript 中依赖 XML 来描述结构,所以一个 好用的 XML 编辑器是必不可少的,你可以为 Flex Builder 安装 XMLBuddy 插件,也可 以使用 Notpad++等独立的文本编辑器 开始 首先打开 Flex Builder3 (当然也可以是 Flash Builder4),创建一个新项目 (Flex 项目),命名为“SpringActionScriptDemo”,其它保持默认,直接点 击 “Finish”完成,短暂的时间过后,Flex Builder 就为你创建了一个空项目, 并且创建了一个 SpringActionScriptDemo.mxml 的程序文件,在编辑器中处于打 开状态。 编辑器中的代码应该如下面所示: 郭少瑞原创教程 www.richbox.net/blog 1. 2. 3. 当然这只是一个空的 Application,里面什么也没有,然后我们需要做的是,把 Spring ActionScript 的类包 SWC 文件引入进来,找到上个章节中提供下载的压 缩包,解压后你会看到若干的 SWC 文件,将这些文件转移到你的项目中的 libs 目录,这个目录是默认的项目引用库,放在这里是为了让你的代码可以引用到这 些类包。 转移好之后,你的 libs 目录看起来应该是这个样子: 图 2:Libs 结构 然后我们将在 src 目录下面建立一些文件。下面的步骤如无特殊说明,新建文件 都基于 src 目录,这里因为文件足够少而且简单所以没有分目录存放,实际上一 个正式的项目的文件复杂度远大于此,需要仔细拆分和优化目录结构。 首先我们建立一个命名为“global.prop”的文本文件,用来存放全局的一些变 量,这里我们先存放一下界面的标题,输入以下的文本: siteName=test site 因为这个应用要显示一些虚拟的数据,所以我们建立一个命名为"data.xml" 的 XML 文件,并输入下面的内容: 1. 2. 3. 4. 5. Zhang San 郭少瑞原创教程 www.richbox.net/blog 6. Li Si 7. Wang wu 8. 11111 9. 22222222222 10. 33333333333 11. 12. 13. 14. XML 内容分析:我们可以看到,我在里面声明了一个 object,id 是 myData,这 个一会儿我们就会引用到,类别是 ArrayCollection(ArrayCollection 是 Flex 的一种数据集合),然后通过使用 construtor-arg 传递一个数组对 象进去,实 现了给 ArrayCollection 赋值。 下面建立最重要的一个 XML 配置文件,命名为”appliction-context.xml“,输 入下面的内容: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. XML 分析:第一行和第二行分别引入了变量文件和定义数据的 XML 文件,然后我 们定义了两个显示对象,一个是 Panel,一个是 List。我们设置 了 List 的一些 属性,包括定义 dataProvider,引用了在 data.xml 中定义的 myData 的数据, 然后我们调用了 Panel 的 addChild 方法,将 List 放到 Panel 中。 到这里 XML 部分的配置工作就做好了,下面我们来看如何在 Flex 中载入并解析 这些配置文件: 郭少瑞原创教程 www.richbox.net/blog 回到 SpringActionScriptDemo.mxml,建立一个代码块儿,然后输入建立 IoC 容 器的代码,之后整体的代码应该如下所示: 1. 2. 3. 4. 17. 18. 按下 F11 键,调试项目,怎么样,是否看到一个显示数据的列表了? 郭少瑞原创教程 www.richbox.net/blog 好了,到这里一个简单的 Spring ActionScript 的例子就完成了,我们将在下一 个章节中深入探讨如何结合 Cairngorm,这样才能适应一个大型项目的开发流程。 附件中是本实例的源码。 附件下载 Spring ActionScript 入门教程(3)-Spring 和 Cairngorm 的结合使用[上] 在前两篇文章中 RIAMeeting 给大家介绍了 Spring ActionScript 的基本概念并 完成了一个简单的例子,在这个章节,RIAMeeting 将结合 Cairngorm 完成一个 RSS 阅读器的实例 (Spring ActionScript 还有一个针对 Cairngorm 的项目叫做 Spring ActionScript Cairngorm,针对 PureMVC 的项目也在开发中),在这个 过程中我们将会了解 IoC 和 MVC 框架的各自的优势以及如何将它们结合在一起来 构建一 个真实的项目。www.riameeting.com 出品[请勿转载] 图 1:Demo 界面 www.riameeting.com 出品[请勿转载] 演示地址:www.riameeting.com 出品[请勿转载] http://www.riameeting.com/examples/SpringASCairngormDemo/SpringAction ScriptCairngormDemo.html 郭少瑞原创教程 www.richbox.net/blog 提示:你可以在 Demo 上点击右键查看源码。 准备知识: 1. Spring ActionScript简介 2. 使用Spring ActionScript开发一个简单的实例 关于 Cairngorm 的简单介绍: Cairngorm 是指导 Flex 开发以MVC(Model-View-Control)模式进行的架构框架, 这也是 Adobe 官方认可并推荐的一个框架。它的重点在于给你一个指导性原则, 而并非具体实现,它要实现的目的就是提高项目的可维护性和灵活性,和重用 (注意是功能上的重用,而非代码级的重用)。它是一个由多个设计模式组合而 成的集合体。 你可以参阅这篇文章,了解关于 Cairngorm 的详细介绍: http://www.riameeting.com/node/134 实现项目:RSS 阅读器 接下来的内容,我们假定项目需求是实现一个 RSS 阅读器,这个阅读器只需实现 载入并分析 Feed 地址,显示 Feed 内容即可,在这个项目中我们将综合使用 Spring ActionScript 和 Cairngorm。 另外这个实例需要你安装Flex Builder3 或者Flash Builder4,你可以在Adobe的 站点下载到这些IDE。请事先了解这些IDE的基本操作知识,本文假定您已经具备 了使用Flex Builder的基本技巧,在操作环节上不会做过于细致的介绍。 Part1 新建项目 首先打开 Flex Builder,创建两个项目: 1. 第一个项目,名为“SpringActionScriptCairngormDemo”,类型是 Flex 项目,保持默认 选项,直接点击 Finish 完成项目创建。 2. 第二个项目,名为“SpringActionScriptCairngormDemoLib”,注意类型是 Flex 库项目 (Flex Library Project)。 这里介绍一下为什么要创建两个项目,第一个项目是我们要用的主项目,在这个 项目中我们将使用 IoC 容器,使用反射的机制根据配置文件从 SWF 中找到 所需 的类并实例化,这就需要最终编译的 SWF 文件中应当包含所有用到的类(Flex 类库和项目自己的类库),如果我们将项目自己的类库也作为 SWC 形式存 在将 郭少瑞原创教程 www.richbox.net/blog 非常有利于编译到主 SWF,这也是第二个 Lib 项目存在的原因;第二个项目做为 一个库项目存在,包含了这个 RSS 阅读器项目的主体代码和实现,我们的 主要 代码工作也是在这个 Lib 库里面,第一个项目只是完成最终的装配工作。 Part2 配置 libs 同前一章类似,我们也需要将项目依赖的 SWC 文件放到项目的 libs 目录以便编 译时引用,请先下载下面的压缩包: http://www.riameeting.com/files/libs_0.rar 下载后解压,你会看到一些 SWC 文件。 对于项目“SpringActionScriptCairngormDemo”,直接将这些文件拷贝到这个 项目的 libs 目录中即可。 对于项目“SpringActionScriptCairngormDemoLib”,因为这个库项目本身不包 含 libs 目录,我们需要在项目中手 工创建这样一个目录,拷贝 SWC 文件到这个 目录中,然后对项目做一下设置,在 Build Path 部分加入这个包含 SWC 的目录: 图 2:Flex Library Build Path Part3 实现 SpringActionScriptCairngormDemoLib 在第三部分我们来实现 Lib 项目的编码,让我们回到 “SpringActionScriptCairngormDemoLib”项目。 郭少瑞原创教程 www.richbox.net/blog 3.1 构建 MVC 目录结构 这个项目是基于 MVC 架构的,那么我们首先完成一些目录结构的创建,在 src 目录下,先创建包 com.riameeting,(即先创建一个目录 com,然后在 com 里 创建一个目录 riameeting),在 riameeting 目录中创建以下的目录结构,注意 中文部分是说明文字: 1. business 这个目录用于存放服务的代理,代理将组件与服务之间进行了解耦 2. command 这个目录用于存放命令,在 MVC 结构中通常命令承担主要的逻辑控制工 作 3. event 存放自定义事件 4. factories 这个目录用于存放工厂类,工厂类将承担一部分的组装工作 5. model 存放数据模型,通常将 MVC 结构中的 ModelLocator 放在这个目录下 6. utils 存放自定义的一些支持项目的类 7. view 存放视图 3.2 实现 model 首先我们先设计好项目的数据模型,对这个项目来说,基本上数据就是两个:Feed 地址,和 Feed 的 XML 内容,那么我们先声明一个接口,定义对这两条数据的存 放。 在 model 下创建一个接口,名为 IApplicationModel,并声明获取 Feed 地址和 Feed 内容的方法: 1. package com.riameeting.model 2. { 3. import mx.collections.XMLListCollection; 4. [Bindable] 5. public interface IApplicationModel 6. { 7. // 8. function get feedURL():String; 9. function set feedURL(url:String):void; 10. // 11. function get feedList():XMLListCollection; 12. function set feedList(dataList:XMLListCollection):void; 13. } 14. } 创建类 ApplicationModel,实现接口 IApplicationModel,并使用单例模式。 郭少瑞原创教程 www.richbox.net/blog 1. package com.riameeting.model 2. { 3. import mx.collections.XMLListCollection; 4. [Bindable] 5. public class ApplicationModel implements IApplicationModel 6. { 7. public function ApplicationModel(enforcer:SingletonEnforcer){} 8. 9. private static var me:ApplicationModel; 10. public static function getInstance():ApplicationModel { 11. if(me==null) { 12. me = new ApplicationModel(new SingletonEnforcer); 13. } 14. return me; 15. } 16. 17. private var _feedURL:String; 18. 19. public function get feedURL():String 20. { 21. return _feedURL; 22. } 23. 24. public function set feedURL(url:String):void 25. { 26. _feedURL = url; 27. } 28. 29. private var _feedList:XMLListCollection; 30. 31. public function get feedList():XMLListCollection 32. { 33. return _feedList; 34. } 35. 36. public function set feedList(dataList:XMLListCollection):void 郭少瑞原创教程 www.richbox.net/blog 37. { 38. _feedList = dataList; 39. } 40. 41. } 42. } 43. class SingletonEnforcer{} 我们在创建一个接口,IApplicationModelAware,这个接口的设计含义是,如果 其它的类需要在自己内部定义 ApplicationModel 并等待 IoC 来注入,就可以实 现这个接口,比如我有个 Command 类,可以实现这个接口来在内部定义 ApplicationModel,虽然实际上我也可以通过 ApplicationModel.getInstance() 的方法获取 Model 的实例, 但这样会造成你的类对 ApplicationModel 类产生直 接的依赖,这就形成了耦合,并且非常不利于单元测试,合理的做法应该是通过 IoC 将 Model 注入到你的类,而不是你的类主动去寻找 Model。 IoC 的理念可以总结为:不要来找我,需要的时候我会给你。 1. package com.riameeting.model 2. { 3. public interface IApplicationModelAware 4. { 5. function get applicationModel():IApplicationModel; 6. function set applicationModel(value:IApplicationModel):void; 7. } 8. } 3.3 创建自定义事件 在 event 目录下,我们来定义事件。如果你了解 Cairngorm 的一些知识,就会知 道 Cairngorm 的基本逻辑控制都是通过事件与命令之间的映射来完成的。这里我 们来定义一个事件,命名为 GetFeedEvent,如果系统想获取 Feed 信息,只要派 发这个事件即可,这个事件会被前端控制器(FrontControler)映射到一个具体 的命令上。 1. package com.riameeting.event 2. { 3. import com.adobe.cairngorm.control.CairngormEvent; 4. 5. public class FeedEvent extends CairngormEvent 6. { 郭少瑞原创教程 www.richbox.net/blog 7. public static var GET_FEED_EVENT:String = "getFeedEvent"; 8. 9. public function FeedEvent(type:String) 10. { 11. super(type, true, true); 12. } 13. 14. } 15. } 3.4 构建视图 在 view 目录下,这里我们构建两个视图,在 Flex 的角度考虑,其实就是构建两 个 MXML 组件(Components),组件一是一个地址栏,允 许用户输入一个 Feed 地址,然后按下按钮去获取 Feed 信息;组件二是一个列表,用于显示 Feed 的 RSS 内容,这里我们可放一个 List 组件,列出 RSS 的所有内容,并自定义项目 渲染器,用标题加摘要的形式来显示 RSS 的一条内容。 组件一:AddressBar.mxml 1. 2. 3. 4. 5. 17. 18. 19. 郭少瑞原创教程 www.richbox.net/blog 20. 21. 22. 组件二:SearchResult.mxml 1. 2. 3. 4. 5. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 3.5 实现代理 在 business 目录下,我们来实现服务的代理。通常一个 Cairngorm 应用的形式 是, 将 Command 和 Service 隔 离,Command 通过调用代理,而代理调用 Service 来获取数据。经过考虑,我们这个代理所需要的方法就是一个获取 Feed 的方法, 郭少瑞原创教程 www.richbox.net/blog 那么我们首先声 明接口,如果其它的类(比如 Command)要调用代理,那么只 需要通过接口了解方法即可,而不需要了解具体的代理类如何实现。 创建接口 IGetFeedDelegate 1. package com.riameeting.business 2. { 3. import org.springextensions.actionscript.cairngorm.business .IBusinessDelegate; 4. 5. public interface IGetFeedDelegate extends IBusinessDelegate 6. { 7. function getFeed(url:String):void; 8. } 9. } 然后创建代理类 GetFeedDelegate 来实现这个接口,并继承 AbstractBusinessDelegate,这是一个抽象代理,包含了一些代理所需的基本属 性。 1. package com.riameeting.business 2. { 3. import mx.rpc.AsyncToken; 4. import mx.rpc.IResponder; 5. 6. import org.springextensions.actionscript.cairngorm.business .AbstractBusinessDelegate; 7. 8. public class GetFeedDelegate extends AbstractBusinessDelegate implements IGetFeedDelegate 9. { 10. public function GetFeedDelegate(service:Object=null, responder:IResponder=null) 11. { 12. super(service, responder); 13. } 14. 15. public function getFeed(url:String):void { 16. service.url = url; 郭少瑞原创教程 www.richbox.net/blog 17. var token:AsyncToken = service.send(); 18. token.addResponder(this.responder); 19. } 20. 21. } 22. } 3.6 实现 Command 在 command 目录,我们来创建命令,在 Cairngorm 中,命令承担着绝大多数的代 码工作,我们需要定义一个命令,来获取 Feed 的内容,一旦有事件触发这个命 令,这个命令就执行并调取代理来获取数据。 不过首先我们需要创建一个命令的基类,命名为 CommandBase,这个基类的目的 是在命令中预先声明对 ApplicationModel 的定 义,其它所有的命令都基于这个 命令来扩展,则所有的命令都具备 ApplicationModel 属性,这就意味着所有的 命令都在实例化的时候已经知道 Model 是什么,而不需要自己去寻找 Model。 1. package com.riameeting.command 2. { 3. import com.riameeting.model.IApplicationModel; 4. import com.riameeting.model.IApplicationModelAware; 5. 6. import org.springextensions.actionscript.cairngorm.commands .AbstractResponderCommand; 7. 8. public class CommandBase extends AbstractResponderCommand implements IApplicationModelAware 9. { 10. public function CommandBase() 11. { 12. super(); 13. } 14. 15. private var _applicatinModel:IApplicationModel; 16. public function get applicationModel():IApplicationModel 17. { 18. return _applicatinModel; 郭少瑞原创教程 www.richbox.net/blog 19. } 20. 21. public function set applicationModel(value:IApplicationModel):void 22. { 23. _applicatinModel = value; 24. } 25. 26. } 27. } 然后实现我们所需的获取 Feed 的命令,命名为 GetFeedCommand: 1. package com.riameeting.command 2. { 3. import com.adobe.cairngorm.control.CairngormEvent; 4. import com.riameeting.business.IGetFeedDelegate; 5. 6. import mx.collections.XMLListCollection; 7. import mx.controls.Alert; 8. 9. /** 10. * 对这个 Command 来说,不需要自己去找 Model, Delegate,IoC 容器会为它注入 11. * */ 12. public class GetFeedCommand extends CommandBase 13. { 14. import mx.managers.CursorManager; 15. override public function execute(event:CairngormEvent):void { 16. super.execute(event); 17. IGetFeedDelegate(this.businessDelegate).getFeed(app licationModel.feedURL); 18. CursorManager.setBusyCursor(); 19. } 20. 21. override public function result(data:Object):void { 22. CursorManager.removeBusyCursor(); 23. var x:XML = new XML(data.result.toString()); 郭少瑞原创教程 www.richbox.net/blog 24. applicationModel.feedList = new XMLListCollection(x.channel.item); 25. trace(applicationModel.feedList.toXMLString()); 26. } 27. 28. override public function fault(info:Object):void { 29. Alert.show(info.toString(),"fault"); 30. } 31. 32. } 33. } 3.7 实现工厂类 这里我们首先引入一个问题,对于 Command,我们希望将代理和 Model 都通过 IoC 注入给它,对于代理,我们也希望将 Service 注入进 去,这都体现了 IoC 的设 计原则,即这些注入工作都有 IoC 容器来完成,项目中的每个类只需要专注于自 己功能的实现,而不需要自己去寻找外部依赖,所有的 依赖都由 IoC 容器来负 责注入。对于 View 我们可以声明属性并通过 XML 配置来注入,但对于 Command 这样只有在 Event 触发的时候才创建的实 例,我们需要用特殊的机制来为它们 注入依赖。这里我们就需要实现一个工厂类 ApplicationModelAwareCommandFactory,这 个工厂将取代 Cairngorm 默认的 Command 实例化方式,在 Command 实例化的时候同时注入依赖。 在 factories 目录中,创建类 ApplicationModelAwareCommandFactory: 1. package com.riameeting.factories 2. { 3. import com.adobe.cairngorm.commands.ICommand; 4. import com.riameeting.command.CommandBase; 5. import com.riameeting.model.IApplicationModel; 6. import com.riameeting.model.IApplicationModelAware; 7. 8. import org.as3commons.reflect.ClassUtils; 9. import org.springextensions.actionscript.cairngorm.commands .ICommandFactory; 10. import org.springextensions.actionscript.cairngorm.commands .ResponderCommandFactory; 11. 郭少瑞原创教程 www.richbox.net/blog 12. public class ApplicationModelAwareCommandFactory extends ResponderCommandFactory implements ICommandFactory, IApplicationModelAware 13. { 14. private var _applicationModel:IApplicationModel; 15. 16. public function ApplicationModelAwareCommandFactory() 17. { 18. super(); 19. } 20. 21. override public function canCreate(clazz:Class):Boolean 22. { 23. if (ClassUtils.isSubclassOf(clazz, CommandBase)) { 24. return super.canCreate(clazz); 25. } 26. return false; 27. } 28. 29. override public function createCommand(clazz:Class):ICommand 30. { 31. var result:CommandBase = super.createCommand(clazz) as CommandBase; 32. result.applicationModel = _applicationModel; 33. return result; 34. } 35. 36. 37. public function get applicationModel():IApplicationModel 38. { 39. return _applicationModel; 40. } 41. public function set applicationModel(value:IApplicationModel):void 42. { 43. _applicationModel = value; 郭少瑞原创教程 www.richbox.net/blog 44. } 45. } 46. } 3.8 实现工具类 ApplicationViewAssembler 因为 IoC 只负责实例化对象,并不负责为你加入显示列表,所以我们来实现一个 工具类 ApplicationViewAssembler,它的作用就是作为一个处理显示对象的容 器,负责将这些显示对象添加到显示列表。将这个类保存在 utils 目录中。 1. package com.riameeting.utils 2. { 3. import flash.display.DisplayObject; 4. 5. import mx.core.Application; 6. import mx.core.FlexSprite; 7. 8. public class ApplicationViewAssembler 9. { 10. public function ApplicationViewAssembler(){} 11. 12. public var elements:Array; 13. 14. public function init():void{ 15. for (var i:int = 0 ; i < elements.length ; i++){ 16. (Application.application as FlexSprite).addChild(elements[i] as DisplayObject); 17. } 18. } 19. } 20. } 至此 Lib 部分的编码结束了,你可以编译一下,看 bin 目录下面是不是生产 SWC 文件了,在下半部分我们将在主体项目中引入这个 Lib 项目,并通过 IoC 容器装 配出一个可用的 RSS 阅读器。 点击这里阅读下半部分内容 郭少瑞原创教程 www.richbox.net/blog Spring ActionScript 入门教程(3)-Spring 和 Cairngorm 的结合使用[下] 本文接上一部分继续完成 RSS 阅读器实例,在上个部分中我们完成了 Lib 项目的 构建,其实已经基本上完成了项目本身的逻辑代码,而在这一部分,我们将把这 个 Lib 引入到 IoC 框架中,并编写相应的 XML 配置文件,最终完成装配,形成完 整的应用。 Part4 实现主项目 SpringActionScriptCairngormDemo 让我们回到 SpringActionScriptCairngormDemo,开始完成 IoC 的注入工作。 4.1 配置编译参数 打开项目属性,在编译参数部分,将项目依赖的 SWC 文件都设置好,包括两部 分:一部分是已经下载到 libs 目录下的 SWC 文件,还要把我们上个例子中编译 好的 SpringActionScriptCairngormDemoLib.swc 也配置进去,配置参数应该如 下: -locale en_US -default-background-color #000000 -include-libraries ../libs/spring-actionscript.swc ../l ibs/spring-actionscript-cairngorm.swc ../libs/as3commons-reflect.swc ../libs/as3commons-lang.swc ../libs/as3commons-logging.swc ../libs/fl exunit.swc ../../SpringActionScriptCairngormDemoLib/bin/SpringActionS criptCairngormDemoLib.swc 参见附图: 郭少瑞原创教程 www.richbox.net/blog 4.2 写配置 XML 在 src 目录下,创建一个文件夹名为“config”,然后在 config 下面再创建两 个目录,分别是 cairngorm 和 view,第一个目录是 为了存放和 Cairngorm 相关 的配置,第二个目录是用于存放跟视图相关的配置。当然这样拆分目录是为了便 于区分和维护,实际上你也可以根据需要按照自 己的需要拆分目录结构,IoC 对此没有硬性要求。 首先我们先来配置 Cairngorm 的部分,将 Cairngorm 部分必须的 Service, ModelLocator,FrontControler 等部分一一做配置。在 cairngorm 目录下,创 建一个 XML 文件,名为 “cairngorm.xml”。输入下面的内容: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. feedService 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 郭少瑞原创教程 www.richbox.net/blog 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. businessDelegateFactory 33. 34. 35. 36. com.riameeting.command.GetFeedCommand 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 郭少瑞原创教程 www.richbox.net/blog 48. 49. appAwareCmdFactory 50. 51. 52. 53. 可以看到主体配置分为 4 个部分: 1. ModelLocator - 对应在 Lib 中创建的 ApplicationModel,在此创建一个 Model 的实例 2. Service Locator - 先创建一个 ID 为“feedService”的 HTTPService,然后创建一个 ID 为 “serviceLocator”的 Service Locator,将 feedService 引入进去 3. Delegate Factory - 我们通过配置代理工厂,将第二部分的服务注入到代理中去,这 样代理就具备了通过自身调用服务的能力,而不需要同外部服务产生直接的依赖 4. FrontControler - 首先我们配置工厂类 ApplicationModelAwareCommandFactory,将 Model 注入到 Command 中去。然后创建一个前端控制器“frontController”,将事件与 命令之间建立映射。 然后我们来创建一个关于视图的配置文件,定义界面上都显示什么样的组件,在 view 下面创建一个 XML 文件,名为“global.xml”,然后输入下面的内容: 1. 2. 3. 4. 5. 6. 7. 8. 6. 7. 8. 9. 然后我们在主代码中加载配置文件,这个过程与我们之前使用 Spring ActionScript 的方式相同: 1. package 2. { 3. import flash.display.DisplayObject; 4. import flash.display.Sprite; 5. 6. import org.springextensions.actionscript.context.support.XM LApplicationContext; 7. 8. import test.ClassRef; 9. 10. public class EventBusTest extends Sprite 11. { 郭少瑞原创教程 www.richbox.net/blog 12. [Embed(source="config/application_context.xml",mime Type ="application/octet-stream")] 13. public var view:Class; 14. 15. public var applicationContext:XMLApplicationContext; 16. 17. public function EventBusTest() 18. { 19. new ClassRef; 20. applicationContext = new XMLApplicationContext(); 21. applicationContext.addEmbeddedConfig(view); 22. applicationContext.load(); 23. addChild(applicationContext.getObject("a") as DisplayObject); 24. addChild(applicationContext.getObject("b") as DisplayObject); 25. } 26. } 27. } 然后有两个类 A 和 B,注意 A 中将派发事件,交由 EventBus 托管,EventBus 将 执行 B 中的 Handler,执行相应的操作,整个过程非常优雅的实现了松耦合,A 和 B 彼此都不知道对方的存在,甚至也不需要知道 EventBus 的存在。 A 的代码,注意我们使用了[RouteEvents]来标注哪些事件将被托管: 1. package test 2. { 3. import flash.display.Sprite; 4. import flash.events.MouseEvent; 5. 6. [RouteEvents] 7. [Event(name="move",type="test.TestEvent")] 8. 9. public class A extends Sprite 10. { 11. 12. public function A() 13. { 郭少瑞原创教程 www.richbox.net/blog 14. super(); 15. this.graphics.beginFill(0x000000,1); 16. this.graphics.drawRect(0,0,100,100); 17. this.graphics.endFill(); 18. x = 10; 19. y = 10; 20. addEventListener(MouseEvent.CLICK,startMove); 21. } 22. 23. private function startMove(e:MouseEvent):void { 24. trace("A clicked"); 25. var sEvt:TestEvent = new TestEvent(TestEvent.MOVE); 26. sEvt.speed = 10; 27. dispatchEvent(sEvt); 28. } 29. 30. } 31. } B 的代码,注意我们使用了[EventHandler(name="move")]来确定哪个事件将被 后面的方法处理,注意该方法必须是 Public 的: 1. package test 2. { 3. import flash.display.Sprite; 4. 5. public class B extends Sprite 6. { 7. public function B() 8. { 9. super(); 10. this.graphics.beginFill(0xFF0000,1); 11. this.graphics.drawRect(0,0,100,100); 12. this.graphics.endFill(); 13. x = 110; 14. y = 10; 15. } 16. 郭少瑞原创教程 www.richbox.net/blog 17. [EventHandler(name="move")] 18. public function trackHandler(e:TestEvent):void { 19. x += e.speed; 20. trace("B move:"+e.speed); 21. } 22. 23. } 24. } 项目源码查看 详情请点击这里查看 使用 Spring ActionScript 的时候编译所需类 的 6 种方式 问题 在使用 IoC 框架,比如 Spring ActionScript 的时候,因为代码中没有对类的引 用,Flex 并不会自动将所需的类编译到主 SWF 中去,这就会产生一个问题,即 运行时找不到所需 的类,这也是困惑 Spring ActionScript 新手的一个问题。 那么如何解决呢,以下内容译自 Spring ActionScript 的官方文档。 原文地址: http://www.springactionscript.org/docs/reference/html/Class-inclusion .html 解决方案(根据你的需要选择一种方式) 1.在你的代码中任何位置加入对类的引用: 1. { 2. Myclass1, Myclass2 3. } 2.创建变量或数组加入对类的引用: 1. private var _includeClass:Array = [Myclass1,Myclass2]; 郭少瑞原创教程 www.richbox.net/blog 3.使用 Frame metadata: 1. package com.myclasses 2. { 3. [Frame(extraClass="com.myclasses.Myclass1")] 4. [Frame(extraClass="com.myclasses.Myclass2")] 5. public class MyMainClass 6. { 7. } 8. } 4.使用 resource bundle: 在你的项目中创建一个名为 classreferences.properties 的文件并添加你的 类进入,比如: 1. Class1 = ClassReference("com.myclasses.Myclass1") 2. Class2 = ClassReference("com.myclasses.Myclass2") 然后在你的代码中添加对资源的引用: 1. [ResourceBundle("classreferences")] 2. private var _classReferences:ResourceBundle; 5.使用 ANT 工具作为一个预加载器生成编译配置文件 第一步,添加一个编译参数到你的项目,如下图所示(注意 Additional compiler arguments 参数): 郭少瑞原创教程 www.richbox.net/blog 第二步,创建一个 XSLT ANT 任务到你的项目根目录(注意不是 src),命名为 'springasprebuild.xml',并添加下面的代码: 1. 23. 24. 26. 27. 第三步,在你的项目根目录创建一个"xslt"的目录,然后在这个目录中创建一个 新的文件叫做"springasconfig.xsl",并添加下面的代码: 1. 2. http://www. springactionscript.org/schema/objects/spring-actions cript-obj... " 8. exclude-result-prefixes="xsi springas"> 9. 郭少瑞原创教程 www.richbox.net/blog 10. 11. 13. 14. 15. 16. 17. 19. 20. 21. 22. 23. 24. 25. 26. 28. 29. 30. 31. 32. 33. 34. 35. 37. 38. 39. 40. 41. 42. 43. 44. 郭少瑞原创教程 www.richbox.net/blog 45. 46. 47. 添加 ANT 任务到你的项目,右键点击你的项目,选择"Properties",然后再选择 "Builders" 点击"New"并选择"ANT Builder"并点击"OK",出现对话框。给 Builder 创建一个 名称,比如"Spring AS Builder",然后选择点击"Browse workspace",在接下 来的对话框中选择你项目根目录中的 build 文件,比如"springasprebuild.xml" 郭少瑞原创教程 www.richbox.net/blog 点击“OK”返回 Builder 列表,你会发现顺序是错的,点击"UP"将 SpringAS_Builder 移到第一位 郭少瑞原创教程 www.richbox.net/blog 点击"OK"完成,项目就配置好了。测试以下,编译你的项目,你的源码目录下面 创建了一个名为"springas.config"的文件,文件内容类似于这样: 1. 2. 3. 4. mx.messaging.channels.AMFChannel 5. mx.messaging.ChannelSet 6. mx.rpc.remoting.mxml.RemoteObject 7. 8. 好了,完工 郭少瑞原创教程 www.richbox.net/blog 6.使用Maven。你需要先点击这里下载mojo文件,然后打开运行"mvn install" 将它加入到你的本地仓库。 然后像下面的方式一样使用: 1. ... 2. 3. 4. spring-as-includes.conf ig 5. ${project.build.sourceDi rectory} 6. 7. 8. ... 9. 10. 11. org.springextensions.actionscript 12. prebuild-mojo 13. 0.1-SNAPSHOT 14. 15. 16. generate-resources 17. 18. generate-compiler-config 19. 20. 21. 22. 23. 24. ${basedir}/src/main/flex/YOUR-CONTEXT-FILE.xm l 25. 26. ${generatedCompilerConfigDir} 郭少瑞原创教程 www.richbox.net/blog 27. ${generatedCompilerConfigNa me} 28. 29. 30. 31. org.sonatype.flexmojos 32. flexmojos-maven-plugin 33. 3.6-SNAPSHOT 34. 35. ... 36. 37. ${generatedCompilerConfigDir}/${generatedCompi lerConfigName} 38. 39. ... 40. 41. 42. 43. 44. 45. ... Spring ActionScript 对于 Module 的支持 Spring ActionScript 对于 Module 开发有无支持? 一般在小规模的 RIA 应用中,所需的配置量也很少,我们直接写一个 XML 配置文 件,一次性载入就可以了。但如果涉及到大规模应用,比如在 Flex 项 目开发中, 会将若干模块做成 Flex Module 来实现模块的分离,这样因为主应用和 Module 的加载时间不一致,势必导致我们需要为他们各自编写独立的 XML 配置(这种情 况也适用于我们 开发 Flash 项目,分为多个 SWF 进行加载)。那么 Spring ActionScript 对此有无支持呢?答案是肯定的,Spring ActionScript 作为一个 成熟的解决方案,也考虑到了这个因素,这也是 Spring ActionScript 在社区大 受欢迎的原因。 郭少瑞原创教程 www.richbox.net/blog 使用 Application 上下文和 Module 上下文 假设这样一个情景,有两个上下文。一个是在主应用中创建的,另一个则是在需 要延迟加载的模块中创建的。第一个我们称之为 Application 上下文,另一个称 之为 Module 上下文。 现在假设 Application 上下文的配置如下: 1. 2. 3. 4. 5. 6. 7. Module 上下文的配置如下: 1. 2. 3. 4. 5. 当Module 上下文创建的时候,我们设置Application 上下文为它的父级(parent): 1. var moduleContext:XMLApplicationContext = new XMLApplicationContext("module-context.xml"); 2. moduleContext.parent = applicationContext; 这样做的结果就是,当你在 Application 上下文中请求一个 id 是 myOtherObject 的对象,你会得到一个类型是 com.myclasses.MyOtherObject 的实例。然而, 当你是在 Module 上下文中请求同一个对象,你会得到一个类型是 com.myclasses.moduleimplementations.MyOtherObject 的实例。 下面,我们稍微更改一下两个配置,添加一些依赖并展示如何在 Module 上下文 中覆写这些依赖。 Application 上下文的配置: 郭少瑞原创教程 www.richbox.net/blog 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 现在从 Application 上下文中请求 id 是 myOtherObject 的对象,你会得到一个 类型是 com.myclasses.MyOtherObject 的实例,和它的依赖(类型是 com.dependencies.MyDependency).然 后我们更改 Module 上下文的配置如下: 1. 2. 3. 4. 5. 当我们再次从 Module 上下文中请求 id 是 myOtherObject 的对象,我们会得到类 型是 com.myclasses.MyOtherObject 的实例,它的依赖则变成了类型是 com.moduledependencies.MyDependency 的一个实例。 注意:像这样的重写引用对象,前提条件是对象的 scoped 属性设置为 prototype。 重写外部属性值也将遵循同样的逻辑(即更改 value 而不是 ref),所以你是可 以更改从父级的上下文中获得的属性的。 如果 Application 上下文中有一个外部配置的属性叫做 prop1,你可以在 Module 上下文中引用: 1. 2. 3. 4. 5. 郭少瑞原创教程 www.richbox.net/blog 6. 7. 2. 3. 4. 5. 6. 7. 8. 9. 2. Collections Spring ActionScript 包含了一些有用的基础的数据集合,让我们方便的 归类数据,这些可用的标签包括 array, array-collection , dictionary 和 vector。注意如果要使用 array-collection,上下文的类型必须是 FlexXMLApplicationContext,因为这个集合 是 Flex 特有的。代码示例: 1. 2. 3. 4. 郭少瑞原创教程 www.richbox.net/blog 5. 6. 7. 8. development 9. development@example.org 10. 11. 12. 13. 14. 15. 16. a list element followed by a reference 17. 18. 19. 20. 21. 22. 23. 24. a list element followed by a reference 25. 26. 27. 28. 29. 30. 31. 32. string1 33. string2 34. string3 35. string4 36. 37. 38. 39. 3. 使用 this 郭少瑞原创教程 www.richbox.net/blog Spring ActionScript 提供了 this 的关键字可以直接让你在配置中使用, 它指向当前的上下文。这个特性是非常有用的,因为很多情况下你配置的 实例,需 要获得 Spring ActionScript 上下文的引用,你可能会直接从 父级的对象去获取这个引用,但这样就破坏了解耦的原则。而使用 this, 你可以直接在配置的 XML 中将上下文传入,这样是不是优雅很多? 1. 2. 3. 4. 延迟初始化对象 有时我们不希望一个对象在上下文被初始化的同时也被初始化,比如对象 特别多的情况下,基于性能的考虑,这时可以使用延迟初始化,举例如下: 1. 2. 3. 5. 使用 Meta 的自动装配 Spring ActionScript对于自动装配有非常好的支持,包括byName,byType 等各种模式,这里我们只介绍基于Metadata的自动装配,其它方式请参考 官方文档 (http://www.springactionscript.org/docs/reference/html/containe r-documentation.html)。 首先要保证在 XML 配置中加入了自动装配的处理器: 1. 简单的属性装配可以像下面一样: 2. public class ExampleComponent extends UIComponent { 3. 4. [Autowired] 5. public var modelInstance:IModelLocator; 6. 7. public function ExampleComponent() { 郭少瑞原创教程 www.richbox.net/blog 8. super(); 9. } 10. 11. } 如果你希望按照名称装配,则改为: 12. public class ExampleComponent extends UIComponent { 13. 14. [Autowired(mode='byName')] 15. public var modelInstance:IModelLocator; 16. 17. public function ExampleComponent() { 18. super(); 19. } 20. 21. } 当然你也可以指定到配置中一个对象: 22. public class ExampleComponent extends UIComponent { 23. 24. [Autowired(name='ModelLocator')] 25. public var modelInstance:IModelLocator; 26. 27. public function ExampleComponent() { 28. super(); 29. } 30. 31. } 6. 标注必须注入的属性 你可以为需要注入的属性标记[Required],来保证它会在 XML 配置中被注 入: 1. [Required] 2. public var myProperty:Type; 如果你这样标记了,但是没有在 XML 配置中找到它的依赖,那么就会抛出 IllegalArgumentError 的错误。要使用这个特性,你要包含下面的对象: 郭少瑞原创教程 www.richbox.net/blog 3. 7. 将某一个对象的属性注入其它对象 有时候你会有这样的需求,即你要为某个对象的属性配置的依赖不是另一 个对象,而是另一个对象的属性,那怎么办呢?可以使用 FieldRetrievingFactoryObject 1. 2. 3. 4. 5. 6. 7. 8. 同时它也支持静态属性: 9. 10. 11. 6. 熟悉 XML 的朋友就会发现,关键之处在于我们通过 xsi:schemaLocation 指定了 XSD 的位置,编辑器就知道该如何规范这个 XML 的编写。试着开始 编写 object,看到代码提示了吧 Spring ActionScript Operation API 入门教程 [一]:简介 在 Spring ActionScript 1.0 RC 版本中,包含了一个 Operation API,今天我 们就来对这个部分做个简单介绍。在之后的文章中,我们将练习使用 Operation API 来完成一个简单的示例。 Operation API 简介 在很多 Flash 或 Flex 应用中有一个共性:他们都需要连接到后端获取数据,比 如:呼叫一个远程对象,加载一个二级模块或资源文件,这些方式也有 一个共 性:他们都是异步的。而 Flex 框架和 Flash Player 看起来为不同类型的数据检 索提供了不同的异步模式,比如回调方法,基于事件的方法,呼叫一个实例返回 一个 IEventDispatcher 或 其它接口,等等。这些看起来有些混乱,也使我们的 编程方式看起来不统一。 在这种情况下,Spring ActionScript Operation API 出现了,它提供了一种通 用的方式,包含了上面不同的模式并非常易于使用。它提供了一些类和接口来让 开发者非常容易编写他们的逻辑,同样对于一些通用 的任务,Spring ActionScript 也提供了支持,比如加载 Flex 模块,资源模块和远程对象调用。 注意 Operation API 不是一个 MVC 或 MVCS 框架,作者认为提供一个框架过于僵 硬,不如给开发者提供一套基础的接口和类更方便他们的使用。每个应用都有自 己的特点,而 Operation API 的灵活和便捷将使它很容易整合到应用中。 郭少瑞原创教程 www.richbox.net/blog Operations, commands, services and tasks 如标题所述,Operation API 包含 4 个部分: 1. Operation: 一个异步的动作. 2. Command: 一个延期执行的动作. 3. Service:一组相关的 Operation 的集合. 4. Task: 一组被工作流控制的 Command 的集合. Operation(操作) 操作是一个异步的动作,比如我们向服务器发送一次请求,然后稍等片刻,获取 到了服务器返回的数据,可以将这个过程抽象为一个操作。在编程层面,我们把 一个操作对应到具体的类,则这个类需要实现操作的接口: 1. public interface IOperation extends IEventDispatcher { 2. 3. function get result():*; 4. 5. function get error():*; 6. 7. function addCompleteListener(listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void; 8. 9. function addErrorListener(listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void; 10. 11. function removeCompleteListener(listener:Function, useCapture:Boolean = false):void; 12. 13. function removeErrorListener(listener:Function, useCapture:Boolean = false):void; 14. 15. } 注意这个接口规范了异步的操作模式,包括返回的结果或错误,对过程使用事件 侦听。如果你需要侦听数据的加载进度,则要实现下面的接口: 1. public interface IProgressOperation extends IOperation { 2. 郭少瑞原创教程 www.richbox.net/blog 3. function get progress():uint; 4. 5. function get total():uint; 6. 7. function addProgressListener(listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void; 8. 9. function removeProgressListener(listener:Function, useCapture:Boolean = false):void; 10. } 操作可以说是 Operation API 概念中的最小单元,因为其有规范的接口,我们可 以很方便的在 Command 和 Service 等部分来使用它。我们甚至可以把若干小的操 作集合起来使用,这就要用到 OperationQueue 类,示例如下: 1. var queue:OperationQueue = new OperationQueue(); 2. queue.addCompleteListener(handleQueueComplete); 3. queue.addOperation(new FirstOperation()); 4. queue.addOperation(new SecondOperation()); 5. queue.addOperation(new ThirdOperation()); 6. queue.addOperation(new FourthOperation()); 另外 Spring ActionScript 也封装好了一些通用的操作,列表如下: • LoadPropertiesOperation • LoadPropertiesBatchOperation • LoadStyleModuleOperation • LoadURLOperation • LoadModuleOperation • NetConnectionOperation • RemoteObjectOperation • LoadResourceBundleOperation • LoadResourceModuleOperation Command(命令) 命令是需要延期执行的动作。这个概念跟 Cairngorm 中的 Command 很类似,它负 责具体的逻辑处理,需要一定的机制来触发。在 Cairngorm 中是由 FrontControler 将事件映射到 Command 来触发 Command 的执行。而在 Operation API 中比较灵活,并没有规定由谁来触发 Command,而很多情况下我们可以把它 和 Task 结合起来使用,功能强大,后面会做介绍。Command 的接 口也比较简单: 1. public interface ICommand { 郭少瑞原创教程 www.richbox.net/blog 2. 3. function execute():*; 4. 5. } 继承此接口需要实现 execute 的方法。跟操作类似,我们也可以把若干命令集合 起来使用,这里要使用 CompositeCommand 类。注意你可以定义执行的方式(并 行或顺序执行): 1. var compositeCommand:CompositeCommand = new CompositeCommand(ComposeiteCommandKind.SEQUENCE); 2. compositeCommand.addCommand(new FirstCommand()); 3. compositeCommand.addCommand(new SecondCommand()); 4. compositeCommand.addCommand(new ThirdCommand()); 5. compositeCommand.addCommand(new FourthCommand()); 6. compositeCommand.addCompleteListener(handleComposite CommandComplete); 7. compositeCommand.addErrorListener(handleCompositeCom mandError); 8. compositeCommand.execute(); 我们通常不会直接调用一个操作,而是调用命令(操作一般放到命令或服务里调 用),而为每一个操作都对应一个命令的类并不现实,这时我们可以使用 GenericOperationCommand。 1. var genericOperationCommand = new genericOperationCommand(LoadModuleOperation,['module .swf']); 2. genericOperationCommand.addCompleteHandler(operation CompleteHandler); 3. genericOperationCommand.execute(); Service(服务) 服务的实现则完全跟我们的业务逻辑相关,我们首先需要定义接口,抽象出那些 需要跟后端交互的方法。比如我们的应用中要实现用户信息操作的服务,则接口 定义如下: 1. public interface IUserService { 2. 3. function createUser():IOperation; 4. 5. function updateUser(user:User):IOperation; 6. 郭少瑞原创教程 www.richbox.net/blog 7. function deleteUser(user:User):IOperation; 8. 9. } 服务的实现,这里选择继承 RemoteObjectService 来简化操作: 1. public class UserService extends RemoteObjectService implements IUserService { 2. 3. public function UserService(remoteObject:RemoteObject) { 4. Assert.notNull(remoteObject,"remoteObject argument must not be null"); 5. super(remoteObject); 6. } 7. 8. public function createUser():IOperation { 9. return call('createUser'); 10. } 11. 12. public function updateUser(user:User):IOperation { 13. return call('updateUser',user); 14. } 15. 16. public function deleteUser(user:User):IOperation { 17. return call('deleteUser',user); 18. } 19. } 然后我们可以在命令中调取服务,来做具体的逻辑判断: 1. public class CreateUserCommand extends AbstractOperation implements IAsyncCommand { 2. 3. private var _userService:IUserService; 4. private var _applicationModel:IApplicationModel; 5. 6. public function CreateUserCommand(userService:IUserService, applicationModel:IApplicationModel) { 7. Assert.notNull(userService,"userService argument must not be null"); 8. Assert.notNull(applicationModel,"applicationModel argument must not be null"); 9. _userService = userService; 郭少瑞原创教程 www.richbox.net/blog 10. _applicationModel = applicationModel; 11. } 12. 13. public function execute():* { 14. var operation:IOperation = _userService.createUser(); 15. operation.addCompleteListener(handleComplete); 16. operation.addErrorListener(handleError); 17. } 18. 19. protected function handleComplete(event:OperationEvent):void { 20. _applicationModel.users.addItem(event.result as User); 21. dispatchCompleteEvent(event.result); 22. } 23. 24. protected function handleError(event:OperationEvent):void { 25. dispatchErrorEvent(event.error); 26. } 27. 28. } Task(任务) 为了可以方便的批量执行 Command,Spring ActionScript 引入了 Task 的概念。 一个 Task 是若干 Command 的集合,但不仅仅如此,Task 允许你定义 Command 的 执行顺序,甚至可以引入循环和判断。首先预览一下 ITask 这个接口: 1. public interface ITask extends ICommand, IOperation { 2. 3. function get parent():ITask; 4. function set parent(value:ITask):void; 5. 6. function next(command:ICommand):ITask; 7. 8. function and(command:ICommand):ITask; 9. 10. function if_(condition:IConditionProvider=null, ifElseBlock:IIfElseBlock=null):IIfElseBlock; 11. 12. function else_():IIfElseBlock; 13. 郭少瑞原创教程 www.richbox.net/blog 14. function while_(condition:IConditionProvider=null, whileBlock:IWhileBlock=null):IWhileBlock; 15. 16. function for_(count:uint, countProvider:ICountProvider=null, forBlock:IForBlock=null):IForBlock; 17. 18. function exit():ITask; 19. 20. function reset(doHardReset:Boolean = false):ITask; 21. 22. function pause(duration:uint, pauseCommand:ICommand=null):ITask; 23. 24. function end():ITask; 25. } Task 类实现了这个接口,如前所述,我们可以定义 Command 的执行顺序,比如 我们要并行执行,代码如下: 1. var task:Task = new Task().and(new FirstCommand()).and(new SecondCommand()).and(new ThirdCommand()).and(new FourthCommand()); 2. task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); 3. task.execute(); 我们还可以使用 next 方法,含义是先执行前面的 Command,等待执行完毕之后, 再执行下一个 Command。比如: 1. var task:Task = new Task().and(new FirstCommand()).and(new SecondCommand()).next(new ThirdCommand()).next(new FourthCommand()); 2. task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); 3. task.execute(); 在 Task 里执行 For 循环: 1. var task:Task = new Task(); 2. 3. task.for_(10) 4. .next(new FirstCommand()) 5. .end(); 6. 郭少瑞原创教程 www.richbox.net/blog 7. task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); 8. task.execute(); 我们也可以使用 If 判断,条件是一个实现 IConditionProvider 接口的类: 1. public interface IConditionProvider { 2. function getResult():Boolean; 3. } 1. var task:Task = new Task(); 2. 3. task.if_(new ConditionProvider()) 4. .next(new FirstCommand()) 5. .else_() 6. .next(new SecondCommand()) 7. .end(); 8. 9. task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); 10. task.execute(); 还可以使用 While 循环: 1. var task:Task = new Task(); 2. 3. task.while_(new MyConditionProvider()) 4. .next(new FirstCommand()) 5. .end(); 6. 7. task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); 8. task.execute(); 下面我们看看如何在 XML 配置中使用 Task,首先是命名空间的配置: 1. http://www.springactionscript.org/schema/object s http://www.springactionscript.org/schema/objects/s pring-actionscript-obj... http://www.springactionscript.org/schema/task

9.

" title="http://www.springactionscript.org/schema/util /spring-actionscript-task-1.0.xsd">

10.

">http://www.springactionscript.org/schema/util/ spring-actionscript-task-1... 11. 要使用 Task 的命名空间,你需要为上下文添加 TaskNamespaceHandler 的类: 1. applicationContext.addNamespaceHandler(new TaskNamespaceHandler()); 这样你就可以在 XML 配置中使用 Task 了,一个简单的 Task 配置如下: 1. 2. 3. 4. 5. 郭少瑞原创教程 www.richbox.net/blog 6. 7. 8. 9. 10. 11. 12. 13. 14. 你可以把 Command 单独配置,修改如下: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 加入判断: 1. 2. 3. 4. 5. 6. 7. 8. 9. 郭少瑞原创教程 www.richbox.net/blog 10. 11. 参考网页: http://www.springactionscript.org/docs/reference/html/the_operation_a pi.html 在下一篇文章中我们将使用 Operation API 完成一个实例,敬请关注. Spring ActionScript Operation API 入门教程 [二]:实例 在上一篇文章中我们简单介绍了 Spring ActionScript 的 Operation API,这里 我们通过一个实例,来理解如何在我们的项目开发中引入这个机制。 这里假设项目需求是,需要用户先登录,然后进入到用户显示列表,这两个部分 都需要调取后台服务进行异步操作,正好符合 Operation API 的应用范畴。 最后完成 Demo 的示意图: 点击这里查看完成 Demo 的演示: http://www.riameeting.com/examples/OperationDemo/ 在示例上点击右键可查看源码,也可以点击这里查看: 郭少瑞原创教程 www.richbox.net/blog http://www.riameeting.com/examples/OperationDemo/srcview/index.html 这里假设您已经具备了Spring ActionScript的使用经验,不再详细阐述项目的 构建步骤(如果您还不熟悉,请参阅这篇文章:Spring ActionScript入门教程 (2)-一个简单的实例),而是对一些关键要点加以介绍: 项目主文件,我们依然分离了逻辑代码的执行,只保留了 Spring ActionScript 上下文的加载: 1. 2. 7. 8. 33. 34. 35. 36. 37. 数据 Model 的接口设计: 1. package model 2. { 3. import mx.collections.ArrayCollection; 4. 5. import vo.UserVO; 6. 7. [Bindable]public interface IApplicationModel 8. { 9. function get employeeList():ArrayCollection; 10. function set employeeList(value:ArrayCollection):void; 11. function get user():UserVO; 12. function set user(value:UserVO):void; 13. function get viewIndex():int; 14. function set viewIndex(value:int):void; 15. } 16. } 郭少瑞原创教程 www.richbox.net/blog Model 我们将通过 XML 配置中各个实例的依赖注入,在实例中获得引用。然后我 们实现两个操作,以便在 Service 中使用。 操作一:登录,注意我通过 setTimeout 虚拟了后台响应的延时。 1. package service.operation 2. { 3. import flash.utils.setTimeout; 4. 5. import mx.managers.CursorManager; 6. 7. import org.springextensions.actionscript.core.operation.Abs tractOperation; 8. 9. import vo.UserVO; 10. 11. public class LoginOperation extends AbstractOperation 12. { 13. public function LoginOperation(user:UserVO) 14. { 15. super(); 16. CursorManager.setBusyCursor(); 17. setTimeout(success,1000,user); 18. } 19. 20. private function success(user:UserVO):void { 21. if(user.userName == "jim" && user.password == "jim") { 22. result = 1; 23. } else { 24. result = 0; 25. } 26. CursorManager.removeBusyCursor(); 27. dispatchCompleteEvent(); 28. } 29. 30. } 31. } 操作二:获取用户信息列表 1. package service.operation 2. { 郭少瑞原创教程 www.richbox.net/blog 3. import flash.utils.setTimeout; 4. 5. import mx.collections.ArrayCollection; 6. import mx.managers.CursorManager; 7. 8. import org.springextensions.actionscript.core.operation.Abs tractOperation; 9. 10. import vo.UserVO; 11. 12. public class GetEmployeeListOperation extends AbstractOperation 13. { 14. public function GetEmployeeListOperation() 15. { 16. super(); 17. CursorManager.setBusyCursor(); 18. setTimeout(success,1000); 19. } 20. 21. private function success():void { 22. CursorManager.removeBusyCursor(); 23. var data:Array = []; 24. data.push(new UserVO("Jim","xx")); 25. data.push(new UserVO("Tom","xx")); 26. data.push(new UserVO("Marry","xx")); 27. result = new ArrayCollection(data); 28. dispatchCompleteEvent(); 29. } 30. 31. } 然后实现服务类,这里只有两个方法:登录和获取数据。注意上述的两个操作在 这里得到应用。 1. package service 2. { 3. import org.springextensions.actionscript.core.operation.IOp eration; 4. 5. import service.operation.GetEmployeeListOperation; 6. import service.operation.LoginOperation; 郭少瑞原创教程 www.richbox.net/blog 7. 8. import vo.UserVO; 9. 10. public class UserService implements IUserService 11. { 12. public function UserService() 13. { 14. } 15. 16. public function login(user:UserVO):IOperation 17. { 18. return new LoginOperation(user); 19. } 20. 21. public function getEmployeeList():IOperation 22. { 23. return new GetEmployeeListOperation(); 24. } 25. } 26. } 然后我们实现两个命令(Command),来调取服务。 命令一:登录 1. package command 2. { 3. import model.IApplicationModel; 4. 5. import org.springextensions.actionscript.core.command.IAsyn cCommand; 6. import org.springextensions.actionscript.core.operation.Abs tractOperation; 7. import org.springextensions.actionscript.core.operation.IOp eration; 8. import org.springextensions.actionscript.core.operation.Ope rationEvent; 9. 10. import service.IUserService; 11. 郭少瑞原创教程 www.richbox.net/blog 12. public class LoginCommand extends AbstractOperation implements IAsyncCommand 13. { 14. private var _userService:IUserService; 15. private var _applicationModel:IApplicationModel; 16. 17. 18. public function LoginCommand(userService:IUserService, applicationModel:IApplicationModel) 19. { 20. super(); 21. _userService = userService; 22. _applicationModel = applicationModel; 23. } 24. 25. public function execute():* 26. { 27. var operation:IOperation = _userService.login(_applicationModel.user); 28. operation.addCompleteListener(handleComplete); 29. operation.addErrorListener(handleError); 30. } 31. 32. protected function handleComplete(event:OperationEvent):void { 33. trace(event.result); 34. if(event.result == 1) { 35. _applicationModel.user.loginStatus = true; 36. } 37. dispatchCompleteEvent(event.result); 38. } 39. 40. protected function handleError(event:OperationEvent):void { 41. dispatchErrorEvent(event.error); 42. } 43. 44. 45. } 46. } 郭少瑞原创教程 www.richbox.net/blog 命令二:获取用户数据 1. package command 2. { 3. import model.IApplicationModel; 4. 5. import org.springextensions.actionscript.core.command.IAsyn cCommand; 6. import org.springextensions.actionscript.core.operation.Abs tractOperation; 7. import org.springextensions.actionscript.core.operation.IOp eration; 8. import org.springextensions.actionscript.core.operation.Ope rationEvent; 9. 10. import service.IUserService; 11. 12. public class GetEmployeeListCommand extends AbstractOperation implements IAsyncCommand 13. { 14. private var _userService:IUserService; 15. private var _applicationModel:IApplicationModel; 16. 17. 18. public function GetEmployeeListCommand(userService:IUserService, applicationModel:IApplicationModel) 19. { 20. super(); 21. _userService = userService; 22. _applicationModel = applicationModel; 23. } 24. 25. public function execute():* 26. { 27. var operation:IOperation = _userService.getEmployeeList(); 28. operation.addCompleteListener(handleComplete); 郭少瑞原创教程 www.richbox.net/blog 29. operation.addErrorListener(handleError); 30. } 31. 32. protected function handleComplete(event:OperationEvent):void { 33. _applicationModel.viewIndex = 1; 34. _applicationModel.employeeList = event.result; 35. dispatchCompleteEvent(event.result); 36. } 37. 38. protected function handleError(event:OperationEvent):void { 39. dispatchErrorEvent(event.error); 40. } 41. 42. 43. } 44. } 各个部分准备完毕之后,我们在 XML 配置中完成装配: 1. 2. 7. 8. 9. 10. 11. 12. 郭少瑞原创教程 www.richbox.net/blog 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. mainView 35. 36. 37. 38. 39. 40. 注意其中的 initTask,包含了两个 Command,而且是顺序执行的关系,先执行登 录操作,然后获取用户列表数据。感兴趣的朋友可以尝试修改 和扩展,变为加 入 If 判断或别的机制的应用配置。这是一个简单的示例,真实的应用场景会比 它要复杂,欢迎大家在这里分享自己的经验。
还剩73页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 5 人已下载

下载pdf

pdf贡献者

yb520315

贡献于2011-09-13

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!