|
一、在JavaScript中調用Flex方法 在Flex中可以用ExternalInterface來調用Flex的方法,途徑是通過在Flex應用可調用方法列表中添加指定的公用方法。在Flex應用中通過調用addCallback()可以把一個方法添加到此列表中。addCallback將一個ActionScript的方法注冊為一個JavaScript和VBScript可以調用的方法。 addCallback()函數的定義如下: addCallback(function_name:String, closure:Function):void function_name參數就是在Html頁面中腳本調用的方法名。closure參數是要調用的本地方法,這個參數可以是一個方法也可以是對象實例。
舉個例子: <mx:Script> ??? import flash.external.*; ??? public function myFunc():Number { ??????? return 42; ??? } ??? public function initApp():void { ??????? ExternalInterface.addCallback("myFlexFunction",myFunc); ??? } </mx:Script> 那么在Html頁面中,先獲得SWF對象的引用,也就是用<object .../>聲明的Swf的Id屬性,比如說是MyFlexApp。然后就可以用以下方式調用Flex中的方法。 <SCRIPT language='JavaScript' charset='utf-8'> ??? function callApp() { ??????? var x = MyFlexApp.myFlexFunction(); ??????? alert(x); ??? } </SCRIPT> <button onclick="callApp()">Call App</button>
二、在Flex中調用 JavaScript 你可以調用Html頁面中的JavaScript,通過與JavaScript的交互,可以改變Style,調用遠程方法。還可以將數據傳遞給Html頁面,處理后再返回給Flex,完成這樣的功能主要有兩種方法:ExternalInterface()和navigateToUrl()。 在Flex中調用JavaScript最簡單的方法是使用ExternalInterface(),可以使用此API調用任意JavaScript,傳遞參數,獲得返回值,如果調用失敗,Flex拋出一個異常。 ExternalInterface封裝了對瀏覽器支持的檢查,可以用available屬性來查看。 ExternalInterface的使用非常簡單,語法如下: flash.external.ExternalInterface.call(function_name: String[, arg1, ...]):Object; 參數function_name是要調用的JavaScript的函數名,后面的參數是JavaScript需要的參數。 舉個例子說明如何調用JavaScript函數 Flex應用中,添加如下方法: <mx:Script> <?xml version="1.0" encoding="iso-8859-1"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> ??? <mx:Script> ??????? import flash.external.*; ?? ? ??????? public function callWrapper():void { ??????????? var f:String = "changeDocumentTitle"; ??????????? var m:String = ExternalInterface.call(f,"New Title"); ??????????? trace(m); ??????? } ??? </mx:Script> ??? <mx:Button label="Change Document Title" click="callWrapper()"/> </mx:Application> Html頁面中有如下函數定義: <SCRIPT LANGUAGE="JavaScript"> ??? function changeDocumentTitle(a) { ??????? window.document.title=a; ??????? return "successful"; ??? } </SCRIPT>
一。安裝amfphp, 1. 下載ampfphp1.2版本 2. 建立一個目錄amfphp, 將包中的文件解壓到此目錄中。 3. 目錄結構舉例如下: c:\amfphp\amf-core c:\amfphp\browser c:\amfphp\services c:\amfphp\gateway.php 在Http Server中(可以是IIS,Apache Http Server)中建立一個虛擬目錄,映射c:\amfphp 4. 驗證 在瀏覽器中輸入 http://localhost/amfphp/gateway.php 會看到一個成功頁面。
二。編寫PHP端代碼 舉個例子:定義一個sample類,這個類編寫在sample.php中 其中定義一個getUsers方法 這個php文件放在amfphp\services\中。 <?php // Create new service for PHP Remoting as Class class sample { ??????? function sample () ??????? { ??????????????? // Define the methodTable for this class in the constructor ??????????????? $this->methodTable = array( ??????????????????????????????? "getUsers" => array( ??????????????????????????????? "description" => "Return a list of users", ??????????????????????????????? "access" => "remote" ??????????????????????? ) ??????????????? ); ??????? }
??????? function getUsers ($pUserName) { ??????????????? $mysql = mysql_connect(localhost, "username", "password"); ??????????????? mysql_select_db( "sample" ); ??????????????? //return a list of all the users ??????????????? $Query = "SELECT * from users"; ??????????????? $Result = mysql_query( $Query ); ??????????????? while ($row = mysql_fetch_object($Result)) { ??????????????????????? $ArrayOfUsers[] = $row; ??????????????? } ??????????????? return( $ArrayOfUsers ); ??????? } } ?> 驗證: 在瀏覽器中輸入http://localhost/amfphp/browser/index.html 會發現在左邊Frame中有一個sampe的鏈接,點擊后,在右邊Frame中可以測試此方法。
三。編寫Flex端代碼 首先寫一個RemotingConnection類,繼承自NetConnection,主要是用于統一指定編碼格式 package { ??????? import flash.net.NetConnection; ??????? import flash.net.ObjectEncoding; ?????? ? ??????? public class RemotingConnection extends NetConnection ??????? { ??????????????? public function RemotingConnection( sURL:String ) ??????????????? { ??????????????????????? objectEncoding = ObjectEncoding.AMF0; ??????????????????????? if (sURL) connect( sURL ); ??????????????? } ?????????????? ? ??????????????? public function AppendToGatewayUrl( s : String ) : void ??????????????? { ??????????????? } ??????? } } 然后在應用中可以進行如下調用: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" creationComplete="initApplication()"> ??????? <mx:DataGrid dataProvider="{dataProvider}"> ??????????????? <mx:columns> ??????????????????????????????? <mx:DataGridColumn headerText="Userid" dataField="userid"/> ??????????????????????????????? <mx:DataGridColumn headerText="User Name" dataField="username"/> ??????????????????????????????? <mx:DataGridColumn headerText="User Name" dataField="emailaddress"/> ??????????????????????? </mx:columns> ??????? </mx:DataGrid> ??????? <mx:Script> ??????????????? <![CDATA[ ??????????????????????? import mx.controls.Alert; ??????????????????????? [Bindable] ??????????????????????? public var dataProvider:Array; ?????????????????????? ? ??????????????????????? import flash.net.Responder; ? ??????????????????????? public var gateway : RemotingConnection; ?????????????????????? ? ??????????????????????? public function initApplication() : void ??????????????????????? { ??????????????????????????????? gateway = new RemotingConnection( "http://localhost/amfphp/gateway.php" ); ??????????????????????????????? gateway.call( "sample.getUsers", new Responder(onResult, onFault)); ??????????????????????? } ?????????????? ? ??????????????????????? public function onResult( result : Array ) : void ??????????????????????? { ??????????????????????????????? dataProvider = result; ??????????????????????????????? // mx.controls.Alert.show("result: " + result.toString()); ??????????????????????? } ?????????????????????? ? ?????????????????????? ? ??????????????????????? public function onFault( fault : String ) : void ??????????????????????? { ??????????????????????????????? // trace( fault ); ??????????????????????????????? mx.controls.Alert.show(fault); ??????????????????????? } ??????????????? ]]> ??????? </mx:Script> </mx:Application>
補充說明:如果調用的PHP函數需要參數,比如:getUsers($user_name) 那么可以在Flex調用端,需要相應的添加此參數: gateway.call( "sample.getUsers", new Responder(onResult, onFault), "<username>");
MacroMedia的Flex2.0 Beta3發布了。 今天想把項目從Beta2遷移到Beta3下,有一個事情需要注意一下:
<mx:Application />不再支持原有的xmlns="*"
也就是說原來的在同一目錄下的使用缺省*作為命名空間的Component在Beta3中會出錯,錯誤提示: Cann't resolve ... as a component implementation
舉個例子說明一下,比如你有一個MXML Application文件名是:main.mxml, 引用了一個名為UserComponent的組件。 <mx:Application xmlns="*"> ??? <UserComponent id="userComp"/> </mx:Application>
UserComponent.mxml文件與main.mxml放在一起。這樣的做法在Beta2中是OK的。 在Beta3中需要修改: <mx:Application xmlns:MyComp="*"> ??? <MyComp:UserComponent id="userComp"/> </mx:Application> 也就是說必須有一個缺省的NameSpace。
另外Tree中change事件 event.target.selectedNode 屬性修改為 event.target.selectedItem
不斷補充中。。。。
<mx:tree/>中,folderOpenIcon="UIComponent" 需要修改為: folderOpenIcon="mx.core.UIComponent" folderClosedIcon也一樣。(2006.5.12)
最近在搞一個把DocBook的Xml文檔轉換成Html的工作。 遇到了一些問題,把解決的心得總結一下寫在這里。
首先介紹一下DocBook的由來,DocBook是一個開源項目,其實就是一些DTD,規定了書寫文檔的一些標準。 在此標準下,就可以拋棄Word,WPS之類的工具用寫字板來寫文檔了。 文檔此Xml形式保存,需要的時候就使用Xslt通過已有的大量的各種各樣的Xsl轉換成所需要的格式,比如:RTF,PDF,HTML等等。 這種方式帶來了比較大的自由和靈活性。很多人對用這種方式寫文檔非常推崇。 DocBook網站:http://www.docbook.org, http://docbook.sf.net 講解DocBook Xsl的一個很好網站:http://www.sagehill.net/docbookxsl O'reilly出版一本DocBook的書(免費) http://www.oreilly.com/catalog/docbook/chapter/book/docbook.html DocBook百科全書: http://wiki.docbook.org/topic
遇到的一個主要問題是原來的DocBook就是想把一個Docbook文檔中的章節拆分轉換生成若干個Html. 查閱文檔后得知使用html\chunk.xsl可以實現此功能。 OK,下載Saxon,用Exe4Java生成Windwos平臺下的EXE文件后,進行轉換。
Good,果然生成了一堆Html,不過為什么Html的文件都是些ch0X.html這樣的格式? 再查閱文檔,原來這是DocBook的生成規則,第一章生成的Html就取名為ch01.html, Sect1生成s01,加上所在章節的前綴,如果在第2章,則生成文件名為ch02s01.html,以此類推。 如果想要生成自定義的文件名,就需要在DocBook中指定相應的id屬性。如: <chapter id="workflow">...</chapter>, 那么這一章就會生成workflow.html.
ok, 給DocBook文檔中所有章節加上了id屬性,指定了文件名。再生成一下。
Faint,失敗了,生成的文件名還是老樣子?為什么? 再仔細查閱文檔,原來在轉換的時候少指定了一個參數 use.id.as.filename, 只有此參數值不為0時,上述特性才生效。而缺省值是0.
OK,添加此參數, 執行如下命令:
saxon docbook.xml docbook-xsl-1.69.1\html\chunk.xsl use.id.as.file=1
如果使用xsltproc, 命令格式如下: xsltproc --stringparam use.id.as.filename 1 ..\docbook-xsl-1.69.1\html\chunk.xsl docbook.xml
Good, 成功了。
最后,推薦一本關于Xslt的好書: Manning - Xslt Quickly, 使用了大量的實例來引導讀者一步步,由淺入深逐步學會Xslt
在Flex2.0中, Validator組件的使用方式和1.5中相比, 進行了一些改變, 不再需要定義Model, 可以在Validator屬性中直接引用Form成員了. ????<mx:Form?id="loginForm"> ????????<mx:Text?text="?{AtsModelLocator.getInstance().loginFailMessage?}"?width="80%"?color="red"/> ???? ????????<mx:FormItem?label="Username:?"?required="true"> ????????????<mx:TextInput?id="username"?/> ????????</mx:FormItem>
????????<mx:FormItem?label="Password:?"?required="true"> ????????????<mx:TextInput?id="password"?/> ????????</mx:FormItem> ????</mx:Form>
????<mx:ControlBar> ????????<mx:Button?id="loginSubmit"?label="Login"?mouseUp="loginUser()"/> ????</mx:ControlBar> ???? ????<mx:StringValidator?id="userNameValidator"?source="{username}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?3.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?20."? ????????minLength="4"?maxLength="20"/>
????<mx:StringValidator?id="userPassValidator"?source="{password}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?6.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?10."? ????????minLength="4"?maxLength="20"/>
這樣就定義好了兩個Validator, 可以對用戶名和用戶密碼進行校驗. 但是怎么使用這兩個Validator呢?
我是這樣用的:
????<mx:Script> ????<![CDATA[ ????????import?mx.controls.Alert; ????????import?mx.events.ValidationResultEvent; ????????import?mx.validators.ValidationResult;?? ???????????? ???????import?com.ats.vo.LoginVO; ???????import?com.ats.control.LoginEvent; ??????? ???????import?mx.validators; ??????? ???????public?function?loginUser()?:?void ???????{ ??????????if?(?!?modelCheckValid?)?{ ??????????????modelCheckValid?=?true; ??????????????return; ??????????} ??????????? ??????????var?loginVO?:?LoginVO?=?new?LoginVO(); ??????????loginVO.username?=?username.text; ??????????loginVO.password?=?password.text; ???????????? ????????????var?event?:?LoginEvent?=?new?LoginEvent(?loginVO?); ????????????dispatchEvent(?event?); ???????} ??????? ???????private?var?modelCheckValid?:?Boolean?=?true; ????]]> ????</mx:Script>
????<mx:Form?id="loginForm"> ????????<mx:Text?text="?{AtsModelLocator.getInstance().loginFailMessage?}"?width="80%"?color="red"/> ???? ????????<mx:FormItem?label="Username:?"?required="true"> ????????????<mx:TextInput?id="username"?/> ????????</mx:FormItem>
????????<mx:FormItem?label="Password:?"?required="true"> ????????????<mx:TextInput?id="password"?/> ????????</mx:FormItem> ????</mx:Form>
????<mx:ControlBar> ????????<mx:Button?id="loginSubmit"?label="Login"?mouseUp="loginUser()"/> ????</mx:ControlBar> ???? ????<mx:StringValidator?id="userNameValidator"?source="{username}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?3.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?20."? ????????minLength="4"?maxLength="20" ????????invalid="modelCheckValid=false" ????????trigger="{loginSubmit}" ????????triggerEvent="mouseDown"/>
????<mx:StringValidator?id="userPassValidator"?source="{password}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?6.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?10."? ????????minLength="4"?maxLength="20" ????????invalid="modelCheckValid=false" ????????trigger="{loginSubmit}" ????????triggerEvent="mouseDown"/>
為什么這么復雜地在Validator中定義trigger, triggerEvent呢? 原因是這樣的: 如果不是在Validator的invalid事件中去設置modelCheckValid這個標志量. 就需要在loginUser()函數中對所有Validator進行判斷, 代碼會顯得比較臃腫復雜. 而且如果需要考慮是否需要一次性顯示出所有校驗失敗的錯誤. 代碼示例: ????<mx:Script> ????<![CDATA[ ????????import?mx.controls.Alert; ????????import?mx.events.ValidationResultEvent; ????????import?mx.validators.ValidationResult;?? ???????????? ???????import?com.ats.vo.LoginVO; ???????import?com.ats.control.LoginEvent; ??????? ???????import?mx.validators; ??????? ???????public?function?loginUser()?:?void ???????{ ??????? ??????????var?vrEvent?:?ValidateResultEvent; ?????????? ??????????var?checkFailed?:?Boolean?=?false; ?????????? ??????????vrEvent?=?userNameValidator.validate(); ??????????if?(?vrEvent.results?!=?null?&&?vrEvent.results.length?>?0?)?{ ??????????????//?驗證失敗 ??????????????checkFailed?=?true; ??????????} ?????????? ??????????vrEvent?=?userPassValidator.validate(); ??????????if?(?vrEvent.results?!=?null?&&?vrEvent.results.length?>?0?)?{ ??????????????//?驗證失敗 ??????????????checkFailed?=?true; ??????????} ?????????? ??????????if?(?checkFailed?)?return; ??????????? ??????????var?loginVO?:?LoginVO?=?new?LoginVO(); ??????????loginVO.username?=?username.text; ??????????loginVO.password?=?password.text; ???????????? ????????????var?event?:?LoginEvent?=?new?LoginEvent(?loginVO?); ????????????dispatchEvent(?event?); ???????} ??????? ????]]> ????</mx:Script>
????<mx:Form?id="loginForm"> ????????<mx:Text?text="?{AtsModelLocator.getInstance().loginFailMessage?}"?width="80%"?color="red"/> ???? ????????<mx:FormItem?label="Username:?"?required="true"> ????????????<mx:TextInput?id="username"?/> ????????</mx:FormItem>
????????<mx:FormItem?label="Password:?"?required="true"> ????????????<mx:TextInput?id="password"?/> ????????</mx:FormItem> ????</mx:Form>
????<mx:ControlBar> ????????<mx:Button?id="loginSubmit"?label="Login"?mouseUp="loginUser()"/> ????</mx:ControlBar> ???? ????<mx:StringValidator?id="userNameValidator"?source="{username}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?3.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?20."? ????????minLength="4"?maxLength="20"/>
????<mx:StringValidator?id="userPassValidator"?source="{password}"?property="text" ????????tooShortError="This?string?is?shorter?than?the?minimum?allowed?length?of?6.?"? ????????tooLongError="This?string?is?longer?than?the?maximum?allowed?length?of?10."? ????????minLength="4"?maxLength="20"/>
這種方法也是可行的. 至于具體使用哪一個, 憑自己的喜好了.
這一段時間在 Cairngorm上搭建了一個小項目, 順便小結一下開發過程: 1. 首先規劃構建View, 將一個應用的界面, 分成適當的Mxml Component 2. view中必然涉及的需要數據的綁定, 將組件需要的數據都集中到ModelLocator中. 3. 設計事件(CairngormEvent), 也就是與用戶交互的過程中以及系統運轉的過程中會需要派發哪些事件, 需要注意的一點是, Cairngorm中Flex事件也需要轉化成CairngormEvent 4. 設計事件的處理函數, 也就是命令. 在FrontControl中對事件和命令進行注冊. 5. 命令中通過代理去調用服務. 5. 設計代理類, 在代理類中調用服務 5. 設計命令中涉及的服務(最可能的是與數據庫的交互), 并添加相應的配置 6. 設計服務中需要使用的ValueObject 7. 命令中如果需要對視圖組件數據進行存取, 需要通過ViewHelper來完成, 設計相應的ViewHelper. 同時在mxml中對viewHelper進行注冊.
補充說明: 事件的產生不一定全部是與用戶交互的結果, 也就是說不全是由View產生的. 當然大部分的事件(比如用戶點擊了保存按鈕)是這樣產生的. 在命令中也可以產生命令, 典型的就是SequenceCommand, 應用中可以把一個事件的處理分成幾個步驟來完成, 完成第1個步驟后怎么通知第2個步驟開始呢, 當然還是繼續派發事件啦. 在SequenceCommand在類中, 把派發事件封裝了一下, 給出了一個executeNextCommand()可以直接調用. 不過在這里我也遇到了一個問題, 直接使用SequenceCommand的executeNextCommand()并不管用. 好象dispatchEvent并沒有效果, 我后來是自己修改了代碼, 使用Application.application.dispatchEvent才解決問題的.
Cairngorm的優點: 一. 實現了比較徹底的解耦 1. 事件機制, 對用戶的響應(比如點擊保存按鈕), 并不是直接從View中抓取數據, 然后New一個類, 調用這個類的某個方法, 將數據保存到數據庫中, 而只是簡單地派發一個事件, 具體事件由誰來響應, 如何處理對他來說是透明不可見的. 2. Locator模式, Cairngorm中service, view, model的獲取都是通過Locator的, 也就是說系統其他部分對于service, view, model只需要知道其ID就夠了, 其內部實現等待細節都是不需要知道的. 舉個例子, 傳統的方法: 你要找一個叫張三的人幫你干一件事, 你需要知道張三長什么樣, 然后在一個坐著10個人的大辦公室里找到他, 告訴他你的要求. 而現在在這個大辦公室的門口多了一個前臺小姐, 你只需要告訴這個小姐,我要找張三, 然后她會幫你去找, 你根本不需要知道張三的模樣.
RIA的優點: 由于Flex的原因, 系統處理是異步的. 比如, 你請求了一個比較耗時的數據庫讀取操作, 請求發出后, 你就可以進行其他操作了, 服務結束會產生相應事件, 然后由Command進行后續處理, 最后引發頁面數據更新.
進行了一系列的改動。最明顯的是Xml命名空間的變化. 從www.macromedia.com/2005/xml 修改為 www.adobe.com/2006/xml 其次變量、和成員的綁定變得更簡單,對于[Bindable]屬性的變量或者類成員。 可以不需要手工指定并派發事件,系統會自動進行。 Beta1代碼示意: private?var?_fieldTest:String; [Bindable("textChanged")] public?function?get?fieldTest()?:?String{?return?_fieldTest;} public?function?set?fieldTest(s?:?String)?{ ????_fieldTest?=?s; ????dispatchEvent(new?Event("textChanged")); } Beta2代碼示意: private?var?_fieldTest?:?String; [Bindable] public?function?get?fieldTest()?{?return?_fieldTest;?} public?function?set?fieldTest(s?:?String)?{ ????_fieldTest?=?s; } 有所簡化。 另外一些多余的屬性和方法被取消。 一些類、屬性、方法改變名字。
摘要: 最近做一個項目的時候,需要將數據庫從原先的SqlServer遷移到Oracle中。需要遷移的不僅是數據還需要將表結構、存儲過程、視圖、觸發器.... 所有東西都遷過去。于是在網上搜索了一下,很快找到了www.swissql.com中提供了這樣的工具。但是能下載的是30天有效。只能轉換2000行Sql文本的試用版。自己動手、豐衣足食。開始破解:1. 安裝SwisSql2. 把SwisSql的Lib目... 閱讀全文
感覺目前采用插件模式進行功能擴展的東西越來越多了. 從Eclipse開始, 確實給軟件帶來巨大的便利. 可擴展性得到了淋漓盡致的體現.
言歸正傳, 列舉一下我目前使用的FireFox的擴展: Tab Mix Plus: 擴展FireFox的標簽功能 All-in-One Gestures: 讓你使用鼠標手勢來執行一般的命令。包括搖桿導航.滾輪導航和頁面卷軸等等。
FasterFox: 給FF提速. 感覺好像是快了一些.
FlashGot: 允許 Firefox、Mozilla Suite、Netscape 和 Thunderbird 使用大多數流行的外部下載管理器處理單一的和全部("全部" 和 "選擇")下載, 現在可以拋棄FF那個看上去土土的下載器了. 如果你安裝的是迅雷的話, 他自帶一個FireFox的插件, 就不需要裝這個了. Colorful Tab: 讓每個標簽使用不同的顏色使其易于識別,可以將非活動的標簽加淡化效果, 并可以設置淡化的度. 而漂亮的界面總體上也更具魅力。好象沒有在其他地方看到過. 現在頁面感覺更加生動活潑. Image Zoom:增加圖像縮放功能。右鍵點擊一個圖像,從彈出菜單選擇一個縮放選項。或者在按下鼠標右鍵的同時轉動滾輪來縮放圖像。 Restart Firefox:重新啟動Firefox, 安裝新的擴展后, 點這個就行了.
Gmail Manager: Gmail郵件管理器. 比Gmail notifier好。
Reveal:讓你可以一次性瀏覽所有標簽頁. ScapBook:網頁收藏夾.
Adblock Plus:攔截網頁廣告 NoScript: 阻止網頁中Script代碼的運行。 Drag de Go: 既可根據拖動對象的不同也可以根據拖動方向的不同 業定制不同的動作。十分的個性化。
IE Tab: 推薦使用, 可以在FireFox中使用IE內核顯示頁面. 插件安裝后會在StatusBar(可以配置,也可以顯示在工具欄)中顯示一個小圖標, 左鍵點擊小圖標即可切換瀏覽器的內核. 非常爽! 這樣對于一些FireFox兼容不好的網站就不需要再打開一個IE瀏覽器了, 在FireFox中全部搞定.
Load Time Analyzer: 會在一個工具條上顯示網頁加載的事件和時間, 并能夠用圖形直觀的顯示出來. View Source Chart: 可以把網頁的源代碼進行格式化, 使用顏色加以區分.
Google Notebook: Google推出的網頁便簽類產品, 在瀏覽時看到發好的東西, 可以隨時記錄下來, 好處是: 一處記錄, 到處瀏覽. 因為他的記錄會保存在GMail的服務器中.
FoxyProxy: 好用的代理切換, 如果使用Tor或者代理的話, 可以方便地切換使用哪個代理. Download Embedded: 用于下載頁面內嵌的對象, 比如視頻,mp3,Flash等等.
先簡要地介紹一下Cairngorm中采用的設計模式: Cairngorm框架最大的革新是將用戶行為和系統級事件統一地映射為Cairngorm事件. 當組件接收到用戶行為或者系統事件后, 用戶請求被轉換成組件可以傳播的內部事件. RIA中處理用戶請求不需要到服務器去轉一圈. 當用戶行為指定要執行一個功能時, Cairngorm要求廣播一個合適的事件. 在設計模式中命令模式特別適合此種情形. 在這個模式中,?將實現功能的類稱之為命令(Command). 每一個而且是所有的命令提供一個單點入口, 一個execute()方法. 這樣允許第3方調用此命令, 而不需要了解命令具體是如何實現的. 通常這些命令被叫作"Worker", 因為他們承擔了在應用背后進行工作的任務.
我們現在開始根據示例來研究Cairngorm Store. 看一下Cairngorm Store關鍵功能之一: 將商品添加到購物車中. 為實現此功能, 創建一個新的命令類: AddProductToShoppingCartCommand
import?org.nevis.cairngorm.commands.Command; import?org.nevis.cairngorm.control.Event; import?org.nevis.cairngorm.samples.store.model.ModelLocator; import?org.nevis.cairngorm.samples.store.vo.ProductVO;
class?org.nevis.cairngorm.samples.store.command.AddProductToShoppingCartCommand??implements?Command?? { ????public?function?execute(?event?:?Event?):Void ????{ ????????var?product?:?ProductVO?=?ProductVO(?event.data.product?); ????????var?quantity?:?Number?=?Number(?event.data.quantity?); ????????ModelLocator.shoppingCart.addElement(?product,?quantity?); ????}???? }
這個類看起來并不復雜. 首先一個具體的類實現了Cairngorm的命令接口. 如果你查看了Cairngorm的源碼, 你會發現這個接口只是簡單地規定了命令必須實現一個方法: execute() 作為入口. 看一下execute()方法的實現, 可以發現事件是如何執行包含ProductVO值對象和數量的命令的. VO和數量是預先裝載在Event類中的. Event也是一個Caringorm定義的類, 其中包括事件的類型和事件的方法. 購物車屬于客戶端數據, 因此它存放于ModelLocator類中. 所以,命令只是添加適當數量的商品到購物車中, 使用購物車提供的方法. 這就是創建一個簡單功能命令類的所有工作. 命令查詢事件, 獲取事件相關數據. 如果執行的命令更改應用的數據,比如要求在購物車視圖中新增一個商品, 應用需要使用ModelLocater完成更改客戶端數據.
有一個非常重要的設計概念在這里強調一下. 在前面的示例中, 所有復雜的業務邏輯(比如一個購物車可以做什么,不可以做什么)都被封裝在一個類中(稱之為ShoppingCart). 比如: 一個用戶添加一個商品到購物車中, 如果購物車沒有此種商品, 則新增一個, 如果已經存在, 則將數量加1. Cairngorm并不減輕開發者創建業務對象的工作. 特別之處只是在于它實現業務域的類. 開發者應該從Cairngorm架構中抽離出來, 把業務邏輯從命令中提取出來放入類中. 一個典型的實現方法是進行抽象類的重構. 此項技術的好處在于可以進行單元測試, 書寫API文檔, 使用其他應用開發者可以進行復用. Caringorm商店中的購物車類是遵循此原則的極好的例子. 借鑒設計模式的思想, Cairngorm對客戶事件的進行響應而不是對服務器HTTP的進行響應, Cairngorm使用前臺控制(Front Controller)模式作為所有Cairngorm事件的統一入口.
class?org.nevis.cairngorm.samples.store.control.ShopController?extends?FrontController { ????public?function?ShopController() ???{ ???????initialiseCommands(); ???} ???? ????//----------------------------------------------------------------------------
????public?function?initialiseCommands() ????{ ??????addCommand(?ShopController.EVENT_GET_PRODUCTS,?new?GetProductsCommand()?); ??????addCommand(?ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART,?new?AddProductToShoppingCartCommand()?); ??????addCommand(?ShopController.EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART,?new?DeleteProductFromShoppingCartCommand()?);?? ??????addCommand(?ShopController.EVENT_FILTER_PRODUCTS,?new?FilterProductsCommand()?);????? ??????addCommand(?ShopController.EVENT_SORT_PRODUCTS,?new?SortProductsCommand()?);????? ??????addCommand(?ShopController.EVENT_VALIDATE_ORDER,?new?ValidateOrderCommand()?); ??????addCommand(?ShopController.EVENT_VALIDATE_CREDIT_CARD,?new?ValidateCreditCardCommand()?);????? ??????addCommand(?ShopController.EVENT_COMPLETE_PURCHASE,?new?CompletePurchaseCommand()?);????? ????} ???? ????//-------------------------------------------------------------------------
????public?static?var?EVENT_GET_PRODUCTS?=?"getProducts"; ????public?static?var?EVENT_ADD_PRODUCT_TO_SHOPPING_CART?=?"addProductToShoppingCart"; ????public?static?var?EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART?=?"deleteProductFromShoppingCart";?? ????public?static?var?EVENT_FILTER_PRODUCTS?=?"filterProducts"; ????public?static?var?EVENT_SORT_PRODUCTS?=?"sortProducts"; ????public?static?var?EVENT_VALIDATE_ORDER?=?"validateOrder"; ????public?static?var?EVENT_VALIDATE_CREDIT_CARD?=?"validateCreditCard"; ????public?static?var?EVENT_COMPLETE_PURCHASE?=?"completePurchase";???????????? ???????? }
構造函數調用 initialiseCommands(), 將廣播的事件委派給相應的命令去處理.
我們看一個添加商品到購物車的例子. 當應用廣播ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART命令時, 前臺控制中下面這行代碼保證AddProductToShoppingCartCommand的execute()方法被調用. addCommand( ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART, new AddProductToShoppingCartCommand() ); ShopController繼承了Cairngorm中的FrontController基類, 因此可以使用addCommand()來給事件注冊相應的命令. Cairngorm底層架構完成了剩余部分的工作. 應用中任意地方簡單地廣播適當的事件, Cairngorm確保相應的命令被觸發. 另外需要做的是在Mxml的主入口點創建控制器. 在Cairngorm商店中, 是Main.mxml, 代碼如下: <control:ShopController id="controller" /> "Control"的命名空間在應用標簽中定義, 指定如下Cairngorm包: xmlns:control="org.nevis.cairngorm.samples.store.control.*" 你只需要這樣做,就可以保證應用擁有一個前臺控制模式, 響應所有的事件, 并觸發你使用addCommand()注冊的命令.
|