无论是传统的 Web 应用程序还是 RIA 很多时候需要和服务器连接。当我们用 Flash 进行典型的三层开发时,Flash 播放器取代了传统层客户端浏览器。所谓 Flash 与服务器端的通信,就是指 Flash 如何跟逻辑层的服务器端编程语言交换数据。
概述
我们可以把整个服务器端的程序当成一个黑盒子,不用去了解它怎样连接数据库,又如何存取数据表的内容。但是我们必须知道它如何处理结果显示在 Flash 客户端。
不论你采用那种技术来开发服务器端程序,都应该遵守以下原则:
- 接受资料的客户端是 Flash,不是浏览器,因此动态网页中不要有 HTML 标签。
- 所有传给服务器端的数据,必须使用“名称-值”配对的格式或 XML 格式(下次再讲)
- Flash MX 及更高版本输入/输出的数据的编码格式是 UTF-8(Unicode),所以输入 Flash 的数据必须经过 UTF-8 编码才能正确显示中文。一般将代码存成 UTF-8 格式就可以了, 也可以在 Flash 中指定 System 对象的 useCodepage 属性为 true 来编码。
什么是“名称-值”配对?大家应该记得 Flash 读取的外部文件变量的格式吧。格式是:变量 1=变量值&变量 2=变量值
。如 name = "jim"&age = "28"
,其中 name 和 age 都是变量,jim 与 28 分别为它们对应的值。多个变量用 &连接起来,类似于 URL 中查询字符串的格式。
注意:不管是“名称-值”的格式还是 XML 格式,值都是以字符串形式传递到 Flash 中。
只要遵循上述格式,就可以用任何一种后台语言输出适合 Flash 读取的动态数据。常见的有:
- ASP 与 ASP.net 输出数据的格式:<%Response.Write("变量 1=变量值&变量 2=变量值")%>
- PHP 输出数据的格式:<?php echo("变量 1=变量值&变量 2=变量值") ?>
- JSP 输出数据的格式:<% out.print("变量 1=变量值&变量 2=变量值"); %>
- ColdFusion 输出数据的格式:
变量 1=变量值&变量 2=变量值
Flash 与后台连接方法很多,比如说使用 loadVariables 函数、LoadVars 对象、XML 对象、XML Socket 对象、Flash Remoting 和 Webservice。
其中 loadVariables 函数 Flash Player 4 就开始支持了,它只能接收字符串变量,没有属性方法,加之也没有事件处理函数,因此逐渐被遗弃了。 我们这里也就不再过多讨论它了,直接从 LoadVars 对象开始。
使用 LoadVars 实现 Flash 与服务器通信
从 Flash Player 6 开始,可以使用 LoadVars 对象来实现 Flash 与后台通信。同 loadVariables 函数一样,它只能接收 MIME 格式的字符串变量。而且遇 到特殊字符时,必须进行 URL 编码。
LoadVars 对象通过其 sendAndLoad
方法将对象中的属性变量发送(send)到指定的 URL,同时载入(load)服务端器的输出变量并将其放入 目标对象中。当然,发送和载入这两个过程可以分开进行。这就是 LoadVars 对象比 loadVariables 函数强大之处,另外一个强大之处在于:载入变量时,还可以通过 LoadVars 对象的 onLoad
事件来判断载入的结果是成功还是失败。请看下面的例子。
请在舞台上添加名为 name_ti
的 TextInput 实例,名为 msg_ta
、result_ta
的 TextArea 实例和名为 send_btn
的 Button 实例。将下面的 ActionScript 添加到时间轴的第 1 帧:
1. 客户端
var submitListener:Object = new Object();
submitListener.click = function(evt:Object) {
var result_lv:LoadVars = new LoadVars();
var send_lv:LoadVars = new LoadVars();
send_lv.userName = name_ti.text;
send_lv.msg = msg_ta.text;
send_lv.sendAndLoad("http://localhost/service/echo.asp", result_lv, "POST");
result_lv.onLoad = function(success:Boolean) {
if (success) {
result_ta.text = result_lv.resultVar;
} else {
result_ta.text = "连接到服务器失败";
}
}
}
send_btn.addEventListener("click", submitListener);
说明:当用户单击下面示例中 Login
按钮实例时,将创建两个 LoadVars 对象:send_lv
和 result_lv
。send_lv
对象从 name_ti
和 msg_ta
实例复制名称并将数据发送到 echo.asp
。此脚本的结果将载入 result_lv
对象,服务器响应则显示在 TextArea 实例 (result_ta
) 中。
2. 服务器端
前面说过,任何服务器端编程语言,只要按[变量/值]配对的格式输出纯文本文件就能和 Flash 连接。接下来我们就来看这个实例的服务器端代码。
- ASP 版:
<%@LANGUAGE="VBscript" CODEPAGE="65001"%>
<%Dim userName,msguser
Name=Request.Form("userName")
msg=Request.Form("msg")
Response.Write "resultVar="&userName&"说:"&msg
%>
- ASP.NET 版:
<%@ Page Language="C#"%>
<%
string userName,msg;
userName = Request.Form["userName"].ToString();
msg = Request.Form["msg"].ToString();
Response.Write("resultVar="+userName+"说:"+msg);
%>
- PHP 版:
<?php
$userName=$_POST["userName"];
$msg=$_POST["msg"];
echo "resultVar=".$userName."说:".$msg
?>
- CFM 版:
<cfparam name="userName" default="" type="any">
<cfparam name="msg" default="" type="any">
<cfoutput>resultVar=#userName#说:#msg#</cfoutput>
- JSP 版:
<%@ page language="java" pageEncoding="UTF-8"%>
<%String userName = request.getParameter("userName");
String msg = request.getParameter("msg");
out.print("resultVar="+userName+"说:"+msg);
%>
你可能也注意到了,几乎没有改动 Flash 的代码,只是改动后台语言而已。可以看出用 Flash 作表示层的程序是具有很强的移植性的,这也是 RIA 的一大特点。下次我们将谈一谈怎样使用 XML 对象来实现 Flash 与服务器端的通信,敬请关注!
点击此处下载源代码。
使用 XML 实现 Flash 与服务器通信
从 Flash Player 5 开始,就可以使用 XML 对象来实现 Flash 与后台通信。Flash 浏览器与 XML 数据之间的直接进行数据交换,并且同 LoadVars 函数一样,都是以字符串形式传递的。后台语言作为 XML 数据和数据库的中介,负责将数据库的数据动态生成 XML,将 XML 变动的数据更新回数据库。如下图所示:
XML 对象可比 LoadVars 对象高级多了,它处理的是 XML 元素,XML 元素本身有意义而且格式良好,利用我们和电脑识别, 它早已成为数据交换格式的标准。而 LoadVars 用来处理变量,LoadVars 中的变量很少有什么实际意义,如果用来读取数据库中的数据,变量会 很多。而 XML 对象就简单多了,与 XML 相关的技术很多,比如 DOM、SOM、SMLT、SAX2 等。即使你对这些技术不了解,你也可以用后台语言输出数据的方式来实现。
使用 XML 对象来实现 Flash 与后台通信,主要是通过 XML 对象的 sendAndLoad 方法。该方法和 LoadVars 的 sendAndLoad 方法 类似,它把指定的 XML 对象编码为 XML 文档,使用 POST 方法将其发送到指定的 URL,下载服务器的响应,并将其加载到参数中指定的 resultXMLobject 中。服务器响应加载的方式与 XML.load 方法使用的方式相同。
下面是一个简单的 ASP+ XML + Flash 查询实例。XML.sendAndLoad 方法传输一个包含学生姓名的 XML 包,并使用 onLoad 方法来处理来自服务器的响应。
1. 客户端
import mx.controls.Alert;
// 新建用来响应的 XML 对象
var response_xml = new XML();
// 响应时忽略 XML 空白
response_xml.ignoreWhite = true;
function showResult() {
// 清除所有项目
student_dg.removeAll();
response_xml.onLoad = function() {
var nodes = this.firstChild.childNodes;
var len = nodes.length;
if (len < 1) {
Alert.show('没有搜索到相应的记录!', '提示信息');
} else {
// 将 XML 对象解析成项目对象
for (var i = 0; i < len; i++) {
student_dg.addItem({
学号 : nodes[i].attributes.id,
姓名 : nodes[i].attributes.name,
班级 : nodes[i].attributes.cname
});
}
}
}
}
// 新建用来发送请求的 XML 对象
var request_xml = new XML();
// 创建一个新的 元素 search
element = request_xml.createElement('student');
function click() {
// 将输入的学生姓名赋值给 search 元素 name 属性
element.attributes.name = name_ti.text;
// 将 search 元素追加到 对象中
request_xml.appendChild(element);
// 传输一个包含学生姓名的 XML 包
request_xml.sendAndLoad('http://localhost/student/search.asp', response_xml);
showResult();
}
search_btn.addEventListener('click', this);
2. 服务器端
后台以 ASP 为例,ASP 要能读取 SWF 文件请求的 XML 元素,得用 XML DOMDocument,这就要求服务器必须安装有 MSXML2.DOMDocument 组件。至于 ASP 怎样输出动态 XML 文件,可以用 ASP 的 Response.Write 方法,当然同样也可以用 XML DOMDocument 对象来实现。不过,理论上前者的速度会快些。
- ASP 版:
<%@LANGUAGE="JAVASCRIPT" CODEPAGE="65001"%>
<%
// 建立 XML DOM 对象
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async =false;
var requestXml=Request.Form();
// 判断是否接收到 SWF 文件传过来的 XML 包
if(requestXml.Count >0){
// 加载 XML 包
doc.loadXML(requestXml);
// 取得根元素
var rootNode = doc.documentElement;
// 取得根元素的 name 属性值
var name = rootNode.attributes[0].nodeValue;
// 设定为 XML 文件
Response.ContentType="text/xml";
// 输出 XML 文件声明
Response.Write('<?xml version="1.0" encoding="UTF-8"?>');
var conn = new ActiveXObject("ADODB.CONNECTION");
strconn = "DBQ="+Server.MapPath("Exam.mdb")+";Driver={Microsoft Access Driver (*.mdb)};";
conn.Open(strconn);
var rs = new ActiveXObject("ADODB.RECORDSET");
var sql = "Select StudentID,Name,ClassName FROM Student Where Name LIKE &'"+name+"%&'";
rs.Open(sql,conn,1,1);
var i=0;
// 输出根标记
Response.Write("<item>");
while(!rs.EOF){
// 输出子元素及其属性
Response.Write("<student id=\""+rs("StudentID")+"\" name=\""+
rs("Name")+"\" cname=\""+rs("ClassName")+"\"/>");
i++;
rs.MoveNext();
}
Response.Write("</item>");
rs.Close();
conn.Close();
}
%>
点击此处下载附件,该附件中还包含此实例的各版本后台脚本。
ASP.NET 版:
<%@ Page Language="C#" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
private void Page_Load(object sender, System.EventArgs e) {
Stream inStream = Request.InputStream;
if (inStream.Length > 0) {
XmlReader reader = XmlReader.Create(Request.InputStream);
reader.ReadToFollowing("student");
string name = reader.GetAttribute("name");
reader.Close();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(Response.Output, settings);
writer.WriteStartElement("item");
string sqlStr = "Select StudentID,Name,ClassName FROM Student" +
" Where Name LIKE '" + name + "%'";
using(OleDbConnection connection = new OleDbConnection(sqlStr, con))
{
OleDbCommand cmd = new OleDbCommand(sqlStr, con);
connection.Open();
OleDbDataReader dr = command.ExecuteReader();
while (dr.Read()) {
writer.WriteStartElement("student");
writer.WriteAttributeString("id", dr[0].ToString());
writer.WriteAttributeString("name", dr[1].ToString());
writer.WriteAttributeString("cname", dr[2].ToString());
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Close();
dr.Close();
}
}
}
</script>
因为我们只是对 XML 数据进行查询, 所以好使用 XMLReader 和 XmlWriter 类, 它们可以提供对 XML 文件快速、 非缓存、 只进读写, 所以速度比用 XmlDocument 类快得多。 而且它不需要服务器安装有 MSXML2.DOMDocument 组件, 其扩展性更强。
我租用的服务器就没有安装这个组件, 怪不得我用 ASP 作为后台在服务器运行会出错。 实际上, 大家看到的 Demo 的后台用的是 C#。
总结
注意:
- 测试 PHP 版时,由于使用了
$GLOBALS["HTTP_RAW_POST_DATA"]
全局变量,请打开php.ini
,将always_populate_raw_post_data = On
前的;
去掉;这是一种不得以的方法,如果有哪位找到好方法,请告诉我一下。 - 对于 CF 版,因为在交换数据的过程中,CF 解析 XML 时不接受汉字。因此,我们需要在 Flash 中将要传送传送的参数进行 URL 编码,请将
name_ti.text
修改为escape(name_ti.text)
。
其实,我个人并不主张用 XML 来实现 Flash 与服务器端的通信,我宁愿用 LoadVars 和 Flash Remoting。
评论 (0)