關(guān)于基于JavaSript的RIA客戶端數(shù)據(jù)處理(下)
一、引子
上一篇討論了關(guān)于客戶端數(shù)據(jù)處理的一些問題,以簡單的用例場景的方式描述了出來。很明顯,要想實現(xiàn)一個功能完整的Rich客戶端的話,必須能夠滿足上述用例場景的需求。能否根據(jù)這些需求做出合理的設(shè)計,是一個挑戰(zhàn)。尤其對于設(shè)計而言,不同的人有著不同的風格,而且由于背景不同,也會有不同的見解。本文中,我只是陳述出自己的一些想法和設(shè)想,更多的是希望能夠拋磚引玉,通過在這個方面的討論也能增進我的理解。呵呵。很顯然,blog的形式更適合作為思路的介紹以及探討的平臺,而不是詳細設(shè)計的文檔。而且很明顯這一篇文章是承載不了所有的詳細設(shè)計的。我爭取把我在各個細化的方面的想法在后續(xù)的文章里面發(fā)出來。如果時間允許的話,整理出初始的文檔和代碼,建立一個小的開源項目未嘗不可(因為如此,所有的JS都是采用英文來注釋──其實還有一個原因是練習英文 :))。這都是后話了。
二、縮略語
-
RIA:Rich Internet Application的縮寫。RIA是擁有傳統(tǒng)本地應(yīng)用的功能和效果的Web應(yīng)用。RIA一般把UI相關(guān)的處理交給了Web客戶端,但是大量的數(shù)據(jù)(包括應(yīng)用的狀態(tài)、數(shù)據(jù)等)還是交給服務(wù)端處理
-
Ajax:又寫為AJAX,是"Asynchronous JavaScript and XML"的縮寫。是一種使用瀏覽器技術(shù)進行RIA開發(fā)的技術(shù)
- Prototype:開源的優(yōu)雅的Ajax以及JavaScript基礎(chǔ)擴展框架。由于被Rails采用而聞名,使用相當廣泛
- jQuery:功能類似Prototype + script.aculo.us的開源Ajax框架。據(jù)我所知,Google用得比較多
- Ext:對YUI的一個擴展的UI構(gòu)件庫。經(jīng)過改進后,可以使用jQuery或者Prototype作為基礎(chǔ)。目前好像正在完善自身的基礎(chǔ)Ext base。以優(yōu)秀的構(gòu)件聞名。雖然目前仍然屬于商業(yè)構(gòu)件庫,但是License相對寬松,一般的商業(yè)應(yīng)用可以免費使用
-
dojo:由dojo foundation管理的一個開源JavaScript框架。提供了很好的JavaScript擴展,目前被IBM和Sun等大公司支持和使用
-
Json: JavaScript Object Notation的縮寫。它是一種純文本的數(shù)據(jù)對象傳輸協(xié)議,在Ajax的應(yīng)用中被廣泛采用
-
CRUD:Create(創(chuàng)建)、Retrieve(獲取)、Update(更新)和Delete(刪除)這四種簡單的數(shù)據(jù)操作的縮寫
-
Form:本文中的Form指的是經(jīng)過Ajax擴展的簡單的HTML電子表單。表單內(nèi)部可以擁有很多如ComboBox、TextBox等構(gòu)件。一般來說,一個表單對應(yīng)著一個業(yè)務(wù)的數(shù)據(jù)對象
-
Tree:樹形顯示結(jié)構(gòu)化數(shù)據(jù)的構(gòu)件,由于數(shù)據(jù)是高度結(jié)構(gòu)化的,往往可以采用懶加載等技術(shù)來提高性能
-
Grid:以表格形式顯示和編輯數(shù)據(jù)的UI構(gòu)件。一般分為表頭(標題欄)、表身(數(shù)據(jù)列表)和表尾(合計、狀態(tài)顯示等)三個部分。其中,表頭可以是復(fù)合的表頭,而表身可以是復(fù)合的格式(Tree、Grid、ComboBox、CheckBox等)。一個Grid可以有一個復(fù)雜的Grid定義
-
Enhanced Grid:下面簡稱為EGrid,是Grid的擴展。在Grid的功能基礎(chǔ)之上提供了數(shù)據(jù)獲取和數(shù)據(jù)持久化的能力,可以大大的減少開發(fā)應(yīng)用的時間(Ext中的Grid可以認為是一個簡化了的EGrid)
-
CodeList:代碼表,一般用在下拉列表數(shù)據(jù)處,在系統(tǒng)的實現(xiàn)中,由于性能以及標準的要求,下拉列表一般都是采用代碼保存數(shù)據(jù),但是用戶在填寫表單的時候需要看到正常的文字而不是代碼,這就需要系統(tǒng)通過CodeList進行文字和代碼的轉(zhuǎn)換
-
LRU:Least Recent Used的縮寫,是一種簡單的緩存策略,如果緩存已滿,那么就釋放最近最少使用的那個緩存數(shù)據(jù)
-
REST:是REpresentational State Transfer的縮寫,是一種基于輕量級WebService協(xié)議
- JDBC:是Java DataBase Connectivity對縮寫,是基于Java的數(shù)據(jù)庫連接規(guī)范。
三、基礎(chǔ)
既然決定采用Ajax,就最好采用一個基礎(chǔ),在這個有很多優(yōu)秀的Ajax框架可供選擇的時代,誰要是還要赤手空拳的來寫Ajax應(yīng)用,就未免有點兒過于勇敢,而近于魯莽了。這篇文章不是Ajax框架對比文章,我不打算在這里一一列舉各個流行的Ajax框架的優(yōu)缺點,我只拿下面幾個進行討論,dojo、Prototype、jQuery、Ext。先提需求,框架應(yīng)該:
- 以一種形式支持面向?qū)ο螅ó吘归_發(fā)人員多數(shù)都是Java程序員,更有可能的是,他/她只對Java熟悉)
- 以一種方式來支持命名空間和分包機制(開發(fā)企業(yè)應(yīng)用與開發(fā)網(wǎng)站不同,復(fù)雜的不是技術(shù)而是業(yè)務(wù)。沒有命名空間和分包支持,對于大型應(yīng)用,基本不可控制。──設(shè)想一下如果Java沒有package關(guān)鍵字會怎樣)
- 有完善的模塊封裝與管理規(guī)范或者最佳實踐,能夠自動處理模塊間的依賴則更好(模塊的定義不在這里解釋了,一個例子說明吧,一個Jar就是一個模塊。模塊化和構(gòu)件化是實現(xiàn)、維護和管理大型應(yīng)用的重要手段)
- 提供豐富的調(diào)優(yōu)選項,使得對復(fù)雜的應(yīng)用調(diào)優(yōu)是可能的(這一點對于UI層尤為重要,因為它直接面對使用者)
- 便于調(diào)試(這一點對于開發(fā)者致關(guān)重要)
綜合上面幾點,我選擇dojo作為基礎(chǔ)。Sorry Prototype。
四、整體構(gòu)架
整體構(gòu)架如下圖所示(為了便于理解UI構(gòu)件與其對關(guān)系,我把需要數(shù)據(jù)處理的UI構(gòu)件也加了上去,圖中藍背景色的部分就是):
五、DataSet
DataSet的概念很簡單,就是數(shù)據(jù)對象的集合。它的構(gòu)架如下圖所示(注意:DataSet只是一套標準的API,可以有不同的實現(xiàn)——比如XML形式的):如圖所示,DataSet由四個部分構(gòu)成,Record Set(數(shù)據(jù)集合)、Change Tracker(數(shù)據(jù)變更追蹤)、Meta Data(數(shù)據(jù)對象源信息)和Cursors(游標API)。
分別介紹如下:
- Record Set:Record Set就是Record的集合,一個Record就是一個數(shù)據(jù)對象,它由一系列的屬性(Property)構(gòu)成,屬性是一個簡單的字符串,其對應(yīng)的值可以是任意類型。Record提供屬性讀寫的方法,可以直接在Record上對屬性進行讀寫,并且,Record會為寫操作提供一個事件。Record Set內(nèi)部的元素必須是Record,Record Set支持對內(nèi)部Record的CRUD操作。并且會有相應(yīng)的事件觸發(fā)
- Change Tracker:ChangeTracker為DataSet提供所有寫操作的追蹤,可以通過配置選擇Change Tracker是否記錄修改,如果記錄修改,采用的是針對每一個Record記錄增加、刪除以及針對每一個屬性記錄First和Last修改的策略
- Meta Data:提供DataSet中Record的元數(shù)據(jù)(屬性名、屬性對應(yīng)類型、其他自定義數(shù)據(jù)——校驗、Form Label信息、表頭信息等)以及DataSet的元數(shù)據(jù)(在全部數(shù)據(jù)中的位置等)。
- Cursors:Cursor其實就是Record的迭代器,可以通過對dataset查詢(一般都是非常簡單的filter或者range)得到,推薦通過Cursor進行Record訪問,而不是通過Index,因為通過迭代器訪問Record,DataSet擁有更多的能力。雖然通過Cursor完全可以訪問所有的Record及其中的數(shù)據(jù),但是由于DataSet擁有MetaData,所以還是采用DataSet作為數(shù)據(jù)綁定的主體
DataSet是整個客戶端數(shù)據(jù)處理構(gòu)架的核心,所有的數(shù)據(jù)訪問都應(yīng)該通過DataSet的API。這樣客戶端的數(shù)據(jù)處理才是統(tǒng)一的一個整體。
解決的用例問題:
- 數(shù)據(jù)綁定:Form綁定、Grid綁定
- 數(shù)據(jù)變更追蹤:Grid變更提示、數(shù)據(jù)集合變更追蹤、Form修改的追蹤
- 數(shù)據(jù)訪問:數(shù)據(jù)對象元數(shù)據(jù)信息訪問、數(shù)據(jù)寫操作的統(tǒng)一事件定義、統(tǒng)一的數(shù)據(jù)讀取方式
六、DataSource
DataSource的功能是提供對數(shù)據(jù)進行查詢以及數(shù)據(jù)的持久化(持久化到客戶端或者服務(wù)器端)。與DataSet一樣,不同的格式數(shù)據(jù)就會有不同的DataSource,一種DataSource代表了一種客戶端與服務(wù)端的數(shù)據(jù)傳輸協(xié)議。但是由于DataSource的邏輯與結(jié)構(gòu)過于復(fù)雜(事實上,DataSet的實現(xiàn)也完全依賴DataSource的實現(xiàn),可以類比JDBC),不應(yīng)該對每一種格式都重新實現(xiàn)一個DataSource,由此,DataSource不應(yīng)該是一套標準的API,而是使用了Adapter模式,來滿足不同的數(shù)據(jù)來源,其構(gòu)架如下圖所示:如圖所示,DataSource由Cache、Query、Persist以及Providers構(gòu)成,分別介紹如下:
- Cache:Cache的概念在前面已經(jīng)闡述了,不在這里多說了。在這里簡單的介紹一下客戶端Cache的策略以及技術(shù),由于基于瀏覽器的數(shù)據(jù)緩存技術(shù)非常重要,擬在后續(xù)的文檔《客戶端的緩存策略與相關(guān)技術(shù)》中對其進行詳細討論
- 緩存策略(這一方面客戶端數(shù)據(jù)的緩存與服務(wù)端的數(shù)據(jù)緩存考慮的問題應(yīng)該是類似的,唯一的區(qū)別是,客戶端的數(shù)據(jù)緩存不必考慮集群支持。:))
- LRU:基礎(chǔ)的Cache算法,如果緩存已滿時,根據(jù)最近很少使用算法來確定哪些對象需要被清除
- Priority:按照優(yōu)先級高低來清理緩存空間的策略,當緩存已滿時,按照優(yōu)先級高低來確定哪些對象需要被清除,可以與LRU算法共存
- Refreshable:有時效性的數(shù)據(jù),或者在運行時有可能會被修改需要同步或者刷新的數(shù)據(jù)。可以設(shè)置數(shù)據(jù)過期時間,到時間則數(shù)據(jù)處于stale狀態(tài),再度訪問該數(shù)據(jù)時,如果不能重新獲得該數(shù)據(jù),則報錯
- Expireable:臨時性數(shù)據(jù),可以設(shè)置失效時間,到時間則數(shù)據(jù)失效,在緩存需要清理時,緩存會清理掉這些失效的對象
- 緩存持久化(屬于高級的緩存策略,依賴客戶端基于JavaScript的數(shù)據(jù)存儲技術(shù))
- Save(持久化):把緩存當中的數(shù)據(jù)持久化到本地或者服務(wù)端,其用處如下
- 通過把數(shù)據(jù)持久化可以增加Cache的容量
- 數(shù)據(jù)本地緩存提供了離線表單填寫的能力
- Retrieve、Delete:對緩存中數(shù)據(jù)的基本操作
- Sync:離線緩存的本地數(shù)據(jù),可以與遠程服務(wù)端進行同步,從而實現(xiàn)離線表單提交以及實現(xiàn)離線CodeList等功能
- 緩存技術(shù)
- Client
- 內(nèi)存引用
- Cookie
- Google Gear
- Server(服務(wù)端協(xié)助客戶端做一些緩存,這在傳統(tǒng)的B/S下是匪夷所思的設(shè)計,在RIA的情況下卻未嘗不是一種手段)
- WebService或者REST
- Post + Get
- Query:其實Query只是一個方法,由于有可能會向服務(wù)端發(fā)XmlHttpRequest,所以這個方法需要回調(diào)方法。其參數(shù)應(yīng)該是一個Query對象,一個配置對象,有一些事件的關(guān)鍵字(onBegin、onError、onSuccess等)。Query對象以及配置對象的格式在本文中就不詳細說明了,留給以后慢慢說(因為這個部分是我最喜歡的部分)。很明顯,如果查詢成功,查詢的結(jié)果應(yīng)該是DataSet,一般來說,DataSource是DataSet來源。不同的DataSource,查詢的語言未必相同。不一定所有的查詢對象都支持SQL語法(比如可以支持HQL或者XQuery啊),而且我最推薦采用的是服務(wù)端提供一個服務(wù)抽象層,接受Json格式的查詢請求,并返回Json格式的數(shù)據(jù)
- Persist:數(shù)據(jù)持久化。只是Save和Update兩個方法。接受DataSet和配置對象作為參數(shù)(這兩個方法也應(yīng)該是異步的)。如果DataSet里面沒有足夠的元數(shù)據(jù)信息,需要在配置對象里面提供這些信息。這個部分不比Query部分復(fù)雜
- Providers:數(shù)據(jù)的來源,提供了Query和Persist API的實現(xiàn),是DataSource的底層實現(xiàn),它使DataSource的實現(xiàn)可以跨不同協(xié)議而使用。給DataSource提供不同的Provider,DataSource就可以支持不同的數(shù)據(jù)傳輸協(xié)議。
DataSource是數(shù)據(jù)查詢和持久化的核心,所有的客戶端的數(shù)據(jù)查詢和持久化基本都應(yīng)該采用DataSource,從而獲得DataSource提供的強大而靈活的特性。
解決的用例問題:
- 數(shù)據(jù)緩存:離線運行的CodeList、離線表單填寫、性能考慮
- 數(shù)據(jù)查詢:樣本查詢、模糊查詢、Range查詢、邏輯查詢、自定義查詢
- 數(shù)據(jù)處理:數(shù)據(jù)處理事件、過濾、排序
七、DataStore
DataStore基于DataSource和DataSet的實現(xiàn),實現(xiàn)了dojo的data api。這樣既實現(xiàn)了對需要dojo api的dojo構(gòu)件的支持,又滿足了類似Tree、EGrid這種既需要綁定又需要數(shù)據(jù)來源的高級構(gòu)件的要求。總體來說,DataStore只是薄薄的一層接口,實際的實現(xiàn)完全依賴于DataSource。解決的用例問題:
- 數(shù)據(jù)綁定、查詢、處理:Tree綁定、ComboBox數(shù)據(jù)源、EGrid綁定
八、待討論的問題
客戶端的數(shù)據(jù)處理事實上要比我想象得還要復(fù)雜,我還有一些設(shè)計決策沒有確定,列舉下來以供討論吧。8.1 客戶端的事務(wù)處理?
由于很多數(shù)據(jù)處理都放在了客戶端。客戶端的數(shù)據(jù)處理操作相應(yīng)增多而且復(fù)雜,是否應(yīng)該在DataSource中添加寫事務(wù)的處理?以便對數(shù)據(jù)操作進行更細粒度的管理,而不是僅僅停留在Query、Save和Track階段?8.2 權(quán)限數(shù)據(jù)的來源
如果可以連接到服務(wù)端,用戶在向服務(wù)端登錄后,服務(wù)端會返回用戶的權(quán)限信息列表。客戶端接收后,可以相應(yīng)的提供權(quán)限控制。但是,如果客戶端離線運行,用戶無法向服務(wù)的登錄,權(quán)限信息列表無從獲得,怎么提供權(quán)限控制?探討方案1:離線客戶端無須登錄,由于沒有權(quán)限控制列表,默認擁有系統(tǒng)最低權(quán)限(固定的配置在客戶端),由系統(tǒng)開發(fā)人員決定用戶在離線時可以進行何種操作。用戶在線提交數(shù)據(jù)的時候,服務(wù)端也要根據(jù)相應(yīng)的權(quán)限進行驗證以防止越權(quán)的數(shù)據(jù)操作
探討方案2:離線客戶端仍須登錄,權(quán)限控制列表使用用戶在線登錄時緩存的數(shù)據(jù)。其余與在線方式相同。如果用戶沒有在線登錄過,那么離線應(yīng)用無法使用。
8.3 跨域數(shù)據(jù)的來源
由于瀏覽器的安全性策略,JavaScript無法向除本身域之外的其他服務(wù)器發(fā)送請求。也就是說,對于JavaScript而言,所有的數(shù)據(jù)必須來源于同一個域的服務(wù)器。對客戶端進行集成非常不利。探討方案1:服務(wù)端提供一個服務(wù)接入層,接受如Spring Bean、EJB、JMS、WebService等形式的服務(wù),并且把所有的服務(wù)都轉(zhuǎn)化成為一種固定格式的協(xié)議與客戶端交互。所有的服務(wù)集成與協(xié)議轉(zhuǎn)化都交給服務(wù)端,對客戶端完全透明。
探討方案2:服務(wù)端提供一個簡單的Proxy,通過一定的協(xié)議把請求和回復(fù)轉(zhuǎn)發(fā)給客戶端,處理交給客戶端來做
九、小結(jié)
雖然到了這里,但是對于基于JavaScript的RIA客戶端數(shù)據(jù)處理的討論卻才剛剛開始,還需要很多后續(xù)的展開討論。但是,上午已經(jīng)過去了,需要去吃午飯了。:)posted on 2007-12-15 13:15 guitarpoet 閱讀(1440) 評論(2) 編輯 收藏 所屬分類: 展現(xiàn)層