Cairgorm?+?Django?+?PyAMF简易教程
一、技术简介
1.?Cairngorm框架
????Cairngorm是一个轻量级的用于Flex项目开发的MVC框架,主要由vo、command、event、controller、service、delegate和modellocator等部分构成。其中vo用于数据对象的封装;service主要用于与远程服务器端打交道;delegate为业务逻辑层,接收command对象传来的请求并通过调用service中的方法来处理请求;event为自定义事件;command会接受并处理相应的event;controller通过调用addCommand方法将event和相应的command联系起来;?modellocator存储公共变量;view为应用界面。
2.?Django框架
????django是一个基于python的web开发框架。开发者通常需要编辑的文件有:view,用于实现业务逻辑和动态页面显示;models,数据表对象;forms,表格对象;url,联系访问地址和处理模块;setting,设置django服务器。
二、开发环境
1.?客户端:Win7,FlexBuilder3,Cairngorm
2.?服务器端:CentOS,Python2.5,django.VERSION(1,?2,?4,?'final',?0)
三、开发过程
1.?flex项目开发
1)新建flex?project如命名为CairngormDemo-->选中libs并右键导入cairngorm.swc文件
2)新建folder?“vo”,在vo中新建ActionScript?Class?“?ContactVO”,内容如下:
package?vo
{
????//对象属性必须与服务器端model中相应的类对应
????//[RemoteClass?(alias="vo.ContactVO")]跟服务器端的Contact绑定
????//Bindable标签为Flex中的元标签,其作用为绑定,即当被绑定者改变的时候(被赋值了),可能通知其它被其影响(赋值给它们)的变量发生改变,这里的“可能”就需要编译器来判断。
????[Bindable]
????public?class?ContactVO?extends?Object
????{
????????public?var?id:int;
????????public?var?name:String;
????????public?var?address:String;
????????public?function?ContactVO(name:String,address:String)
????????{
????????????this.name?=?name;
????????????this.address?=?address;
????????}
????}?
}
3)新建folder?“model”,在model中新建ActionScript?Class?“MyModelLocator”并实现com.adobe.cairngorm.model.ModelLocator接口,内容如下:
package?model
{
????//model类使用了单例模式,主要用于存放公共变量
????import?com.adobe.cairngorm.model.ModelLocator;
????import?mx.collections.ArrayCollection;
????import?vo.ContactVO;
????public?class?MyModelLocator?implements?ModelLocator
????{
????????//ArrayElementType元数据标签可以让定义的数组元素的数据类型
????????[ArrayElementType("ContactVO")]
????????private?static?var?myModelLocator:MyModelLocator=null;
????????[Bindable]
????????public?var?contactColl?:?ArrayCollection?=?new?ArrayCollection();
????????public?function?MyModelLocator()
????????{
????????}
????????public?static?function?getInstance():MyModelLocator
????????{
????????????????if(myModelLocator?==?null)
????????????????????myModelLocator?=?new?MyModelLocator();
????????????????return?myModelLocator;
????????}
????}
}
4)新建folder?“service”,在vo中新建ActionScript?Class?“?MyService”,内容如下:
package?service
{
????//service类使用单例模式,用于与后台django通信
????import?mx.messaging.ChannelSet;
????import?mx.messaging.channels.AMFChannel;
????import?mx.rpc.AsyncToken;
????import?mx.rpc.remoting.RemoteObject;
????import?vo.ContactVO;
????public?class?MyService
????{
????????//AMFChannel?uri
????????public?var?serverAmfPath:String;
????????static?private?var?instance:MyService?=?null;
????????private?var?ro:RemoteObject;
????????public?function?MyService()
????????{
????????????initAMFChannel();
????????}
????????static?public?function?getInstance():MyService
????????{
????????????if(instance?==?null)
????????????????instance?=?new?MyService();
????????????return?instance;
????????}
????????//初始化amf信道
????????private?function?initAMFChannel():void
????????{
????????????var?cs:ChannelSet?=?new?ChannelSet(null,false);
????????????//serverAmfPath用于定义服务器地址
????????????serverAmfPath?=?"http://192.168.6.140:8000/gateway/";
????????????var?amfc:AMFChannel?=?new?AMFChannel("amfChannel",serverAmfPath);
????????????cs.addChannel(amfc);
????????????//destination属性是网关服务的名称,在本例中为myservice
????????????ro?=?new?RemoteObject("myservice");
????????????ro.channelSet?=?cs;
????????}
????????//通过RemoteObject调用服务器端方法
????????public?function?saveContact(contact:ContactVO):AsyncToken
????????{
????????????var?token:AsyncToken?=?ro.saveContact(contact.name,contact.address);
????????????return?token;
????????}
????????public?function?getContactList():AsyncToken
????????{
????????????var?token:AsyncToken?=?ro.getContactList();
????????????return?token;
????????}
????}
}
5)新建folder?“business”,在vo中新建ActionScript?Class?“?MyDelegate”,内容如下:
package?business
{
????//调用service类与服务器通信
????import?mx.rpc.IResponder;
????import?mx.rpc.AsyncToken;
????import?service.MyService;
????import?vo.ContactVO;
????import?mx.controls.Alert;
????public?class?MyDelegate
????{
????????private?var?responder:IResponder;
????????private?var?serv:MyService;
????????public?function?MyDelegate(responder:IResponder)
????????{
????????????this.responder?=?responder;
????????????this.serv?=?MyService.getInstance();
????????}
????????//调用代理方法
????????public?function?addContact(contact:ContactVO):void
????????{
????????????var?token:AsyncToken?=?this.serv.saveContact(contact);
????????????token.addResponder(this.responder);
????????}
????????public?function?getContactList():void
????????{
????????????var?token:AsyncToken?=?this.serv.getContactList();
????????????token.addResponder(this.responder);
????????}
????}
}
6)新建folder?“event”,在event中新建ActionScript?Class?“AddContactEvent”和“GetContactListEvent”,均继承com.adobe.cairngorm.control.CairngormEvent类,内容分别如下:
package?event
{
????//自定义事件,添加通信记录
????import?com.adobe.cairngorm.control.CairngormEvent;
????import?vo.ContactVO;
????public?class?AddContactEvent?extends?CairngormEvent
????{
????????public?static?const?ADD_CONTACT_EVENT:String?=?"addcontact";
????????public?var?contactVO:ContactVO;
????????public?function?AddContactEvent(contactVO:ContactVO)
????????{
????????????super(AddContactEvent.ADD_CONTACT_EVENT);
????????????this.contactVO?=?contactVO;
????????}
????}
}
------------------------------------------------------------------------------------------------------------
package?event
{
????import?com.adobe.cairngorm.control.CairngormEvent;
????import?vo.ContactVO;
????public?class?GetContactListEvent?extends?CairngormEvent
????{
????????public?static?const?GET_CONTACT_LIST_EVENT:String?=?"getcontactlist";
????????public?function?GetContactListEvent()
????????{
????????????super(GetContactListEvent.GET_CONTACT_LIST_EVENT);
????????}
????}
}
7)新建folder?“command”,在command中新建ActionScript?Class?“AddContactCommand”和“GetContactListCommand”,均实现com.adobe.cairngorm.commands.ICommand接口,内容分别为:
package?command
{
????//接收事件后,交给相应的command处理
????import?business.MyDelegate;
????import?com.adobe.cairngorm.commands.ICommand;
????import?com.adobe.cairngorm.control.CairngormEvent;
????import?event.AddContactEvent;
????import?model.MyModelLocator;
????import?mx.controls.Alert;
????import?mx.rpc.Responder;
????import?mx.rpc.events.ResultEvent;
????import?vo.ContactVO;
????public?class?AddContactCommand?implements?ICommand
????{
????????public?var?ml:MyModelLocator?=?MyModelLocator.getInstance();
????????public?function?AddContactCommand()
????????{
????????}
????????public?function?execute(event:CairngormEvent):void
????????{
????????????//接收传递来的数据,并存于addContactEvent变量
????????????var?addContactEvent:AddContactEvent?=?AddContactEvent(event);
????????????var?responder:Responder?=?new?Responder(result,fault);
????????????var?delegate:MyDelegate?=?new?MyDelegate(responder);
????????????delegate.addContact(addContactEvent.contactVO);
????????}
????????//命令运行正常的处理函数
????????public?function?result(evt:ResultEvent):void
????????{
????????????ml.contactColl.addItem(evt.result);
????????}
????????public?function?fault(evt:ResultEvent):void
????????{
????????????Alert.show(evt.toString());
????????}
????}
}
------------------------------------------------------------------------------------------------------------
package?command
{
????import?business.MyDelegate;
????import?com.adobe.cairngorm.commands.ICommand;
????import?com.adobe.cairngorm.control.CairngormEvent;
????import?model.MyModelLocator;
????import?mx.collections.ArrayCollection;
????import?mx.rpc.Responder;
????import?mx.rpc.events.ResultEvent;
????public?class?GetContactListCommand?implements?ICommand
????{
????????public?var?ml:MyModelLocator?=?MyModelLocator.getInstance();
????????public?function?GetContactListCommand()
????????{
????????}
????????public?function?execute(event:CairngormEvent):void
????????{
????????????var?responder:Responder?=?new?Responder(result,fault);
????????????var?delegate:MyDelegate?=?new?MyDelegate(responder);
????????????delegate.getContactList();
????????}
????????public?function?result(evt:ResultEvent):void
????????{
????????????ml.contactColl?=?new?ArrayCollection(evt.result?as?Array)
????????}
????????public?function?fault(evt:ResultEvent):void
????????{
????????}
????}
}
8)新建folder?“model”,在model中新建ActionScript?Class?“Controller”,继承com.adobe.cairngorm.control.FrontController,内容如下:
package?control
{
????//接收自定义事件,并绑定到处理该事件的Command类
????import?com.adobe.cairngorm.control.FrontController;
????import?command.AddContactCommand;
????import?event.AddContactEvent;
????import?event.GetContactListEvent;
????import?command.GetContactListCommand;
????public?class?Controller?extends?FrontController
????{
????????public?function?Controller()
????????{
????????????this.addCommand(AddContactEvent.ADD_CONTACT_EVENT,AddContactCommand);
????????????this.addCommand(GetContactListEvent.GET_CONTACT_LIST_EVENT,GetContactListCommand);
????????}
????}
}
9)新建folder?“view”,在view中新建MXML?Component?“view”,内容如下:
<?xml?version="1.0"?encoding="utf-8"?>
<mx:HBox?xmlns:mx="http://www.adobe.com/2006/mxml"?width="564"?height="220">
<mx:Script>
?<![CDATA[
???import?mx.collections.ArrayCollection;
???import?vo.ContactVO;
???import?event.AddContactEvent;
???import?com.adobe.cairngorm.control.CairngormEventDispatcher;
??
???[Bindable]
???public?var?contactColl:ArrayCollection?=?new?ArrayCollection();
????????
???private?function?addContact():void
???{
????var?contactVO?:?ContactVO?=?new?ContactVO(xxName.text,xxAddr.text);
????var?event?:?AddContactEvent?=?new?AddContactEvent(?contactVO?);
?????CairngormEventDispatcher.getInstance().dispatchEvent(?event?);
?????
?????xxName.text="";
?????xxAddr.text="";
??}
?]]>
</mx:Script>
<mx:Form?id="addcontactForm">?????
?????????<mx:FormItem?label="姓名:?">
?????????????<mx:TextInput?id="xxName"/>
?????????</mx:FormItem>????
?????????<mx:FormItem?label="地址:?">
?????????????<mx:TextInput?id="xxAddr"/>
?????????</mx:FormItem>??????????
?????????<mx:Button?label="添加"?click="addContact()"/>
?????</mx:Form>?
??<mx:VRule??height="100%"?strokeColor="#DDDDDD"/>
??<mx:DataGrid?dataProvider="{contactColl}"?width="308"?height="220"?alternatingItemColors="[#86EFF0,?#FFFFFF]">
??<mx:columns>
??<mx:DataGridColumn?headerText="姓名"?dataField="name"?width="100"/>
??<mx:DataGridColumn?headerText="地址"?dataField="address"/>
??</mx:columns>
??</mx:DataGrid>
</mx:HBox>
10)编写主模块
<?xml?version="1.0"?encoding="utf-8"?>
<mx:Application?xmlns:mx="http://www.adobe.com/2006/mxml"?layout="absolute"
xmlns:v="view.*"?xmlns:c="control.*"?creationComplete="init()">
<mx:Script>
<![CDATA[
????import?model.MyModelLocator;
????import?com.adobe.cairngorm.control.CairngormEventDispatcher;
????import?event.GetContactListEvent;
????[Bindable]
????public?var?ml:MyModelLocator?=?MyModelLocator.getInstance();
????public?function?init():void
????{
????????var?event:GetContactListEvent?=?new?GetContactListEvent();
????????CairngormEventDispatcher.getInstance().dispatchEvent(event);
????}
]]>
</mx:Script>
<c:Controller?id="addControl"/>
<v:view?id="addView"?contactColl="{ml.contactColl}"/>
</mx:Application>
3.Django项目开发
0)准备工作:配置mysql数据库使其支持中文存取;安装PyAMF模块
1)创建django项目和应用
#?mkdir?/tmp/test
#?cd?/tmp/test
#?django-admin.py?startproject?contact
#?cd?contact
#?python?manage.py?startapp?addcontact
2)编辑数据模型文件
#?cd?addcontact
#?vi?models.py
//内容如下
from?django.db?import?models
class?Contact(models.Model):
????????name?=?models.CharField(max_length=30)
????????address?=?models.CharField(max_length=100)
????????def?__unicode__(self):
????????????????return?self.name
3)编辑setting.py文件,主要内容如下:
。。。
DATABASES?=?{
????'default':?{
????????'ENGINE':?'django.db.backends.mysql',?#?Add?'postgresql_psycopg2',?'postgresql',?'mysql',?'sqlite3'?or?'oracle'.
????????'NAME':?'contact',??????????????????????#?Or?path?to?database?file?if?using?sqlite3.
????????'USER':?'root',??????????????????????#?Not?used?with?sqlite3.
????????'PASSWORD':?'password',???
。。。
INSTALLED_APPS?=?(
????。。。
????#?Uncomment?the?next?line?to?enable?the?admin:
????'django.contrib.admin',
????'contact.addcontact',
)
。。。
4)编辑url.py文件,内容如下
from?django.conf.urls.defaults?import?*
#?Uncomment?the?next?two?lines?to?enable?the?admin:
from?django.contrib?import?admin
admin.autodiscover()
urlpatterns?=?patterns('',
?。。。
????#?Uncomment?the?next?line?to?enable?the?admin:
????(r'^admin/',?include(admin.site.urls)),
)
5)同步数据库
#?python?manage.py?syncdb
。。。
6)在contact目录下创建amfgateway.py文件,内容如下:
import?pyamf
from?pyamf.flex?import?ArrayCollection,?ObjectProxy
from?pyamf.remoting.gateway.django?import?DjangoGateway
from?contact.addcontact.models?import?Contact
#pyamf.register_class(Contact,?'vo.ContactVO')
def?saveContact(request,?name,?address):
???c?=?Contact()
???c.name?=?name
???c.address?=?address
???c.save()
???return?c
def?getContactList(request):
???emailList?=?Contact.objects.all()
???return?emailList
services?=?{
???'myservice.getContactList':getContactList,
???'myservice.saveContact':saveContact,
}
myGateway?=?DjangoGateway(services,?expose_request=True)
7)在url.py中添加语句(r'^gateway/',?'contact.amfgateway.myGateway'),,其末尾的“,”一定不要忘记
8)编写c.py测试文件如下:
from?pyamf.remoting.client?import?RemotingService
import?sys
gateway?=?RemotingService('http://127.0.0.1:8000/gateway/')
saveContact?=?gateway.getService('myservice.saveContact')
rs?=?saveContact('testName','testAddress')
print?rs
sys.exit(0)
9)启动服务器
//我的虚拟机的ip为192.168.6.140
#?python?manage.py?runserver?192.168.6.140:8000
10)运行测试程序,测试amf是否工作正常
4.启动客户端Flex项目