使用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的數據庫中取出數據來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章