使用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.rar47.75 KB