Dorado on the way - final
?
2006年12月25日
今天是圣誕節,進入公司已經四個月了,可是對公司的產品Dorado還幾乎是一個門外漢,(我要說明一下,不是我太笨,剛剛進入公司就接受了一個傳統項目的開發,再加之學校的事情,在此我想我應該聲明一點,我還是一個大四的學生,快結束大學四年的學習了,到最后,亂七八糟的事情實在是太多了,這個報告那個報告的。)
Thomas(我們公司的產品經理),還有范經理,實在是不好意思,還有公司的同事,雖然我比他們中的好多人進入公司都早,可惜我不是最厲害的,至少現在不是。
到上個星期為止,學校的事情基本上已經完了,畢業設計的課題也選了,選的課題是《基于智能Agent的分布式移動計算處理》,本來一開始自作聰明,以為題目為“移動計算”嘛,就是移動設備的計算處理,智能Agent嘛~估計就是一種形式而已,我自從從大學二年級自學Java開始,接觸了Java中的JavaSE和JavaEE兩個體系,正好可以借此課題,讓我對JavaME有所了解,也實現了完成畢業設計的作用。結果后來導師選好了以后,看著導師給的材料,我才知道,我陷入泥潭了~(導師,原諒我這么說,呵呵·)
今天是我真正學習Dorado的第一天,公司給了我一些資料,所以我信心十足,我要趕上公司的其他同事,呵呵~爭取超過他們哦~已經習慣了要做到最好,我是不是太自大了??
還是跟我學習Java一樣,首先在公司的官方網站(http://www.bstek.com/)下載了Dorado的最近版本,我下載的版本是Dorado-5.0 061129.1132,一并還下載了Dorado 5 快速入門,組件使用技巧,當然還有Dorado的API--我的最愛。
首先看了Benny(我們公司的CTO)錄制的兩段視頻說明,依照Dorado安裝自帶的doradosample,把dorado的大致功能作了一個講解說明,個人感覺dorado還是挺有市場前景的,只是需要更大的宣傳。
好了,閑話不多說了,開始我的Dorado之旅吧~
首先,需要了解的是:視圖模型Dorado開發當中非常重要的對象,它封裝了Dorado的界面邏輯和操作邏輯,即主要包含什么數據dataset ,以及這些數據通過什么形式來展現。
下面是我今天學習中,覺得需要注意的一些地方和術語。
Dataset
1. getDataset(“datasetName”) ; 獲取對dataset的引用
2. RecordIterator ri = dataset.recordIterator() ; 獲取對dataset的迭代器引用。
3. 對dataset的遍歷
while(ri.hasNext()){
Record record = ri.nextRecord() ;
// 對每條記錄的操作
}
4. 可是通過getControl(“controlName”) ; 獲取組件的引用
注意,這里得到的是Control對象,需要進行類型的強制轉換。
5. ”Module數據塢”的說明。
1). 數據塢里面的dataset對象可以被不同的視頻模型索引用,以達到數據共享的作用。
2). Module不應該包含任何的業務邏輯,這是一種良好的設計模式。
3). Module的創建和銷毀由Dorado提供的容器來管理,可以當做一個Singleton來使用。
所以在絕大部分情況下,在Module里面添加非靜態的屬性都不是正確 (或者是不太明智)的做法。
4). Module中的dataset的創建和銷毀使用dorado提供的容器來管理的,但開發人員可以強制通過scope和timeout來定制dataset的生命周期。
5). scope有三種取值,分別是request (默認),session , application。
需要特別注意的是,在同一個request中連續以不同的pageIndex ,pageSize , parameters的不同組合來獲取Module中的dataset,但將獲得多個不同的dataset 實例。
6). 如果為了提高效率而將scope設置為application ,則應該注意讓此dataset中的數據量不要過大。常用在大型系統中的代碼表。
6. 通過dataSet.getCurrent() ; 方法,可以從dataSet獲取當前記錄。由于dataSet具有
“當前記錄”這個,所以大多數操作都是對“當前數據”來說的。
Mapping
1. 所有的Mapping單元都是通過名為global的管理單元來進行管理的。
2. 在請求映射的過程中,dorado有著自己獨特的,不同于Struts的映射機制,
例如:對于請求:action=”access.login.d”
access 與對應的controller的名稱一致,
而login與對應的action的名稱一致。
3. controller的clazz屬性所表示的是用于處理這個請求的class ,類似于Struts中的 Action ,而提交的數據,就從Struts 中的ActionFrom轉換成了Dorado的dataset.
4. 對于頁面的訪問安全控制(即只能通過dorado式的請求,而不容許以文件結構路徑來訪問,即../demo/XX.jsp),可以將view中的safe屬性設置為true來控制。
或者通過dorado默認的setting中的security.accessChecher來控制。不過我可以自主創建一個AccessChecker類型的java類來進行控制。但需要將setting.xml里面的 “security.accessChecker”屬性修改為自己創建的類路徑。
5. 可以通過DoradoContext來訪問dorado的上下文信息,并通過標記量來告訴dorado 的上下文從哪里獲取需要的變量。
例如,
Object obj = doradoContext.getAttribute(DoradoContext.SESSION,”username”) ;
i18n
1. 你需要在i18n目錄下新建一些I18N的properties類型文件。此類文件與java中的
一致,都是以鍵-值對的形式存在。
2. 在dataset中的Fields里面設置為${Resource.fileName.key}的形式進行設置。這個就
有點類似于JSP2.0中的EL,其中,fileName是資源文件的文件頭,不包括_cn_ZH
等類似的字樣。而key是在文件中的鍵。這些都是在系統的setting.xml中的
“common.locale.language”和“common.locale.country ”來進行的配置。同樣,你可
以通過修改這兩個屬性來啟用不同的I18N文件。
3. 對于動態更改用戶的國際化資源的情況,可以使用
LocalHelper.getLocale(“language”,”country”),
ResourceManager.getInstance().setDefaultLocale(context,
DoradoContext.SESSION,
locale) ; 來設置。
EL
在JSP2.0方面的書籍中有大量的經典介紹,這里就不再記錄。
開發時,只需記住Dorado內置的隱式變量,即可。
Skin
1. 皮膚文件夾存放的位置是在skins文件夾下面的。
在使用新皮膚時,只需要修改setting.xml中的view.smartweb2.skin對應的值即可。
2. 同時可以通過修改skin.css文件來修改dorado中的標簽庫的所有展示風格。
3. 同時也支持傳統的JSP開發,即在<head>標簽中設置相信的各種屬性,以完成讓
dorado以用戶自定義的形式進行展現。
2007年1月1日
關于Dataset
可以通過RecordIterator 對dataset中的數據進行遍歷(包括已經在客戶端“刪除”的記錄)。
為什么在客戶端已經“刪除”的記錄,dataset仍然可以遍歷到?
原因就在于Dorado出于對性能的考慮,在客戶端做的刪除并沒有立刻更新服務器段的記錄,而僅僅是在客戶端的dataset中做了刪除的標記。在用戶提交了以后,才會對服務器端的記錄做修改。所以用戶在客戶端做的刪除操作后,如果刷新頁面,刪除的記錄將會重新出現。
可以通過如下代碼對dataset中已經標記為“刪除”的記錄進行遍歷:
RecordIterator rit = dataset.recordIterator() ; // 獲取dataset的遍歷器
rit.setVisibility(Dataset.FILTER_DELETED) ; // 設置遍歷器的可見屬性
while(rit.hasNext()){
Record record = rit.nextRecord() ; // 取得當前的Record對象
// 對記錄進行操作
}
isFirst 以及 isLast的理解
在dataset中容易犯下的錯誤就是對isFirst和isLast的誤解。
isFirst和isLast并不像大家想象當中的那樣,代表著Dataset的當前記錄(注意,所有對Dataset的操作,都是對“當前記錄”而言)是否是第一條記錄或者是最后一條記錄。他們真正的含義如下:
isFirst:
官方解釋:
isFirst表示Dataset已經在試圖繼續向前移動當前記錄的過程失敗,亦即當dataset的當前記錄從第二條記錄轉到第一條記錄時isFirst仍然是 false,只有當Dataset試圖繼續向前移動當前記錄后,isFirst才會變成 true,此時dataset的當前記錄仍然是第一條記錄。
我的理解:
對于isFirst,你可以于Java當中的Iterator作對比。我們假設Java中的 Iterator具有previous(),就是next()倒著遍歷(),那么當當前記錄從第二條作previous()成功到達第一條記錄的時候,isFirst仍然返回false,為什么?因為在移動過程中沒有受阻,它成功的前移了。下面要注意了,現在當前記錄已經在第一條了,現在如果當前記錄再試圖向前移動時,此時受阻了,因為在當前記錄前面已經沒有記錄可以移動了,此時 isFirst()返回true。
如下圖:
在dorado的設計過程中,數據導航條的數據前移和后移過程中,并不會查看當前記錄是否是第一條或者是最后一條數據,而是默認前或者后還有數據,從而繼續作向前或向后的操作,只有在移動受阻后,才修改是否到邊界的標記,這樣或許在移動操作中可能會對移動的性能有一定的幫助。
個人認為,這里把isFisrt()看作是對當前記錄的操作時候“越界”的標志更為合適。
IsLast:
官方的解釋:
isLast表示Dataset已經在試圖繼續向后移動當前記錄的工程失敗,亦即當dataset試圖繼續向前移動當前記錄后,isFirst才會變為true,此時 Dataset的當前記錄仍然是倒數第一條記錄。
我的理解:
可以對比isFirst來理解,我覺得我已經解釋的比較清楚了。
moveFirst 和 moveLast方法
當用戶調用了Dataset的moveFirst或moveLast之后,Dataset的isFirst或isLast立刻被置為true。
當dataset沒有任何可見記錄的時候,isFirst和isLast將同時為true,并且當前記錄為null。
想必在前面理解了我對isFirst和isLast的講解之后,對這兩個方法的理解應該不會出現什么偏差了。
不過我想提醒大家一下,注意我這里的用詞,是“可見記錄”,即是說,如果在客戶端刪除了所有的記錄,雖然沒有向服務器提交,但此時isFirst和isLast都會同時返回true。這里就很好的統一了對用戶的“體驗一致性”,即用戶認為已經沒有數據了。
不知道大家有沒有在瀏覽器中查看過Dorado生成的jsp文件的源代碼,其實這些源代碼都是通過html和xml界面模板信息共同展現的。
Dorado內部加載順序:第一步: 客戶端發出請求
?????????????????????????????????????????????????????????第二步:初始化 視圖模型
?????????????????????????????????????????????????????????第三步:初始化 Dataset
?????????????????????????????????????????????????????????第四步:初始化 組件
?????????????????????????????????????????????????????????第五步:完成組件與Dataset之間的綁定
?????????????????????????????????????????????????????????第六步: Dataset向外部請求數據,完成數據加載
?????????????????????????????????????????????????????????第七步:向客戶端返回HTML/XML界面模板信息
?????????????????????????????????????????????????????????第八步:完成,顯示頁面
2007年1月8日
Dataset中最重要的方法: flushData()
功能我想我不說大家也知道,就是通過不刷新頁面來實現數據更新與交換。
在設置對象的屬性于視圖模型中的字段的時候,可是使用在試圖模型中的objectClazz來幫助我們實現這個一一對應的關系。-fromDO方法
注:因為這里是根據java class中的屬性名稱一一映射的,所以如果出現屬性名稱于試圖模型中所希望的字段名稱不一致的時候,可以使用property屬性來輔助我們。
異步交互:
在dataset中設置autoLoadData為false,并且設置async為true。
MasterLink:
主從表的設置:
方法一: 修改主表的Dataset中的afterScroll事件。
方法二: 在masterLink中設置,便可以完成同樣的功能。
特點:可以緩存已經下載的數據
在中設置多個監聽器,各個監聽器之間用逗號分隔。
在監聽器中分別提供了beforeXX和afterXX方法,其中afterXX的返回值為void,beforeXX的返回值為boolean型,這樣如果在beforeXX方法中返回false,就可以實現中止標準的dataset.XX()以及監聽器本身的afterXX()方法的操作。
ViewProperties
在傳統的開發方式中,常常通過getParameter()方法來獲取頁面的參數信息。但是需要注意以下的提示:
在dorado中,可以通過兩種方式來發送request請求,一種是通過JSP頁面來發送request請求,還有一種是通過客戶端的dataset的flushData()方法來發送request請求,但需要注意的是,通過這兩種方式產生的request請求是完全不通的request對象。所以通過類似于DoradoContext.getContext().getParameter(“pageSize”)這樣的方法在第一種request請求中是正確的,可以獲得通過JSP頁面傳送的pageSize參數,但在第二種request中,通過這樣的方法所得到的就是null,需要特別的注意。
所以,在開發中常常遇到的問題就是你第一頁顯示的沒有問題,但是當你點擊下一頁的時候,就會有問題。這是因為第一頁是通過JSP頁面發送的請求,而當點擊下一頁的時候,就是通過客戶端的Dataset來發送的請求。
如果通過ViewProperties方式,就不存在這樣的問題。
具體使用如下:
DoradoContext.getContext().getAttribute(DoradoContext.VIEW,”pageSize”) ;
這個方法返回的是Object類型的返回值,你只需要做適當的強制轉型即可。
我們可以從服務器端或者客戶端來訪問、存貯ViewProperties,用“推”的形式來實現客戶端于服務器端之間的數據傳遞
服務器端:
DoradoContext.getContext().setAttribute(DoradoContext.VIEW, key, value) ;
DoradoContext.getContext().getAttribute(DoradoContext.VIEW, key) ;
客戶端:
getViewModel().properties().getValue(key) ;
getViewModel().properties().setValue(key, value) ;
同時,我們也可以通過EL表達式來方便的訪問viewProperties屬性:
${ViewProperties.XXX},
${ViewProperties.getString(“XXX”)}
數據校驗
在dataset中添加校驗器來完成
在dataset的beforeChange()方法中添加代碼。
例如可以使用如下方式:
switch(field.getName()){
case “key1” : {
// code here
}
...
}
記錄狀態
none -無狀態: 當數據下載到客戶端,此時記錄是“無狀態”的,這是 Dorado的默認狀態。
new -新增狀態:表示該記錄剛剛被添加到數據集,并且尚未得到驗證和確認。如果此時我們執行了對該記錄的撤銷,那么該記錄將被從數據集中移除。
insert -已添加狀態:表示這是一條新增的并且已經經過驗證和確認的記錄。
modify -已修改狀態:表示這是一條數據已經被修改的并且已經經過驗證和確認的記錄。
delete - 已刪除狀態:表示這是一條被標記為已刪除的記錄。默認形式下此種記錄是不可見的,我們對數據集的遍歷操作也不會得到該記錄。但是我們前面還是接受了一種方法,可以遍歷到這類記錄。
可以通過Rocord.getState()方法獲得記錄的狀態信息。
并且可以通過dataset.getOldRecord(Record r)來獲取記錄r的原始值。
組件開發
一. DataTable
分配下載功能: 設置autoLoadPage為true
在表格中,列標題常常需要漢化成為中文,我們不建議您在DataTable里直接修改,盡管這樣做也可以達到目的,我們建議您在與DataTable綁定的Dataset中的Fields中進行修改。
設置fixedColumn來設置鎖定的列數。
設置confirmCancel和confirmDelete屬性可以設置對表格進行快捷鍵的操作時,是否彈出相應的提示信息。
設置editable來設置表格是否可編輯。
通過headerHeight可以設置表格頭的高度。
ignored屬性是控制表格向客戶端輸出,一旦設置為true,在客戶端將不會有這個表格元素存在。
top和left用來設置表格在屏幕的絕對位置。
在修改事件的時候,返回值為false,表明不需要再繼續執行系統默認的執行方式,而只執行我們自定義的執行方式即可。
我們可以通過dataset.getField(“fieldName”).setReadOnly(true) 來控制具體某一個單元格的只讀屬性。
對表格可編輯狀態控制的具體總結:
行狀態:利用dataset的afterScroll動態設定dataset的readOnly屬性實現。
列狀態:利用column的readOnly屬性實現。
指定m行n列的所在單元格狀態:在dataset的afterScroll動態設定field的readOnly屬性實現。