本教程简要介绍基于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;
在服务器端, 我们采用MySql数据库;
除了开发必须的IDE, MySql之外, 需要先下载或安装以下文件: 下载页面
docs: 存放文档, 与Flex文档类似, 有HTML及PDF;
lib: 存放程序运行依赖的jar, 如mysql-connector, BlazeDS等jar包;
src: 目录存放程序源代码
athena打头的jar供Java端使用;
athena打头的swc供Flex端使用; sdk的具体使用在后文有介绍;
配置可参见http://athenasource.org/flex/basic-tutorial.php?part=1
至此, 服务器端已基本配置完毕;
使用FlashBuilder创建工程:
注意: server type选择None/Other, 我们使用编程方式链接服务器;
复制src目录地址, 配置到flex-services.config.xml中, 为下一步的代码生成做好准备;
JSP在include时如果不在被Include文件中声明编码, 在外部文件中将出现乱码. 解决方案就是:
在被Include jsp文件中声明:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
此时如果外部jsp编码为 utf-8 — 即: 两者utf-8大小写不同, 将会出现如下错误:
Page directive: illegal to have multiple occurrences of contentType with different values (old: text/html; charset=utf-8, new: text/html; charset=UTF-8)]
可通过配置Eclipse/MyEclipse jsp文件默认编码来避免不必要的操作: http://liguoliang.com/2011/set-eclipse-jsp-files-encoding-utf-8/
// Proudly powered by Apache, PHP, MySQL, WordPress, Bootstrap, etc,.