原文:Flash Remoting for Rails Tutorial
里克:1、Flash Remoting从flash player6就开始了,Flex Client是个新家伙。2、Flash Remoting如何翻译?我想翻译为flash远程。
在我们使用Rails的时候,可能会忽视掉另一个开发工具:Flash Remoting。长期的使用xml,可能会改变你的编程习惯。就像作者引用的那句话:”If all you have is a hammer everything looks like a nail”。Remoting可以直接向flash传递对象,数组。Remoting使用AMF(Active Message Format)传递byte流,这比使用xml要快很多。
而且在06年8月,Midnight Coders发布了他们的WebORB插件。
他们的例子是基于Flex2的,这需要客户端安装Flash player9.0,这并不有好,因为Remoting在Flash player6中就已经开始使用了。所以这里我们只拿我们需要的。
如果你之前没有使用过Flash Remoting,请先安装Remoting Components。
这里我们制作一个flash的mp3播放器,用rails作为后端服务。点击这里,你可以下载这个例子的代码。
创建一个应用:mp3app
> rails mp3app > cd mp3app
安装weborb插件
> ruby script/plugin install http://themidnightcoders.net:8089/svn/weborb
创建一个名为‘mp3app_development’的数据库
CREATE TABLE `tracks` (
`id` int(11) NOT NULL auto_increment,
`title` varchar(50) NOT NULL default '',
`artist` varchar(50) NOT NULL default '',
`album_art` varchar(50) NOT NULL default '',
`filename` varchar(50) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
insert into `tracks` values
('1','After Midnight','Eric Clapton','clapton.jpg','AfterMidnight.mp3'),
('2','Midnight Train to Georgia','Gladys Knight','gladys.jpg',
'MidnightTrainToGeorgia.mp3'),
('3','Midnight In A Perfect World','DJ Shadow','shadow.jpg',
'MidnightInAPerfectWorld.mp3'),
('4','Two Minutes to Midnight','Iron Maiden','maiden.jpg',
'TwoMinutesToMidnight.mp3');
创建‘Track’model
> ruby script/generate model Track
在‘app/services’目录下创建一个Remoting services服务,文件为:’TrackService.rb’
require 'weborb/context'
require 'rbconfig'
class TrackService
def getTracks
tracks = Track.find(:all)
end
end
如果你曾经用过AMFPHP或者.net下的Remoting,上面的这个服务端可以说是“相当”简单了。但是你可以运行测试一下。
下面进入到我们的Flash。
对于Flash应用,有几个框架可供选择,比如ARP和 Cairngorn。但是在我们这个应用上,他们显得太过强大了。我们可以写一个自己的轻量级的框架。这是一种MVC框架,Model是一个Remoting Class,用来和后台程序沟通(PHP, .NET, 或者 我们的 Rails) ,一个.fla的controller,和一个View class。
M 和 V 在 C 的控制下进行事件相应与处理,而其他的类来扩展其他的功能。
基本的Remoting是这样:
import mx.remoting.Service;
import mx.services.Log;
import mx.remoting.PendingCall;;
import mx.rpc.RelayResponder;
import mx.rpc.FaultEvent;
import mx.rpc.ResultEvent;
import mx.remoting.debug.NetDebug;
import mx.utils.Delegate;
class com.vixiom.remoting.Remoting
{
private var gatewayURL:String;
private var servicePath:String;
private var svc:Service;
function dispatchEvent() {};
function addEventListener() {};
function removeEventListener() {};
/**
* Constructor
*
* @param gURL gatewayURL
* @param sp service path
* @param u username
* @param p password
*
*/
public function Remoting(gURL, sp, u, p)
{
gatewayURL = gURL;
servicePath = sp;
// initialize as a broadcaster
mx.events.EventDispatcher.initialize(this);
// create a new service
svc = new Service (gatewayURL, null, servicePath, null, null);
// credentials
if (u != undefined && p != undefined) {
svc.connection.setCredentials(u, p);
}
}
/**
* Global fault event
*/
function handleRemotingError(fault:FaultEvent):Void
{
mx.remoting.debug.NetDebug.trace({level:"None",
message:"Error: " +
fault.fault.faultstring });
}
/**
* Event dispatcher
*
* @param d data
* @param et eventType
*
*/
function dispatch(d, et)
{
// broadcast message
var eventObj:Object={target:this,type:et}
eventObj.data = d;
dispatchEvent(eventObj);
}
}
基本的View Class是这样:
import mx.utils.Delegate;
class com.vixiom.view.View
{
private var target:MovieClip;
function dispatchEvent() {};
function addEventListener() {};
function removeEventListener() {};
/**
* Constructor
*
* @param t target (target timeline: _root || a mc)
*/
public function View (t:MovieClip)
{
target = t;
// initialize as a broadcaster
mx.events.EventDispatcher.initialize(this);
}
/**
* Event dispatcher
*
* @param d data
* @param et eventType
*
*/
function dispatch(d, et)
{
// broadcast message
var eventObj:Object={target:this,type:et}
eventObj.data = d;
dispatchEvent(eventObj);
}
}
里克:看到这个时候,我看了一下源代码。as文件的存放是按照类似java的形式。所以下面的话就好理解了。我对as的知识为0.
在这个MP3 player中,我用下面的方法扩充一下Remoting class。你可以不必把你的类放到这个packages里面,当然那样做更利于管理。
'var pc:PendingCall = this.svc.getTracks();'
一句是再远程调用Rails,这和TrackService.rb 类里面的’getTracks’是一样的。我的类中有一个tracks对象,它直接接收ruby的’tracks = re.result;’。我注释了’this.svc.connection.setCredentials(u, p);’一行,因为它在创建一个安全的远程调用。最后一行’dispatch(tracks, “onGetTracks”);’ 将数据传递给view。
import mx.remoting.*;
import mx.rpc.*;
class com.vixiom.remoting.RemotingMp3
extends com.vixiom.remoting.Remoting
{
// tracks holder object
private var tracks:Object;
////////////////////////////////////////////////////////////////
//
// Constructor (gatewayURL, servicePath, userid, password)
//
////////////////////////////////////////////////////////////////
public function RemotingMp3 (gURL, sp, u, p)
{
super(gURL, sp);
// this.svc.connection.setCredentials(u, p);
}
////////////////////////////////////////////////////////////////
//
// Get tracks with handler (onGetTracks)
//
////////////////////////////////////////////////////////////////
public function getTracks()
{
trace("// getting tracks")
// create a pending call out to rails
var pc:PendingCall = this.svc.getTracks();
// create a responder to handle the return from rails
pc.responder = new RelayResponder(this,
"onGetTracks",
"handleRemotingError");
}
public function onGetTracks (re:ResultEvent)
{
if (re != undefined)
{
trace("// onGetTracks broadcaster - Word!")
// put result in recordset
tracks = re.result;
// trace for testing
for (var i = 0; i < tracks.length; i++) {
trace(tracks[i].title);
}
// dispatch event to the view
dispatch(tracks, "onGetTracks");
}
}
}
下面是controller的代码,需要注意的是,‘Rmp3’是我扩展的Remoting class的实例。它有两个参数,一个是WebORB geteway url,一个是在app/services中的’TrackService’类。我还没有展示扩展的view class,controller里已经产生了一个‘Vmp3’实例,with the _root of the Flash file as it’s parameter (it uses that as a target). 。下面四行是view中的按钮方法,最后一行调用远程方法,这是这个app的entry point(as it’s pretty useless sans data)。
// import remoting, view, and debug
import mx.remoting.debug.NetDebug;
import mx.utils.Delegate;
import com.vixiom.remoting.RemotingMp3;
import com.vixiom.view.ViewMp3;
// ini debug
NetDebug.initialize ();
iniApp();
// setup and start
function iniApp()
{
// create remoting & view objects
var Rmp3:RemotingMp3 = new RemotingMp3 (
"http://localhost:3000/weborb",
"TrackService"); // weborb gateway, ruby class name
var Vmp3:ViewMp3 = new ViewMp3 (_root);
// set up listeners
Rmp3.addEventListener ("onGetTracks",
Delegate.create (Vmp3, Vmp3.onGetTracks));
pause_btn.onRelease = Delegate.create(Vmp3, Vmp3.pauseTrack);
play_btn.onRelease = Delegate.create(Vmp3, Vmp3.playTrack);
prev_btn.onRelease = Delegate.create(Vmp3, Vmp3.previousTrack);
next_btn.onRelease = Delegate.create(Vmp3, Vmp3.nextTrack);
// start the app, get the tracks
Rmp3.getTracks();
}
下面是扩展的view,相当复杂,而且和rails及Remoting没什么关系,所以看一下它的注释,就能明白它的意思了。里克:我就不贴了,看类名就知道它在哪了。
class com.vixiom.view.ViewMp3 extends com.vixiom.view.View
就是这样了,不过要注意一下跨域安全问题,尤其是当你的rails应用在一台服务器上,而Flash文件在另一台服务器上的时候。
里克,07年10月23日,Railser.cn
