先说下我的基本情况:
写了3年纯ActionScript代码, 很少用MXML, 以及Style, Fitler, Validator, Formater等操作. 所以下面的资料中很少有关于Flex 架构及AS的, 如果需要恶补AS, 推荐一本<<Essential ActionScript 3.0>>中文版在08年就已出版, 书不错, 只是翻译的不够流畅.
下面列一下这两天准备ACE考试的资料:
(http://www.adobe.com/support/certification/exams/pdfs/ACE_Exam_Guide_FlexAIR.pdf), 查看考试涉及内容及比例.
作为一个ActionScript程序员, 长期不用MXML, 不用甚至没用过各类UI style, filters, blends以及各类layout都要多多准备.
另外, AIR部分占20%, 对文件操作, SQL操作, Air打包安装, 签名, 个性化窗口均有考察, AS程序员不可不防, 这次考试我AIR部分正确率只有60%…
除了考试大纲之外:Third-party books and resources
The following third-party books and resources will help you with your training:
个人感觉不错的资料:
1. 排第一位的, 自然是Flex文档了: http://livedocs.adobe.com/flex/3/html/help.html 知道4的已经有中文版了, 似乎3的也曾见过中文版, 总之还是看英文版吧, 应该熟悉而不熟悉的操作, Class都应该了解清楚;
(这书是去年在某次Adobe上海开发者日的时候狗屎运抽奖抽到的, 一直以来觉得自己Flex还挺良好, 翻都没翻过)
中文名字起的有点大了, 但相比前文所述尚未出版的《Flex 4:开发富媒体应用》要深入一些, 全面一些. 但相对来说, 过于依赖MXML — 很少用, 所以看MXML代码就头大. 在第300多页的时候终于看到一个完整的Class…
不过总体来说, 这本书中Flex相关的知识点算比较全面了, 花了几个小时通读全文, 学了若干MXML标签, 才得以应付得了考试.
下载地址: http://software.pxldesigns.com/attest/index.php (AIR程序)
内含大致有150道题左右, 基本涉及到大纲中的考点 – (考试题目内容多出自文档中)
第一次做的时候正确率只有50%, 对一个纯种AS程序员来说真是伤不起, 我写了接近三年的AS代码啊, 不说67%的通过底线, 至少也得做个60%吧, 伤不起!
于是挨着大纲把相关知识点过了一遍 – Sytle, 没用过! filter 没用过! Effect 没用过! AIR签名? 不懂! AIR 无缝安装? SQLLite?文件操作? 都TM三年前的事了…
根据这次考试的经验, 评论一下这些模拟题, 涵盖范围较全面, 但有些题目出的很偏 – 尤其是各类Filter/BlendMode/Validator/Formater的名字, 好些题目选俩, 答案里说了: 在真实考试中可能有很多类似题目尤其是Validator, 譬如以下题目:
1. 选择两个Flex中的Validator/Formatter/BlendMode…
2. 选择两个不是关键字, 可以作为ID使用的…
3. 选择不存在于Data Management service的两个方法
这些题目基本靠背诵, 但在真正考试中, 我一个都没碰到过, 因此基本可略过这些低层次的题目, 但相关的知识点都是必看的. 可逐个题目做一下, 检查考点是否都已经熟悉.
Class写的没有问题, 实现了IExternalizable 接口, 但总是报错:
ArgumentError: Error #2173: Unable to read object in stream. The class com.liguoliang.helloworld.Department does not implement flash.utils.IExternalizable but is aliased to an externalizable class.
at ObjectInput/readObject()
at mx.collections::ArrayList/readExternal()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\collections\ArrayList.as:586]
at mx.collections::ArrayCollection/readExternal()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\collections\ArrayCollection.as:147]
at ObjectInput/readObject()
at mx.messaging.messages::AbstractMessage/readExternal()[E:\dev\4.0.0\frameworks\projects\rpc\src\mx\messaging\messages\AbstractMessage.as:486]
at mx.messaging.messages::AsyncMessage/readExternal()[E:\dev\4.0.0\frameworks\projects\rpc\src\mx\messaging\messages\AsyncMessage.as:170]
at mx.messaging.messages::AcknowledgeMessage/readExternal()[E:\dev\4.0.0\frameworks\projects\rpc\src\mx\messaging\messages\AcknowledgeMessage.as:95]
找来找去找不到原因, 后来发现在App中根本没有使用过这个类! 很久没开发Flex, 把这么个事给忘了… 个人感觉应该报Class not found的错啊 🙁
对于没有使用过的类, 可以在App中引用一下, 确保在编译时不要被忽略:
// 本例中未试过用Department类, 仅作引用; private static function __ref():void { Department; }
本教程简要介绍基于Athena框架的Flex应用开发. 假定你已具备基本的Flex + Java开发技能. 我们将使用Athena框架快速创建一个类似与Adobe Flex Test Drive的小应用(链接), 该应用与Adobe Flex Test Drive的不同之处在于: Flex端采用了Athena Framework, 并基于Athena Framework增加了服务器端的支持.
由于时间有限, 本例仅展示环境配置, 基于Athena Console管理数据结构并自动生成Java, Flex代码, 通过简单编程实现基本功能.
所有的代码均可通过: http://code.google.com/p/athenahelloworld/ checkout(不含lib).
本文分三部分:
下图为Athena framework官方提供的Test Drive最后效果图, 可进行Employ的CRUD, 并列出Department的所有employ.
在教程1中已经创建好了Java工程及Flex工程;
在教程2中已经使用AthenaConsole及metadata workbench配置好了数据库,并进行了建模及代码生成;
本节我们将编写Java端及Flex端代码, 并最终运行程序;
在Athena框架下, Flex可以直接呼叫Java端的Service. 除了Service Class本身之外, 还需要在xml文件中声明该类, 以便Flex端呼叫使用.
Athena框架下的ServiceClass负责响应Flex端的请求, 与数据库进行交互. 我们可继承org.athenasource.framework.eo.web.service.AbstractService类以快速创建Service.
package com.liguoliang.helloworld.service; import java.util.List; import org.athenasource.framework.eo.core.EOContext; import org.athenasource.framework.eo.query.EJBQLSelect; import org.athenasource.framework.eo.web.service.AbstractService; public class DeptService extends AbstractService { /** * 加载Department列表 * @return */ public List<Object> loadDepts() { EOContext eoContext = createEOContext(); // 创建Athena EoContext; String strEJBQL = "SELECT dept FROM Department dept"; // 加载所有Department; EJBQLSelect select = eoContext.createSelectQuery(strEJBQL); return select.getResultList(); // 执行EJBQL, 并返回所有数据; } }
为了便于Flex端呼叫Service, 我们需要事先创建eo-services.xml配置文件, 该文件位于: WEB-INFO 根目录下, 该目录下有我们在教程1中介绍的eo-config.xml, flex-services.config.xml文件.
我们需要创一个专门存放Service的xml文件: eo-services.xml, 该文件的样例请参考官方文档, 我们增加刚才创建的DeptService:
<service class=”com.liguoliang.helloworld.service.DeptService;” name=”deptService” description=”AthenaFramework HelloWorld” />
Java端工程目录见文末附图;
至此, 我们已经创建并配置好了DeptService, 万事俱备, 只等Flex端来Call了!
在Flex端工程中需要将athena-flx-2.0.0.swc放入labs目录.
将在Application创建完毕后立即初始化EoService, 基于EoService可呼叫Java端定义的Service.
import com.liguoliang.helloworld.Department; import mx.collections.ArrayCollection; import mx.controls.Alert; import mx.events.FlexEvent; import org.athenasource.framework.eo.core.EOService; import org.athenasource.framework.eo.core.ioc.EOServiceLocator; import org.athenasource.framework.eo.remoting.event.EventEOService; import org.athenasource.framework.eo.remoting.event.EventRemoteOperationError; import org.athenasource.framework.eo.remoting.event.EventRemoteOperationSuccess; /** EOService */ protected var eoService:EOService; /** * 创建完毕后响应, 初始化EOService(将会加载Metadata基础数据) */ protected function onCreationComplete(event:FlexEvent):void { // Initialize eoService eoService = new EOService("http://localhost:8080/AthenaHelloWorld/messagebroker/amf", "eo", 2, true, onEoServiceEvent); // Set Service Locator EOServiceLocator.getInstance().eoService = eoService; } /** * EoService初始化完毕, 如果成功则立即加载Department列表. */ protected function onEoServiceEvent(event:EventEOService):void { if(event.kind == EventEOService.KIND_LOGIN_SUCCESS) { trace("Metadata 加载成功"); loadDepts(); // 加载列表 }else if(event.kind == EventEOService.KIND_LOGIN_ERROR || event.kind == EventEOService.KIND_META_LOAD_ERROR) { Alert.show("ERROR: " + event.errorMessage); } } // 加载Department列表 - EoService已初始化完毕, 在任意位置使用EOServiceLocator.getInstance().eoService即可拿到eoService实例; // 使用eoService呼叫Java端创建的Service. private function loadDepts():void { // 注意首个参数serviceName - 需要与Java端eo-service.xml中配置的Service name相同. EOServiceLocator.getInstance().eoService.invokeService("deptService", "loadDepts", [], onLoadDeptsSuccess, onLoadDeptsError); } // 加载成功后响应. private function onLoadDeptsSuccess(e:EventRemoteOperationSuccess):void { var deptsAC:ArrayCollection = e.data as ArrayCollection; trace("加载到的Dept列表长度: " + deptsAC.length); datagirdDepts.dataProvider = deptsAC; // deptsAC中数据为Department类的实例. } private function onLoadDeptsError(e:EventRemoteOperationError):void { Alert.show(e.exceptionDetails, "加载失败!"); }
枯燥的配置只是为了更简单流畅的开发, 终于到了真正运行的时刻了
(在运行之前, 为了方便演示, 我已在数据库中插入了两条测试记录)
运行成功:
可通过配置Java端src根目录下log4j.properties文件以查看更多debug信息(如不存在请创建)
[http-8080-1] INFO uery.EJBQLSelect – EJBQL: SELECT dept FROM Department dept
[http-8080-1] INFO uery.EJBQLSelect – SQL: SELECT dept.department_ID, dept.version, dept.status, dept.ORG_ID, dept.deptName FROM Department dept WHERE dept.status <> 4
本例代码可通过Google code checkout: http://code.google.com/p/athenahelloworld/
其中包含: Java, Flex工程文件(均不含lib), 数据库sql文件(包含在Java工程中),
可下载Athena framework官方示例程序进一步体验: http://athenasource.org/flex/basic-tutorial.php
附录: helloworld最终目录结构:
基于Athena Console可快速创建并管理数据库, 维护数据库结构, 并自动生成代码.
由于数据库并不存在, 因此”Check database”时会提示未知数据库, 此时可点击”Create database”自动创建数据库:
“Creating database: helloWorld …
Database created successfully.”
helloWorld数据库被创建, 但没有任何table. 点击”Initialize database”, 会自动创建框架用于存储数据库结构的内置Table:
这些Table用于存储MetaData, 如: Entity存储Table信息, attribute存储Table中字段信息, relationship存储entity关系信息(如department.employees)
此时数据库已初始化完毕, 点击控制台上方按钮进行建模:
基于Metadata workbench可直接将程序员从数据库处理中解脱处理, 所有操作均在workbench中操作即可达成Table创建, 字段维护等操作.
我们会创建一个Department的Table(Entity), 其中包含有deptName 字段(Attribute)
System name将作为Entity生成代码后的Class名称;
Table name指Table名称(该Table会自动创建, 无需手动操作)
Package name配置了代码生成时的Package路径;
Display name为默认的显示名称; i18n name可自动进行i18n国际化.
为Department增加Attribue:
值得一提的是:
System name会作为Java及Flex两端代码的属性名称; 在命名时会禁止使用各数据库的保留字段;
Column type内置几乎所有的类型, 可根据具体数据库自动创建字段;
配置完毕后保存Entity, 返回控制台程序.
代码生成完毕, 刷新Java与Flex工程, 可以看到代码已生成:
每个Entity会为每种语言自动生成两个Class, 如: Department_EO, Department;
Department_EO: 当metadata有变化, 再次生成代码时, 将会覆盖本类, 因此不建议对本类进行任何手工改动;
Department: 该类继承自: Department_EO仅当第一次生成代码时产生该类, 以后再次生成将不会进行任何覆盖操作; 因此可对重写父类Method或增加其他Method;
// Proudly powered by Apache, PHP, MySQL, WordPress, Bootstrap, etc,.