使用ASSQL创建Flex快速原型程序
最近要做一个Flex的演示程序,Flex本身不支持直接访问数据库,只能是由服务器端来间接访问数据库,在网上找到了一个ASSQL的SWC,可以直接通过Socket访问Mysql数据库,也就是不需要Flex服务器端就可以直接访问MySQL服务器,这样的好处是可以快速开发一个演示程序的原型,缺点是不适用于安全性要求高的Flex真正的运行应用,因为它把数据库连接的密码用户名打包进了客户端的SWF文件中,安全性极差。
1.首先从http://code.google.com/p/assql/下载最新的Beta2.7的源代码,注意最新的程序跟Flex SDK不兼容,需要手工修改代码。比如我连接数据库时遇到了一个1063的错误问题,需要修改
MySqlService.as文件中的private function handleError(info:Object):void {函数声明为 private function handleError(info:Object, token:Object=null):void {
为了编译assql,注意不要使用下载的工程文件(它同最新的Flex SDK不兼容好像),我们需要创建一个新的Flex Library Project,然后将所有的as文件复制到新建的工程文件中,并在项目的Flex Build Path中添加所有的AS文件,设定好后,Flex会自动编译生成assql.swc文件。
2.接下来,创建一个使用assql的Flex应用,代码如下
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:assql="com.maclema.mysql.mxml.*"
layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import com.maclema.mysql.events.MySqlErrorEvent;
import com.maclema.util.ResultsUtil;
private function handleConnected(e:Event):void {
Alert.show("connected ");
service.send("SELECT * FROM books ");
}
private function handleError(e:MySqlErrorEvent):void {
Alert.show(e.text);
}
]]>
</mx:Script>
<assql:MySqlService id="service"
hostname="localhost"
username="root"
password="root"
database="consultant_db"
autoConnect="true"
charSet="utf8"
connect="handleConnected(event)"
sqlError="handleError(event)" />
<mx:DataGrid id="grid" left="10" right="10" top="10" bottom="10"
dataProvider="{service.lastResult}"
columns="{ResultsUtil.getDataGridColumns(service.lastResultSet)}" />
</mx:Application>
注意,要将上面编译好的assql.swc复制到Flex应用的Libs目录下,这样才能编译通过。
运行后,我们就应该可以看到DataGrid中出现想要的结果了。
3.关于assql的中文显示问题
用assql显示中文记录时会显示为乱码,在网上查了一下,assql最新的代码仍然没有很好的解决这个问题,网上相关的讨论对于最新的程序也是无效的,因为assql是基于mysql的jdbc代码改写的,我下载了ConnectorJ的源代码看了一下,改写了一个临时的解决方案,只对UTF8编码的数据库有效。
就是对所有的
writeMultiByte和readMultiByte的调用,都强制使用UTF-8的编码方式,同时修改服务器握手的字符集设定的部分。
我修改后的版本见附件。
4.关于assql的安全认证
因为assql使用了socket通讯,从客户机器上直接进行socket通讯有安全性的问题,为了保证安全性,Adobe Flash Player要求我们必须设置一个policy file 服务器提供一个安全定义文件,来允许我们针对某个端口进行socket通讯。下面就是监听843端口的Serverlet的实现,它将服务器上D:/hubdog/Flex/tomcat/webapps/samples/WEB-INF/flashpolicy.xml这个文件传给发起验证请求的Flash Player
package com.maclema.flash;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.servlet.http.HttpServlet;
import org.apache.log4j.Logger;
public class PolicyServerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static ServerSocket serverSock;
private static boolean listening = true;
private static Thread serverThread;
private static Logger logger = Logger.getLogger(PolicyServerServlet.class);
static {
try {
serverThread = new Thread(new Runnable() {
public void run() {
try {
logger.debug("PolicyServerServlet: Starting...");
serverSock = new ServerSocket(843, 50);
while (listening) {
logger.debug("PolicyServerServlet: Listening...");
final Socket sock = serverSock.accept();
Thread t = new Thread(new Runnable() {
public void run() {
try {
logger.debug("PolicyServerServlet: Handling Request...");
sock.setSoTimeout(10000);
InputStream in = sock.getInputStream();
byte[] buffer = new byte[23];
if (in.read(buffer) != -1
&& (new String(buffer))
.startsWith("<policy-file-request/>")) {
logger.debug("PolicyServerServlet: Serving Policy File...");
// get the local tomcat path, and
// the path to our flashpolicy.xml
// file
File policyFile = new File(
"D:/hubdog/Flex/tomcat/webapps/samples/WEB-INF/flashpolicy.xml");
logger.debug("policy file:"+policyFile.getAbsolutePath());
BufferedReader fin = new BufferedReader(
new FileReader(policyFile));
OutputStream out = sock
.getOutputStream();
String line;
while ((line = fin.readLine()) != null) {
out.write(line.getBytes());
}
fin.close();
out.write(0x00);
out.flush();
out.close();
} else {
logger.debug("PolicyServerServlet: Ignoring Invalid Request");
logger.debug(" "
+ (new String(buffer)));
}
} catch (Exception ex) {
logger.debug("PolicyServerServlet: Error: "
+ ex.toString());
} finally {
try {
sock.close();
} catch (Exception ex2) {
}
}
}
});
t.start();
}
} catch (Exception ex) {
logger.debug("PolicyServerServlet: Error: "
+ ex.toString());
}
}
});
serverThread.start();
} catch (Exception ex) {
logger.debug("PolicyServerServlet Error---");
ex.printStackTrace(System.out);
}
}
public void destroy() {
logger.debug("PolicyServerServlet: Shutting Down...");
if (listening) {
listening = false;
}
if (!serverSock.isClosed()) {
try {
serverSock.close();
} catch (Exception ex) {
}
}
}
}
policy文件的内容如下
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" to-ports="3306" />
</cross-domain-policy>
为了让Web Server启动时自动加载Serverlet,我们需要编辑Web.xml添加下面的定义
<servlet>
<servlet-name>PolicyServerServlet</servlet-name>
<servlet-class>com.maclema.flash.PolicyServerServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>PolicyServerServlet</servlet-name>
<url-pattern>/policyserver</url-pattern>
</servlet-mapping>
为了验证跨域的Flash请求,我们要将Flex客户端的mysqlservice 组件的定义修改一下
<assql:MySqlService id="service"
hostname="192.168.0.2"
username="asroot"
password="root"
database="assql_db"
autoConnect="true"
charSet="utf8"
connect="handleConnected(event)"
sqlError="handleError(event)" />
注意这回Hostname不是Localhost,而是一个IP地址,同时注意用户名asroot定义时,它允许的host name需要是%,否则从其他的机器登录时,会报用户访问拒绝
这回将swf复制到另外一台客户端上,它的ip地址可以是192.168.0.3,然后运行swf,你会发现它确实可以从192.168.0.2的数据库中取出数据来了。
附件 | 大小 |
---|---|
assql.rar | 47.75 KB |