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项目