Flash Remoting 的开发模式
自从三年前我开始从事 Java 网站后台开发工作以来,我一直都在寻找一种比较好的开发模式。纵观现在众多的网站开发方式,虽然开发语言各不相同,但是形式没什么太大的变化。
无论你采用 Perl,PHP,ASP,JSP,实际的过程大致是这样的。
1:用户到你的站点,输入信息,点击“提交”按钮
2:用户等待来自服务端的响应,浏览器加载响应页面,用户可以查看结果。
3:如果结果集不止一页,用户会点击下一页,搜索的请再次提交给服务器,服务端的程序再次搜索结果将第二页结果页面返回给用户的浏览器。
4:如此往复。
总的来说,就是request/response/session 的开发方式,如果习惯了开发桌面应用程序的人,开始的时候会很不习惯这种方式,两个非常关键的技术 — 组件技术和事件驱动开发是长久以来网站开发模式所缺乏的。传统的网站开发技术都会涉及到request, response,session 这三个词汇,无论是采用什么语言,什么技术,而不能以事件驱动和组件为基础来开发应用。虽然 SUN 最近发布了 JSF,试图给 J2ee 添加事件驱动的开发方式,但是据反映,效果不好,现在有一些不错的组件开发的尝试,比如 Apache 的 Tapestry ,它就是采用一种组件的方式,将 request/response/session 从开发者中的视野中屏蔽掉,取而代之的是 object/method/property,开发人员可以不需要知道 request/response/session 的存在,而以面向对象的方式开发自己的组件,用组件来组装自己的网页,它的特色就是组件开发方式,MVC 出色的分离(我个人认为是众多框架中,MVC做的最好的),但是它没有解决另外一个非常重要的问题 — 事件驱动开发。 事件驱动开发方式在桌面应用程序开发中是非常普遍的,用过 VB,Delphi 等C/S 开发工具的人都不陌生。为什么 B/S 开发模式中一直没有事件驱动呢。原因在于 http 协议的“无状态”特性,服务器对于每一次来自浏览器的请求都当作完全新的用户,为了保持状态信息,许多应用服务器都提供“状态管理”,就是通常所说的 session 管理。这样就给最终用户一个无缝集成的假象,好像每次自己的请求都服务器识别为来自一个特定用户的请求,最有名的例子,就是购物网站的购物框。基于这种情况,采用事件驱动开发就非常的困难,还有 HTML 页面本身就不适合事件驱动开发,每次无论返回的结果是大还是小,都会重新刷整个页面,这种开发方式效率也是非常低的,造成大量带宽资源的浪费,服务器端增加Session 管理也会增加服务器资源的浪费。
现在真正采用事件驱动和组件模型来开发网站的技术,大概只有两种:ASP.net和Flash Remoting。前者我本人不来熟悉,对于服务器端技术,它太依赖于微软,客户端也依赖于微软,总的来说,它是个专有技术。而 Flash Remoting 是属于 Macromedia公司的,前端技术依赖于该公司的 Flash ,而后端技术部分依赖于Macromedia,为什么这么说呢, Flash remoting 技术由两个部分组成,前端部分是用 Flash + Flash Remoting 组件来开发,后端采用 Flash remoting gateway + 任何一种后来技术。而 Flash Remoting gateway 现在有很多开发源码的实现方式。这样 Flash Remoting 基本上可以说在服务器端是有众多选择的。
那么让我们看看到底 Rlash Remoting 是个什么东西。
简单的说, FLash remoting 可以让Flash 直接调用服务端的远程过程。服务器端的开发无需做任何适应 Flash 的调正,它可以采用采用任何语言和技术,使用最好的设计模式来设计服务端程序,,无需使用任何 Flash 的API,而有了Flash remoting ,Flash 程序可以调用任何远程服务。
作为 Flash remoting 服务端最重要的技术的就是 The Flash Remoting gateway,它安装在应用服务器上,作为 Flash 播放器和应用服务器之间的一个接口,它主要完成三个工作。
1:将Flash 播放器的请求传递给服务器
2:将来自 Flash 播放器的请求和数据翻译成服务器端的请求和数据
3:将服务器端的响应和数据翻译成Actionscript 的本地数据类型。
Flash 播放器和Flash gateway 之间使用的通信协议是Macromedia自己开发的一种二进制协议 AMF(Action Message Format),它是一种轻量级,高效协议,能够快速的在二者之间序列化,反序列化和传递数据。其实如果大家熟悉 SOAP 的话,会发现这个协议在很多情况上是再对SOAP 重新构造,你可以认为 AMF是Macromedia 的二进制版本的SOAP协议。为什么Macromedia 会再造车轮呢?
首先:Soap 是基于 XML 的,与二进制的AMF 相比,它显得过于累赘,或者说“重量级”,其次:AMF 主要是针对 Actionscript 类型做的设计和优化,它在解析和序列化上都要比 SOAP 这种通用协议格式要高效的多。Flash player 7 可以支持 SOAP,而 FLASH 6 播放器可以通过 Flash remoting gateway 支持SOAP.
总结一下: Flash remoting 由两个部分组成,Flash remoting 组件(客户端) + Flash remoting gateway (服务器端)。
Flash remoting 组件(客户端)主要用于开发人员从事 Flash remoting程序开发,Flash remoting gateway (服务器端)用于将来自 Flash 播放器的对服务器端过程调用的翻译,将它翻译为应用服务器识别的请求调用。然后服务器将结果返回给 Flash remoting gateway ,再由它以 AMF格式返回给 Flash 播放器。
可能到现在还是有人不太明白,Flash remoting 不就是可以让你直接调用服务端的服务吗,这和以前 Flash 5 + XML 的开发方式相比有什么优点。其实一个最明显的有点就是有了 Flash remoting ,开发人员都无需再写客户端和服务端的 XML 解析程序了。此外它可以转换大量的复杂数据类型,自动处理 Actionscript 和服务端的数据转换。使用 AMF来序列化数据也比处理 XML这种字符串的序列化要高效的多,当然提供访问后台服务的一致方式也是它最大的有点,无论后台采用什么技术,前端访问的方式都是不变的。
还有一点值得一提,Flash remoting 处理 Session 的方式对于用户和服务器都是透明的,Session 信息其实包含在每一个AMF包中,无需 Session 管理。因为通常 Flash 是一次性随浏览器加载,此后Session 状态一直自动保持在每次对服务器的调用上,Session 信息保持在 Flash 中,所以服务器是否集群也无多大区别。
Flash 实例编程 Step by Step。
讲述太多的理论,不如用一个具体的例子更能让人理解什么是 Flash remoting.不在一步一步的示范的开始,我要把运行 Flash Remoting 的服务端环境解释一下。前面说过了 Flash remoting 服务端可以采用各种技术,Macromedia 推荐的是它自己公司的两个产品 Coldfusion 和 Jrun ,而 Coldfusion 的底层也是以 Jrun 为基础,不过开发起来更方便,支持Flash remoting 访问 Coldfusion 的网页和组件。 不过价格比较昂贵(几万人民币吧),而 Jrun 是经过Sun j2ee严格认证的应用服务器,而且价格相对很便宜,只有700多美金,所以如果是公司采用 Flash Remoting 的开发方式,我个人觉得 Jrun 是比较超值的。当然如果你不愿意为应用服务器付费的话,还有很多免费的开源解决方案,比如 PHP 项目 www.amfphp.org) 和 Perl 项目 www.simonf.com/flap), 对于 Java 开放者来说 openAMF www.openamf.org 是非常好的开源解决方案,如果有机会我会详细写文章描述这个开源项目。 本人是个 Java 程序员,下面这个例子就采用 Macromedia 的 Jrun 服务器来开发。关于 Jrun 的下载和相关知识,可以参考 Macromedia 网站 www.macromedia.com/software/jrun/?promoid=home_prod_jr_100803。
a) 环境搭建
我希望新建立一个Jrun服务应用以和 Jrun 本身现有的 admin,samples,default 三个 jrun 服务器区别开来,通过 Jrun 新建一个应用。
首先启动 JRun Launcher,点击 admin Jrun Server ,点击 “start” 按钮, 将该服务器启动。它的端口的 8000,这样我们用可以使用 Jrun Management Console了
启动 Jrun Management Console,将打开如下网页。
点击最上面的“Create New Server”
出现一个创建 Jrun 新服务器的新窗口,在 “Jrun Server Name ”中输入 flashremoting ,Jrun 会自动根据你在其中的输入更新 “Jrun Server Directory ” 的内容。点击 “Create Server”
等待片刻,Jrun 将提示创建成功,并将新服务器占用的端口(Jrun分配的)等信息输出,如果你不满意的话,你可以修改。
如果你满意设置,可以点击 “Finish” 按钮,如果不满意端口等设置,可以修改端口号,并点击“Update Port Numbers”进行更新。
打开资源管理器查看,你会发现 Jrun 已经为你在 Server 目录下新建立了一个 Flashremoting 的目录。
b) 开发服务端程序
首先在刚刚建立的 flashremoting 目录的 SERVER_INF 目录下新建立一个 classes 目录。
Jrun 支持FLash 直接调用多种J2ee 技术,最简单是 java class,Java beans,JMX,EJB 我在这里举个 Java Beans的例子。在刚刚建立的 classes 目录中建立如下 Java bean 文件
package com.eiffelqiu.remoting;
public class TestBean implements java.io.Serializable {
private String testvalue = "test";
/**
* Returns the testvalue.
* @return String
*/
public String getTestvalue() {
return testvalue;
}
/**
* Sets the testvalue.
* @param testvalue The testvalue to set
*/
public void setTestvalue(String testvalue) {
this.testvalue = testvalue;
}
}
熟悉 Java 的人会发现这是个非常简单的 Java bean ,甚至连构造函数都给省去了,但是这段程序最关键的部分是我标出红字的部分,也就是:JAVA BEAN 必须实现 Serializable。 如果不实现这个接口,我们将无法将刚刚设置的值再取出来,如果要保持状态信息,你必须实现序列化的接口。有一些网上关于 Flash remoting 的例子省略了这个,结果会造成一些关于 Flash 调用 java bean 的例子无法成功。
进入 classes 目录,在命令行编译这个程序:javac *.java –d .
好了我们所有的服务端程序就完成了。你可能会觉得,就这也太简单了,实际上这正式 Flash remoting 强的地方,服务端程序只要关注自己的技术,无需知道有关Flash 的任何技术,Flash remoting gateway 负责完成Flash Actionscript 对象和服务端对象之间的翻译和转换工作。服务端只要提供一个服务的接口就可以了。这种技术的分割是非常好的,尤其是对于大项目。 按照 Macromedia Flash Remoting 的开发模式,应该分为三个主要角色,Flash designer (设计师,负责界面),Flash Programmer (客户端程序员,负责Flash remoting 客户端编程), 服务端程序员(可以采用各种技术)。
c) 开发客户端程序
客户端的Flash 程序也不是很麻烦。建立如下 client.fla Flash 程序。
如上图所示,一共六个文本框,两个按钮
我分别将命名规则列出
最上面的一个文字框是用户填写输入值的,在该文字框的 var 变量名命名为 sendText
旁边的按钮是一个 Movieclip , Instance name : SetButton(点击可将 sendText 的值传给服务端的 JAVA Bean)
下面的大文字框是用于返回服务器信息的,在该文字框的 var 变量名命名为 responseText
它旁边的按钮是一个Movieclip , Instance name : GetButton(点击可将服务段信息反馈到该文字框)
最下面两个文字框分别设置:网关路径和类对象路径
GATEWAY PATH 对应的文字框的变量名是 gatewayPath
OBJECT PATH 对应的文字框的便两名是 objectPath
我在这里给它们都设置了默认的名字
分别是: localhost:8101/flashservices/gateway 和 com.eiffelqiu.remoting.TestBean
这分别是我刚刚建立的 Jrun server 的 flash gateway 地址和 刚才建立的 JavaBean 的全路径名(Flash remoting 中叫做服务名),你可能会注意到我这里给的端口号是 8101 ,这就是刚刚我们建立的新Jrun服务的端口号
大家仔细观察上图,会发现我放置了一个 Action 层,用于写代码。不过打开这个层的脚本代码,你会发现我只防止了一条语句
#include "client.as"
提示: 为什么我这样做呢,很多 Flash 程序这样做。 探究其主要原因:是防止有人反向工程Flash 得到源文件。 一些人可以通过一些反编译器从 SWF文件获得 FLA 源文件。所以有很多Flash Developer 将自己的代码放置在外面,这样在部署的时候,可以将一些网页程序,比如 JSP 放置在 WEB-INF 目录中,这样用户通过网址无法直接访问这些地址,而只有程序可以访问到它们,从而达到防止反向工程的目录。这种事情见仁见智,仅仅供大家参考。
现在让我们刚刚建立的 Flash 文件的目录下面建立一个 client.as 文件
文件如下:
#include "NetServices.as"
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ::: Button Action Script
SetButton.label = "Set value";
SetButton.clickHandler = function()
{
NetServices.setDefaultGatewayURL(_root.gatewayPath);
serviceConnection = NetServices.createGatewayConnection();
serviceObject = serviceConnection.getService(_root.objectPath, this);
serviceObject.setTestvalue(_root.sendText);
}
GetButton.label = "Get value";
GetButton.clickHandler = function()
{
NetServices.setDefaultGatewayURL(_root.gatewayPath);
serviceConnection = NetServices.createGatewayConnection();
serviceObject = serviceConnection.getService(_root.objectPath, _root);
serviceObject.getTestvalue();
}
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ::: Define data handler
getTestvalue_Result = function(result) {
// Output message header
_root.responseText = "服务器响应: " + result;
//trace("result:"+result);
}
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
代码非常简单,给两个按钮设置标签名,并建立处理函数,Flash remoting 的写法比较固定,首先是设置默认网关地址,就是我们在 gatewayPath 文字框中设置的值 localhost:8101/flashservices/gateway ,然后调用 NetServices.createGatewayConnection() 建立和服务器端 flash gateway 的连接。用NetServices.createGatewayConnection()调用服务,就是我们建立的那个Java bean ,它的地址我们通过文字框变量 objectPath 传递。然后调用 getTestvalue
NetServices.setDefaultGatewayURL(_root.gatewayPath);
serviceConnection = NetServices.createGatewayConnection();
serviceObject = serviceConnection.getService(_root.objectPath, _root);
serviceObject.getTestvalue();
Flash remoting 编程中有个默认响应函数的命名规则,比如如果你调用的函数的名字是getTestvalue,那么你的响应函数的可以直接设置 getTestvalue_Result ,这样就不用自己设置一个反馈对象,在其中设置响应函数了。
现在我们先启动我们的 Flashremoting 服务器
打开 JRun Launcher,如果你刚才已经打开了,点击 “refresh”按钮 ,你会看到自己刚刚建立的 flashremoting 出现在 Jrun server 列表中。选中它,点击 “Start” 按钮
运行 FLash 程序,在第一个文字框中输入 “你好 Flash remoting” ,点击 Setvalue 按钮,然后再点击 Getvalue 按钮
你会看到大文字框中出现来自服务端的相应:
“服务器响应: 你好 Flash remoting”
这就是一个比较完整的 Flash remoting 的例子,你可能会觉得这个例子太简单,Flash Remoting 可以做出更复杂的程序,它并不对服务器端采用的技术有任何限制,而是简化了Flash 和服务端技术之间传递数据,上面的例子只是对传统 Flash remoting 技术的一点介绍,新的 Flash remoting for Flash mx 2004 acionscript 2.0 增添了更多的东西,很多写法也发生了变化,我会在以后的文章中做出介绍的。