tutorials > 裏所有文章列表

Flash Remoting 教學 1 – 下載、安裝與hello world

In tutorials   August 1, 2005 - 12:38 am

◆flash remoting是什麼?

Flash remoting是一種連接flash client 與 server端的技術,它的功用就像是 web service, xml, loadVars一般,可以在兩者之間交換資料,達到動態置換內容的目地。

Flash remoting特別的地方在於它採用macromedia獨家的AMF(Action Message Format),這是一種 binary format的資料型態,透過 AMF over HTTP的方式將flash端資料編碼後傳回server,server端的remoting adaptor接收到資料後則會解碼回正確的native物件,交給正確的程式處理。

AMF除了用於Flash remoting外,也廣泛的用於 Local Connection 與 Flash communication server,它最大的特色在於可直接將flash native object,例如Object, Array, Date, XML,傳回server端,並且在server端自動進行轉譯成適當的物件,例如flash 的Array傳回PHP時就會自動轉換為 Associative Array;這個特色對開發者最大的好處在於不需要再人工處理serialization 與 deserialization的繁複工作,不但精確度更高,同時開發也更省時間。

由於AMF是binary format並且編碼時經過高度壓縮,因此非常適合用來傳遞大量的資料,根據flashorb網站的測試(主要針對web service與flash remoting),當資料量越大時,flash remoting的傳輸效能就越高,遠遠超過web service的表現,因此同樣的道理也可得知xml, loadVars, loadVariables 等使用plaine text format的傳輸方式自然也無可比擬。

至於在server端,目前macromedia官方支援的平台有三種,分別是 Java Coldfusion(但實際上Coldfusion應該只算是java的subset,它是一種 scripting tag library)與.NET,但由於AMF格式已被玩家反組譯成功,因此很快的就在Open Source圈出現各種「民間版」的remoting替代方案,其中比較有名的是:

-AMFPHP: 這是php版的remoting
-OPENAMF: java版的remoting
-Flap: Perl 與Python版的remoting
-FlashORB: 商業版的remoting替代方案,目前支援java與.net

相關閱讀:
十個採用remoting的理由:

◆amfphp是平麼?

本文主要介紹的是php平台上的remoting方案,也就是amfphp。

Amfphp最早是由Justin Watkins所發起並負責撰寫第一版大部份的程式碼,經過三年發展後去年由Patrick Mineault接手,不但改良了大部份的程式碼,同時也補齊了許多重要的功能,例如本系列第二篇要介紹的 pageable recordset。

Amfphp是一個完全由php寫成的server端模組,最大的特色在於完全不用安裝,任何hosting 主機只要能跑php就能執行flash remoting,再加上php原本就有廣大的使用者基礎,因此一推出後很快就獲得玩家們的接受。

如果你想要瞭解amfphp的最新方展,可前往 amfphp wiki 一探究竟,如果你有使用上的疑問,最好的解答就在amfphp mailing list 或是 forum

◆下載amfphp

目前amfphp最新版為 v1.0 milestone 2,據patrick的說這應該是正式發表前最後一個beta版,所以穩定性應該相當不錯才是。

下載位址

◆安裝amfphp

檔案抓回來後解壓縮,應該會得到下圖的結構:

其中flashservices就是amfphp的核心模組,只要將它上傳到網頁的根目錄下即可。本文是以windows + apache 2為例,因此放置位為:

C:\Program Files\Apache Group\Apache2\htdocs\flashservices

其中 htdocs即是apache預設的網頁根目錄,如果你的位置不同請適當修改。
放好 flashservices後基本核心就已完成,但這不代表就可以開始使用,我們還要為每個專案建立專屬的資料夾來放置其它必備的檔案。

◆第一個程式:hello world

這裏我們用一個實際的hello world範例來示範如何讓flash 與 php透過amfphp進行溝通。

首先我們在剛才的網頁根目錄下(htdocs)建一個專案資料夾,名稱為 hello,完整路徑為:
C:\Program Files\Apache Group\Apache2\htdocs\hello

然後請下載本文的範例檔案zip檔,將裏面的東西全部解壓縮到hello資料夾內,此時資料夾的內容應該如下圖:

◆ Amfphp gateway的設定

接者我們就仔細看看裏面有些什麼東西,首先我們來看 gateway.php,程式碼如下:

PHP:
  1. <?php
  2.         include "../flashservices/app/Gateway.php";
  3.         $gateway = new Gateway();
  4.         $gateway->setLooseMode(true);
  5.     $gateway->setCharsetHandler("iconv", "UTF-8", "UTF-8");
  6.     $gateway->setWebServiceHandler('php5');
  7.         $gateway->setBaseClassPath("services/");
  8.         $gateway->service();
  9. ?>

這裏新手最常錯的地方就是第一行,include的設定。一般由於 flashservices核心模組都是放置於web server的根目錄,因此每個專案的子資料夾只要用相對路徑 .. 就可以存取到。但如果你的flashservices路徑不一樣,這裏就要做適當的修改,例如在我使用的hosting主機上(使用linux系統),這個路徑就可能變成:

/home/userrname/website.url/user/apache/htdoc/flashservices

總之這裏請小心確認路徑無誤。

接者第5行的設定也很重要,這裏主要是在設定php該用何種語系處理資料,它的標準格式如下:

setCharsetHandler(string mode, string phpCharset, string sqlCharset)

第一個參數是設定要使用何種方式來重新編碼傳輸的資料,如果是php5的話則可以放使用iconv,這是內建的模組。

第二個參數是設定系統預定的文字編碼方式,如果要用中文的話就改成 utf-8。

第三個參數是設定該如何處理sql query result,也就是recordset的文字編碼,同樣的要用中文請設定成 utf-8。

本來這裏還有第四個參數,是設定 wsCharset (web service charset),但從ms1版本開始這個參數已被預設為utf-8,將來不論是使用SoapClient或 nusoap都會自動讀取 phpCharset的設定為預設值。

所以總之照範例裏的設定直接套用就一定不會錯 :P

最後看一下第7行,這裏是設定server端的程式位置,一般也就是business logic的所在地,或是business delegate的class位置(如果你希望將server端的logic儘量隱藏起來只透過單一管道供flash呼叫的話,這裏就是下手的好地方),預設值是server,這也就是為何解壓縮範例檔後會出現一個同名資料夾的原因。

◆php class的內容

接者我們看一下service資料夾內的Hello.php,這個就是server端的程式,它的地位相當於coldfusion 裏的component(CFC)或java裏的java bean。

它的程式碼如下:

PHP:
  1. <?
  2. class Hello
  3. {
  4.     //constructor
  5.     function Hello()
  6.     {
  7.         $this->methodTable = array(
  8.             "sayHello" => array(
  9.                 "description" => "Return hello message to client",
  10.                 "access"      => "remote",
  11.                 "arguments"   => array("")
  12.             ),
  13.         );
  14.     }
  15.  
  16.     //remote method
  17.     function sayHello($msg)
  18.     {
  19.         return "Amfphp welcomes you: " . $msg . " current time_" . time();
  20.  
  21.     }
  22. }
  23. ?>

如果你有撰寫php class的經驗,應該馬上會發現這個Hello 就是一個標準的php class檔,透過class keyword來宣告class的啟始,並且在constructor裏有一個method table描述整個class要供外界操作的method。

注意這個method table裏還有許多關鍵字可用,在未來的教學文章裏會依序介紹。這裏我們只用到description, access, arguments三樣。其中access一定要設定成remote,這個method才能為外界所存取,不然就會出現錯誤訊息。

第17行開始我們寫了一個sayHello($msg) ,它會接收遠端傳來的一個參數$msg,然後我們將這個$msg加料後再傳回去。加料的部份是19行最後的time(),我們將目前server的時間傳回flash。

◆flash端程式

接者我們看一下flash端的程式。首先請注意我在timeline的第1格用include的方式將程式碼加進去,這樣我就不用在flash 裏可憐的寫程式碼,而可以用 eclipse或primailscirpt等超強無敵編輯器快樂的寫作;所以你要找程式碼的話,直接打開code.as這個檔案即可。

Code.as的內容:

Actionscript:
  1. /*
  2. @author: jeremy@richtechmedia.com
  3. @website: http://ria.richtechmedia.com
  4. released under CC 2.5.
  5. */
  6.  
  7. //remoting related classes
  8. import mx.remoting.Service;
  9. import mx.remoting.PendingCall;
  10. import mx.remoting.RecordSet;
  11. import mx.remoting.debug.NetDebug;
  12. import mx.rpc.RelayResponder;
  13. import mx.rpc.ResultEvent;
  14. import mx.rpc.FaultEvent;
  15.  
  16. //start debugging so we can see debug info in NCD.
  17. NetDebug.initialize();
  18.  
  19. //gateway settings
  20. var gateway:String = "http://localhost/hello/gateway.php";
  21. respGeneral = new RelayResponder(this, "resultReceived", "resultFailure");
  22. _service = new Service(gateway, null, "Hello", null, respGeneral);
  23.  
  24. //callback when result was returned from server
  25. function resultReceived(re:ResultEvent):Void{
  26.     trace("message from server> " + re.result);
  27.     //php returns time in seconds, but flash Date class needs ms hence * 1000
  28.     var tmp = re.result.split("_")[1]*1000;
  29.     trace("server time> " + new Date(tmp));
  30. };
  31.  
  32. //send message to server
  33. btnSend.clickHandler = function(){
  34.     var pc:PendingCall = _service.sayHello(inputText.text);
  35. }

一開始我們先將flash remoting需要的class都import進來,這裏要注意的是,flash remoting需要另外下載與安裝,下載的方式有兩種:

1、 下載flash remoting components (v2)並裝入flash
2、 下載flash remoting sources並解壓縮到 mx目錄下。

第一種方式比較簡單,只要安裝mxp即可將remoting元件裝入flash,日後使用時只要直接拖放這個元件到畫面上即可。第二種方式則是直接取回remoting classes並放入flash預設的mx路徑中,這樣做的好處有很多,例如可以三不五時修改一些地方以符合自已的需求,或是將來想用FAME開發時,也可以讓MTASC正確的編譯。

這裏我假設你已經裝好flash remoting 元件的版本,在components裏也可以看到 flash remoting connector這個元件。

第17行我們啟動NetDebug這個偵錯程式,它會將所有的傳輸交易訊息都顯示在NetConnection Debugger(開啟方式 Window > Other Panel > NetConnection Debugger) 裏,方便除錯,它是工程師的好朋友,實在不能一天沒有它…

第20行開始我們設定了將來連線的路徑,注意裏面的hello就是當初我們在htdocs裏建的hello資料夾,而gateway.php就是前一節所介紹的php檔案。

第21行我們設定了一個general responder,也就是一個catch-all的回應物件,只要server端有回傳訊息,就由這裏設定的兩支function去承接與處理。當然remoting處理回傳訊息的方式還有很多種,這裏因為是hello world級的範例就先按下不表。

第22行我們建立了一個 _service object,這是模擬遠端class的一個物件,請特別注意第三個參數 Hello,它是指 C:\Program Files\Apache Group\Apache2\htdocs\hello\services\Hello.php 也就是前一節介紹過的php class。

經過這三行的設定,我們就完成flash內的連線設定,接下來就可以開始呼叫遠端的method囉!

我們先跳到第33行,這裏我們設定了一個按鈕,當按下時它會執行
var pc:PendingCall = _service.sayHello(inputText.text);
也就是透過先前建立的 _serive物件去呼叫server端的sayHello method, 並且將文字框內輸入的內容傳回去。

這邊另外要注意的是PendingCall的使用,由於我們可能同時對server發生多個request,但遠端連線回應的速度通常不是即時的,因此需要PendingCall來個別指定每個request的callback function,將來一堆訊息傳回時才能正確的處理。

最後我們回到第25行,這個function就是負責接收並處理server回傳資料的地方。首先我們在第26行將server傳回的訊息直接trace出來,注意這裏要使用 re.result才能存取到正確的訊息,這是常見的錯誤之一。
接者第28、29行則是將php傳回的date string轉換回flash的Date格式,由於php是以 string的方式處理時間格式,因此這裏我們得辛苦點自已將它再轉回Date object。

到這裏程式碼就告一個段落,我們來執行看看吧!

這是程式執行的畫面,我們輸入一些文字後按下send.

這是flash將輸入文字傳回php的畫面,請注意參數部份正是我們輸入的文字

這是php回傳訊息的畫面,訊息的尾端已加上系統的時間

◆ending

這個例子中我們很簡單的跑了一遍flash + amfphp + php 的執行範例,從flash傳一個文字串回php,並從php傳一個date物件回來。

在真實案例中面對的情況往往會比這個複雜許多,例如至少會跟database互動撈資料互傳,或是進行authentication的認証等,但這些都是後話,在之後的範例中都會解釋。

本文的範例檔案下載

ps.如果你遇到任何執行上的問題歡迎隨時發問,但請提供必要的背景資料給我,例如使用的作業系統、web server, php版本, amfphp版本以及錯誤訊息、代號或程式碼行數,這樣我能更快瞭解你的問題所在也才能提供正確的答案。

comments(41) | by admin

Flash Remoting 教學 2 – Pageable RecordSet

In tutorials   July 31, 2005 - 4:23 pm

◆ 前言

資料分頁(pageable recordset)一直是網頁應用程式中非常重要的一項技巧,通常工程師不會將大量的資料一次傳回給client,而是將資料先預存在server端,等client需要時再送過去。

在flash remoting 中也同樣提供了這種功能,但以往只有使用Macromedia版的remoting adapter才能正確發揮功能,也就是說如果不是 coldfusion, jrun, remoting for .net之類的正牌產品,這部份功能要不就是不完整,要不就是完全爛掉。

Amfphp 是php版的flash remoting, open source並完全免費。過去amfphp在pageable recordset上的表現可說是非常糟糕,大部份人從來都無法真正實作成功;但隨者patrick加入amfphp開發團隊後,最近amfphp的表現可說是突飛猛進,快速逼進商業產品的水準。

目前最新版的amfphp是 pre-v1.0 milestone 2 (MS2),也就是v1.0正式發表前的最後一個beta,在這個版本裏終於開始有非常完整的pageable recordset功能。

有鑑於MS2 版中的pageable recordset實作手法有大改變,而目前網路上所有的教學文件都尚未更新,因此本文將以實際的例子介紹如何使用amfphp 的pageable recordset,並詳細解釋它的運作原理與 flash 端 RecordSet 配合的方式。

◆下載與安裝

請參考第一篇教學。

◆pageable recordset運作原理

在正式開始前我們先花點時間瞭解一下到底pageable recordset是怎麼個運作法。

首先,pageable recordset的用途在於,如果你在server端有100筆資料,通常不會全部傳回client端,而是以分頁的方式,例如每頁20筆資料共分五頁,然後當user按「下一頁」時才依序傳回需要的資料。

一般來說要做到pageable recordset有兩種方式:

1、 先在server端將100筆資料 query出來,放在session中備用,然後傳回需要的部份。

2、只先query出總資料量為100筆,然後用類似 mysql limit的語法一次撈20筆出來回傳。

第1種做法好處是可以減少與database連線的次數,並且資料存放於記憶體中理論上存取速度會非常快,但缺點則是session會吃掉大量資源,如果許多user同時連線並個自保有自已的session data,那 app server往往會撐不住而當掉。

第2種做法的好處則是不會消耗大量server資源,它在有需要時才去跟db撈出資料,但缺點也就是要頻繁的與db連線,此時良好的db connection management (pooling)就很重要。

以afmphp來說,它採取的是第2種方式,當 flash client一連線時,它會先query出資料的總筆數並回傳給flash, 之後就由flash內的RecordSet class來負責決定分頁方式與每次的取回資料量。

因此從這個描述中,大家可以感覺到整個pageable recordset的運作原理是需要下面兩者交互配合才能達成。

1、amfphp的分頁query功能
2、flash RecordSet 的分頁取回功能

有了基本認識後,接下來我們就開始實作吧。

◆flash 製作

首先我們製作好flash client 端的檔案,這個程式很簡單,只要拉一個 DataGrid與button元件到畫面上即可。

程式碼的部份如下:

Actionscript:
  1. //remoting related
  2. import mx.remoting.Service;
  3. import mx.remoting.PendingCall;
  4. import mx.remoting.RecordSet;
  5. import mx.remoting.debug.NetDebug;
  6. import mx.rpc.RelayResponder;
  7. import mx.rpc.ResultEvent;
  8. import mx.rpc.FaultEvent;
  9. import mx.events.*;
  10. //start debugging so we can see debug info in NCD.
  11. NetDebug.initialize();
  12. //setting gateway
  13. var gateway:String = "http://localhost/pageableRecordSet/gateway.php";
  14. respGeneral = new RelayResponder(this, "contactReceived", "contactFailure");
  15. _service = new Service(gateway, null, "PRecordSet", null, respGeneral);
  16. //
  17. var pc:PendingCall = _service.getFullList(["Name", "Region", "Code"]);
  18. //
  19. dg.columnNames = ["Code", "Name", "Continent"];
  20. //
  21. function contactReceived(re:ResultEvent):Void{
  22.     var tmp:RecordSet = RecordSet(re.result);
  23.     tmp.setDeliveryMode("page", 10, 2);
  24.     dg.dataProvider = tmp;
  25. };
  26. //
  27. btnRefresh.clickHandler = function(){
  28.     dg.removeAll();
  29.     var pc:PendingCall = _service.getFullList(["Name", "Region", "Code"]);
  30. }

◆php端製作

這個例子中我們是使用 windows + apache 2 + php 5.04 + mysql 4.1 + amfphp ms2,但基本上在其它平台或程式版本也應該沒問題(注意amfphp至少要是ms1以上才行)

首先我們在apache的web folder (/htdoc)下建一個專案資料夾:
C:\Program Files\Apache Group\Apache2\htdocs\pageableRecordSet

然後在pageableRecordSet下建一個 service 資料夾
C:\Program Files\Apache Group\Apache2\htdocs\pageableRecordSet\services

在這個新建的資料夾內,建立一個新的php程式,名稱為 PrecordSet.php
它的程式碼如下:

PHP:
  1. <?
  2. class PRecordSet
  3. {
  4.     var $dbhost = "localhost";
  5.     var $dbname = "test";
  6.     var $dbuser = "root";
  7.     var $dbpass = "";
  8.  
  9.     function PRecordSet()
  10.     {
  11.         $this->conn = mysql_pconnect($this->dbhost, $this->dbuser, $this->dbpass);
  12.         mysql_select_db( $this->dbname );
  13.  
  14.         $this->tablename = "country";
  15.  
  16.         $this->methodTable = array(
  17.             "getColumnNames" => array(
  18.                 "description" => "Return column names from table",
  19.                 "access"      => "remote",
  20.                 "arguments"   => array("")
  21.             ),
  22.             "getFullList" => array(
  23.                 "description" => "Return a full list of table records, pass as argument an array of columns to be returned",
  24.                 "access"      => "remote",
  25.                 "arguments"   => array("arrayOfColumns"),
  26.                 "pagesize"    => "10",
  27.             ),
  28.         );
  29.  
  30.     }
  31.  
  32.  
  33.     function getColumnNames()
  34.     {
  35.         $query = mysql_query(sprintf('SHOW COLUMNS FROM %s', $this->tablename));
  36.         return $query;
  37.  
  38.     }
  39.     /*
  40.     前面有幾個參數都沒關係,但
  41.     最後兩個參數最重要:$offset, $limit 會被amfphp自動呼叫
  42.     因此,整個sql語法也要用sprintf來寫。
  43.     */
  44.     function getFullList($ar_col, $cursor, $limit)
  45.     {
  46.         //count it first
  47.         $this->countQuery = "SELECT COUNT(*) AS recordCount FROM country";
  48.         //
  49.         return mysql_query(sprintf("select * FROM %s ORDER BY Name ASC Limit %d, %d", $this->tablename,$cursor,$limit));
  50.     }
  51.     /*
  52.     所有需要 分頁 的function, 都要加上這個 _count,讓amfphp自動去呼叫
  53.    
  54.     */
  55.     function getFullList_count(){
  56.         $q = mysql_query($this->countQuery);
  57.         $row = mysql_fetch_assoc($q);
  58.         return $row['recordCount'];
  59.     }
  60. }
  61. ?>

上面的程式碼中,比較重要的幾點如下:
-amfphp端都是以class的型式存在,因此等於是在寫一個 php class。但一開頭的method table 非常重要,裏面有許多關鍵字可設定這個class的運作行為。

-第26行的pagesize => 10 是告訴amfphp 我希望每頁只傳回10筆資料;這是最關鍵的一行設定,但還需其它地方配合。

-第44行開始的getFullList($ar_col, $cursor, $limit)就是要曝露給client端呼叫的remote method, 名稱為 getFullList,裏面有三個參數。前面的$ar_col 是我們要取回的欄位名稱,實際上這裏要放多少個參數都沒關係,視實際需要而定;比較重要的是最後兩個$cursor與 $limit 參數,這兩個參數是amfphp日後進行分頁取回時會自動填入資料的地方,也就是下面query中limit的兩個關鍵字。

其中$cursor 是指目前所在位置,例如第10筆資料,而$limit則是將下來要取回的資料量,例如假設你設定一次要取回2頁,每頁10筆資料,那麼 $limit就會是 20,而整個function call就會是 getFullList(“some columns”, 10, 20),我們在下面的應用中會再解釋一下這部份。

這裏你只要記住:不管前面有幾個參數(例如$ar_col, 最後兩個一定要是 $cursor, $limit)

-第47行也是必備的項目,從query字串中就可以看出它的功能是在 count()全部的資料量,好在第一次連線時回傳給flash端做為日後分頁計算的基礎。

-第49行的query則是最重要的地方,請注意最兩點。

首先是sprintf的使用,這是一個很傳統的function,主要功能是將 %s, %d這樣的變數動態替換成後面的參數。

第二點則是 limit 的使用,在mysql中limit最常被用來進行分頁處理,它的第一個參數是啟始點(例如要從第10筆資料開始),第二個參數是資料量,例如(20筆),因此透過limit我們就可以從第10筆開始取回20筆資料。

-第55行的getFullList_count()則是amfphp新增的實作手法,這個function基本上就是將前面的getFullList加上 _count,而它主要的功能是用來計算query結果的資料量,這點從56-58行的程式碼中就可看出。它利用前面 COUNT(*) AS recordCount 將計算結果存在 recordCount這個欄位中,然後用$row = mysql_fetch_assoc($q) 與 $row['recordCount'] 來取得計算後的總量。

這支程式是amfphp 內部運作時會自動呼叫的,因此一定要有,但它的名稱不一定要是 functionName_count()這樣,可以在method table內增加一個 countMethod => “my_count”來指定要使用的名稱。

◆實際執行

在實際執行前你需要先放點東西到mysql裏才行,請下載本教學的範例檔案,裏面有個 db.sql 檔,它會在mysql內建的test database內新增一個 country table,這就是我們要用的測試資料。

接者請確定你的web server, php, mysql都正常運作,並且也正確安裝了 amfphp ms2,然後 project folder 名稱正確,service folder裏也有剛寫好的 PrecordSet.php。

最後記得打開 NetConnection Debugger 簡稱NCD (Window > Other Panel > NetConnection Debugger)以方便觀察flash與php間的資料傳輸情況。

當一切就續後就可以執行flash 的 ctrl-enter,此時在NCD中會看到下面的畫面:

這張畫面中顯示當flash第一次與amfphp連線執行 getFullList()後,amfphp傳回了一堆資料,其中最重要的就是:

mTotalCount: 57 這行告訴flash你要求的資料總共有57筆。
mRecordsAvailable: 0 目前我還沒傳回任可一筆資料。

當這些資訊回傳給flash 後,接下來就是flash RecordSet的責任去決定該如何取回這57筆資料,請注意我們在flash裏面寫的程式:

Actionscript:
  1. function contactReceived(re:ResultEvent):Void{
  2.     var tmp:RecordSet = RecordSet(re.result);
  3.     tmp.setDeliveryMode("page", 10, 2);
  4.     dg.dataProvider = tmp;
  5. };

這個contactReceived就是當初設定的 remoting callback, 當amfphp傳回資料時,就是由它去負責接收並做後續處理。在這個function裏我們設定了 setDeliveryMode("page", 10, 2), 這是 RecordSet內建的一個指令,透過這句話我們決定接下來的取回方式是”page”,每次10筆資料,並且預先取回2頁。

然後我們使用 dg.dataProvider = tmp,也就是將recordset餵給 datagrid的dataProivder,就可以順利顯示出來。

而這樣設定後最神奇的地方在於,當user捲動到下一頁時,recordset會知道資料還在server,因此自動跑去跟amfphp要求下面兩頁的資料,請看下圖。

請注意圖中,flash自動去呼叫amfphp中的PageAbleResult.getRecords()這支指令,並且傳回三個參數,第一個參數是session id,這個不重要先不管它,第二個參數則是目前 cursor 所在位置,第3個參數則是flash希望先取回30筆資料備用。

但為什麼是30筆呢?當初我們明明設定是先取回2頁啊!原因是”page”模式下,ReocrdSet永遠會自動取回目前所需的頁面,並且pre-fetch 使用者指定的頁面,因此目前cursor在1,它必需先取回自已所在的第1頁,然後預抓回2頁,也就是總共3頁共30筆資料,這就是 1, 30的由來。

之後RecordSet就會視user的捲動情況而決定何時該向amfphp要求更多的頁面,你可以試試捲動datagrid,此時會發現NCD裏出現一狗票的連線與取回記錄,如下圖

注意裏面有新增了幾個 call指令,這就是RecordSet 在進行自動取回,另外也特別注意倒數第二行的release(),當server 端的所有資料都取回後,ReocrdSet 會透過這指令告訴amfphp可以丟棄存放於server端的分頁記錄順便清空記憶體,等於是某種形式的garbage collection。

透過以上的例子,大家應該可以瞭解amfphp的pageable recodset運作原理,理論上來說只要支援dataProvider與 RecordSet 的元件都會自動支援這個分頁功能,例如combobox, listbox, datagrid 等,但tree就不行,因為它只吃xml data,除非你能替RecordSet 加上即時rs2xml的功能。

◆資料取回模式釋疑

RecordSet在取回資料時共有三種模式,分別解釋如下:

-onDemand: 這是預設的模式,也就是一次取回一筆資料,只有當需要時才連線向amfphp提出請求。好處是每次取回的資料量少,反應速度快,缺點則是會頻繁的app server連線,如果網路速度不快反而會因為lag造成使用上的不變。

-page: 以「頁」為單位取回資料,這是最常見的應用方式,它還可搭配另外兩個參數,分別是pagesize(每頁的資料筆數)與numPrefetchPages(預先取回的頁數),以我們的例子來說,setDeliveryMode(“page”, 10, 2)就是設定取回模式為page, 一頁10筆資料,預先取回2頁。

-fetachAll:這個模式會將所有資料一次取回,但可透過pagesize這個參數來預做分頁,預設值是每頁25筆資料。

一般如果會用到分頁功能,通常不二的選擇就是”page” mode,並且視需要決定每頁的筆數與預先取回量。

◆pageable recordset使用注意事項

amfphp的 pageable recordset 設計與使用上不像coldfusion 那樣方便,但那是因為許多背景因素造成,以open source project來講,能有這樣的表現已經是非常令人讚賞,只要你知道日常操作中該避開的陷井就一切ok。

-amfphp無法處理極大量的page,據各討論list上得到的結論,五千筆是一個上限。

-amfphp使用limit 語法,這是mysql獨有的指令,在mssql上可用select top n 的方式達成,但這牽涉到改寫amfphp的程式。

-php端的 functionName()中要記得加上 $cursor, $limit 兩個參數,這是供amfphp內部分頁使用,少了它們分頁就玩完了。

-php端一定要有 functionName_count()這個指令,也就是每個需要分頁的method都要伴隨者一支count method,才能計算正確的資料量回傳給recordset。

-php端的 method table要有 pagesize => “10”這樣的分頁設定,這是amfphp在第一次回傳資料時要參考的數字,如果這裏沒設定,amfphp就會認定你沒有分頁的需求而將全部資料一次都丟回client端了(這也是目前amfphp example 所犯的錯誤,可能是作者忙者改程式碼還沒空修正這個範例)

◆檔案下載

這個教學的範例檔案可按此下戴。程式碼中已加上大量註解,因此應該很容易理解。

如有任何疑問歡迎隨時提出。

comments(14) | by admin

Flash Remoting 教學 – 前言

In tutorials   July 31, 2005 - 4:04 pm

最近在重新整理RIA的教材,把過去一年新完成的教學範例整理成教材型式並加上註解,同時也針對RIA中最重要的連線方式 flash remoting重新撰寫一系列的講義。

這系列的入門教學將包括下列主題:

1、 Flash remoting(AMFPHP) 介紹、安裝與hello world範例
2、 AMFPHP Pageable Recordset 應用
3、 AMFPHP web serivces應用
4、 AMFPHP Authentication & Authorization

目前已完成第1, 2, 4項,隨者病情急速好轉,照目前寫作速度判斷,預估再兩小時應該就會全部寫完 :-)

note:有朋友來信問到,google上已經可查到一票的remoting教學範例,幹麻浪費時間再寫一次?答案很簡單,一來這是做為下半年度RIA班學生的講義,二來是amfphp 1.0 在實作上許多地方都已經改掉,目前網路上大部份教學與範例都還是針對 0.53 or 0.91版,因此許多範例都已經不能執行了。

所有教學皆內含範例檔案與程式註解,歡迎下載使用,但請注意版權,如轉戴請遵守Creative Common s 2.5的規範。

Add comment | by admin

Next Posts

mobile phone