前言
RIA
(
Rich Internet Applications
),這個(gè)術(shù)語已經(jīng)出現(xiàn)多年,隨著開源社區(qū)和廠商的不斷貢獻(xiàn),涌現(xiàn)出許多
RIA
產(chǎn)品,幾個(gè)重要產(chǎn)品分別是:
Adobe Flex
——
基于
Flash
、
actionscript
、
MXML
。
OpenLaszlo
——
基于
Flash
、
JavaScript
、
LZX
。
?????? Dojo?????
——
基于
JavaScript
、
DHTML
、
XML
。
?????? XUL?????
——
基于
XUL
、
JavaScript
。
除了以上產(chǎn)品外,還有大量的
Ajax
、
Applet
開源項(xiàng)目。他們的目的只有一個(gè):簡化并改善
Web
應(yīng)用程序的交互操作,使應(yīng)用程序可以提供更豐富、更具有交互性和響應(yīng)性的用戶體驗(yàn)。
本文
UI
方面,我們關(guān)注重點(diǎn)是
OpenLaszlo
。
OpenLaszlo
的前身是
LPS
(
Laszlo Presentation Server
),由
Laszlo Systems
公司在
2002
年發(fā)布,
LPS
是那個(gè)時(shí)代誕生的第一個(gè)
RIA
產(chǎn)品。根據(jù)市場和用戶的需要,
Laszlo Systems
公司于
2004
年在
CPL
協(xié)議下發(fā)布了
LPS
的開源產(chǎn)品
OpenLaszlo
。目前,代號為“
Legals
”的
OpenLaszlo
即將在明年第一季度發(fā)布,它的出現(xiàn)使
OpenLaszlo
能夠支持
Ajax
(
DHTML
)。
“
Legals
”的下一個(gè)項(xiàng)目代號為“
Osprey
”,它的目標(biāo)是支持
swf9
的運(yùn)行目標(biāo),也就是當(dāng)前
Flex 2
所采用的運(yùn)行文件版本,預(yù)計(jì)發(fā)布時(shí)間為明年的第二或者第三季度。
代號為
“
Orbit
”
的項(xiàng)目是
Sun
和
Laszlo Systems
公司共同開發(fā)的產(chǎn)品
,
目的是能讓
OpenLaszlo
程序運(yùn)行在包括
Java ME
在內(nèi)的任何
Java
平臺上
,
比如移動(dòng)電話、
PDA
、電視機(jī)頂盒、打印機(jī)
,
等等。
OpenLaszlo
優(yōu)勢在于它是開源的
(
遵循
CPL
協(xié)議
),
基于開發(fā)者熟悉的技術(shù)
(
JavaScript
、
XML
)
。在
SOLO
(
Standalone OpenLaszlo Output
)方式下可部署到任意的
HTTP Web
服務(wù)器,在非
SOLO
方式(
Proxied
方式)下可部署在裝有
OpenLaszlo Server
的
Linux
、
UNIX
、
Windows
、
Mac OS X
操作系統(tǒng)上,并支持任意的
Java Servlet
容器、
Java EE
應(yīng)用服務(wù)器。只要您的瀏覽器支持
Flash 6
或者更高版本,那么就可以體驗(yàn)
OpenLaszlo
了。
本文利用
db4o
作為數(shù)據(jù)庫,
db4o
是一個(gè)開源的純面向?qū)ο髷?shù)據(jù)庫引擎,對于
Java
與
.NET
開發(fā)者來說都是一個(gè)簡單易用的對象持久化工具。同時(shí),
db4o
已經(jīng)被眾多的企業(yè)級應(yīng)用驗(yàn)證為具有優(yōu)秀性能的面向?qū)ο髷?shù)據(jù)庫。可以通過《
開源面向?qū)ο髷?shù)據(jù)庫 db4o 之旅: 初識 db4o
》、《
開源面向?qū)ο髷?shù)據(jù)庫 db4o 之旅: db4o 查詢方式
》系列文章來了解。
OpenLaszlo
安裝
以
Windows 2000/XP
安裝為例,首先安裝
Java 1.4
或以上版本,接著下載
OpenLaszlo Server 3.3.3
,這個(gè)過程并不困難,安裝完畢會(huì)自動(dòng)進(jìn)入
OpenLaszlo
歡迎頁面,很漂亮的世界時(shí)鐘。
現(xiàn)在就可以立即體驗(yàn) OpenLaszlo 的魅力了,只要您有任何一款 XML 編輯器就行,哪怕是 Windows 自帶的記事本。轉(zhuǎn)到 OpenLaszlo 的默認(rèn)安裝目錄“C:\Program Files\OpenLaszlo Server
?? < text > Hello?World! </ text >
</ canvas >
第一個(gè)程序完成
,
在
IE
瀏覽器輸入如下
地址
,
如圖一所示。
????????????????
???????????????? 圖一
第一個(gè)
laszlo
頁面
“效果很不錯(cuò)
……
”,也許您還在欣賞自己地杰作,不過馬上感到這樣開發(fā)不太方便,好在
OpenLaszlo
為我們提供了
Eclipse
插件
IDE4Laszlo
,
IDE4Laszlo
以前是
IBM alphaWorks
項(xiàng)目,現(xiàn)在已經(jīng)開源給
Eclipse
,可在
這里
找到,目前的版本是
接下來安裝插件,在
Eclipse
的菜單欄選擇“
Select Help >> Software Updates >> Find and Install
”再選中“
Search for new features to install
”,點(diǎn)擊“
New Archived Site
”按鈕選擇剛才下載的插件
zip
文件,最后根據(jù)提示即可順利完成插件安裝。
上面的
OpenLaszlo Server
依靠
Tomcat
服務(wù)器為運(yùn)行環(huán)境,不過
OpenLaszlo
也可以運(yùn)行在例如
Jboss
、
WebLogic
、
WebSphere
等服務(wù)器中,并構(gòu)建自己的運(yùn)行環(huán)境。本應(yīng)用程序是在
OpenLaszlo
自己的運(yùn)行環(huán)境中構(gòu)建,可以在
這里
下載。
程序架構(gòu)
與傳統(tǒng) Web 應(yīng)用一樣,RIA 應(yīng)用也遵循 MVC 模式,只不過客戶端要依賴控制端和服務(wù)端提供數(shù)據(jù)來更新視圖,所以多了一個(gè)數(shù)據(jù)層。本實(shí)例為了簡化程序,使用 JSP 文件來作為控制層與數(shù)據(jù)層的橋梁,當(dāng)用戶進(jìn)行操作請求時(shí),OpenLaszlo 向 JSP 發(fā)出請求,JSP 獲得請求并分析應(yīng)該調(diào)用哪種業(yè)務(wù)操作,業(yè)務(wù)層根據(jù)所請求的方法與持久層進(jìn)行交互,將獲取的數(shù)據(jù)以 XML 字符串的形式返回,并通過 JSP 頁面?zhèn)鬟f給 OpenLaszlo 應(yīng)用。圖二展示了本實(shí)例的程序架構(gòu)與數(shù)據(jù)流轉(zhuǎn)過程。
????????????????????????????
?????????????????????????????????????????????? 圖二 OLJD架構(gòu)圖
下面在 Eclipse 建立一個(gè) Laszlo 工程以展示這個(gè)應(yīng)用的程序結(jié)構(gòu)(由于該應(yīng)用程序是基于獨(dú)立的 OpenLaszlo 運(yùn)行環(huán)境,所以未使用 IDE4Laszlo 提供的特性)。
打開 Eclipse,創(chuàng)建一個(gè)名為“openlaszloWITHdb4o”的 Web 應(yīng)用程序。接著轉(zhuǎn)入該程序的所在目錄,為了能保證該應(yīng)用程序能順利加入 RIA 特性,請結(jié)合圖三進(jìn)行如下操作:
1、?????????????
從 OpenLaszlo 獨(dú)立運(yùn)行環(huán)境的 war 包中拷貝“openlaszlo-3.3.3-servlet\lps”目錄到“openlaszloWITHdb4o\”下,該目錄是 OpenLaszlo 的組件庫。
2、?????????????
復(fù)制“openlaszlo-3.3.3-servlet\WEB-INF\lib”目錄到“openlaszloWITHdb4o\WEB-INF\”,該目錄是 OpenLaszlo 的支持庫,然后在該項(xiàng)目的“Java Build Path”中引入這些庫,同時(shí)再引入 dom4j 和 db4o 的支持庫,應(yīng)用程序的服務(wù)器端會(huì)用到。
3、?????????????
復(fù)制“openlaszlo-3.3.3-servlet\WEB-INF\lps”目錄到“openlaszloWITHdb4o\WEB-INF\”,該目錄是 OpenLaszlo 的組件配置信息。
4、?????????????
在“openlaszloWITHdb4o\src”下,分別創(chuàng)建 bo、com 包和類文件,接著創(chuàng)建“helloDb4oUser.lzx”和“peopleoperat.jsp”文件。
5、?????????????
最后,把 war 包的 web.xml 文件拷貝過來,啟動(dòng) OpenLaszlo Server 引擎全靠它了。
????????????????????????????????????????????????????????
???????? 圖三 eclipse中的工程文件結(jié)構(gòu)
?
服務(wù)器端代碼
應(yīng)用程序使用了 Java 5 特性,請保證您的開發(fā)環(huán)境與本文一致。bo 包是整個(gè)用戶管理應(yīng)用程序的數(shù)據(jù)模型,People 類定義了“用戶”,包含姓名、電話等基本信息,請
下載程序源碼查看
。
com
包是與持久層交互的重要部分,Db4oInit 類是一個(gè) Servlet,它的作用是隨 Servlet 容器同時(shí)啟動(dòng) db4o 數(shù)據(jù)庫,并作為 Server 運(yùn)行,以便在運(yùn)行時(shí)通過 db4o 對象管理工具進(jìn)行管理,了解 db4o 的 Server/
Client
模式的具體含義,請參考
《開源面向?qū)ο髷?shù)據(jù)庫 db4o 之旅: db4o 查詢方式》
。最后,不要忘了在 web.xml 中加載 Db4oInit Servlet。
?
Db4oInit
的
init
方法,打開一個(gè)名為“auto.yap”的 db4o 數(shù)據(jù)庫文件,不用擔(dān)心,如果是因?yàn)榈谝淮芜\(yùn)行而沒有該文件,db4o 會(huì)自動(dòng)創(chuàng)建,除了數(shù)據(jù)庫文件,還要加上端口號,在這里我們使用 1010,最后進(jìn)行口令授權(quán)。
import ?javax.servlet.ServletException;
import ?javax.servlet.http.HttpServlet;
import ?com.db4o.Db4o;
import ?com.db4o.ObjectServer;
public ? class ?Db4oInit? extends ?HttpServlet?{
???? private ?ObjectServer?server;
???? public ? void ?destroy()?{
????????server.close();
???????? super .destroy();
????}
???? public ? void ?init()? throws ?ServletException?{
???????? this .server? = ?Db4o.openServer( " auto.yap " , 1010 );
???????? this .server.grantAccess( " admin " , " 123456 " );
????}
}
ContactService
類是 db4o 的 Client 端,用于響應(yīng)業(yè)務(wù)操作,包含了最基本的 CRUD 操作。值得注意的是
getPeopleXml
方法,我們利用 db4o 的 QBE 方式查詢數(shù)據(jù)庫,如果您愿意,還可以使用 SODA、NQ 方式查詢數(shù)據(jù)庫。之后利用 dom4j 進(jìn)行對象的序列化,在此筆者還推薦 XStream 結(jié)合 java 5 的 annotation 進(jìn)行序列化。新增、刪除、修改很簡單,不再敷述,請下載程序源碼查看,注意每次操作完之后 commit 事務(wù)即可。
import ?org.dom4j.Document;
import ?org.dom4j.DocumentHelper;
import ?org.dom4j.Element;
import ?com.db4o.Db4o;
import ?com.db4o.ObjectContainer;
import ?com.db4o.ObjectSet;
import ?bo.People;
import ?java.io.IOException;
public ? class ?ContactService?{
????
???? private ? static ? final ?String?HOST? = ? " localhost " ;?? // ?server?host?name
???? private ? static ? final ? int ?PORT? = ? 1010 ;???????????? // ?server?port
???? private ? static ? final ?String?USER? = ? " admin " ;?????? // ?server?username
???? private ? static ? final ?String?PASSWORD? = ? " 123456 " ;? // ?server?password
???? /**
?????*?retrieve?data?from?db4o?as?XML?String?
?????*? @return ?XML?String
????? */
???? public ?String?getPeopleXml(){
????????ObjectContainer?db? = ? null ;
???????? try ?{
????????????db? = ?Db4o.openClient(HOST,PORT,USER,PASSWORD);
????????????People?peo? = ? new ?People();
????????????ObjectSet < People > ?objectSet? = ?db.get(peo);
????????????Document?peplDoc? = ?DocumentHelper.createDocument();
????????????peplDoc.setXMLEncoding( " UTF-8 " );
????????????Element?rootNode? = ?peplDoc.addElement( " root " );
???????????? for ( int ?i = 0 ;i < objectSet.size();i ++ ){
????????????????Element?peplNode? = ?rootNode.addElement( " node " );
????????????????People?eachPeople? = ?(People)objectSet.get(i);
????????????????peplNode.addAttribute( " userId " ,String.valueOf(eachPeople.getUserId()));
????????????????peplNode.addAttribute( " userName " ,eachPeople.getUserName());
????????????????peplNode.addAttribute( " userPhone " ,eachPeople.getUserPhone());
????????????????peplNode.addAttribute( " userEmail " ,eachPeople.getUserEmail());
????????????????peplNode.addAttribute( " userAddress " ,eachPeople.getUserAddress());
????????????}
???????????? return ?peplDoc.getRootElement().asXML();
????????} catch (IOException?e){
????????????e.printStackTrace();
???????????? return ? " <error/> " ;
????????} finally {
???????????? if (db != null ){
????????????????db.close();????????
????????????}
????????}
????}
}
peopleoperat.jsp
代碼也相對簡單,請
下載程序源碼查看
。
頁面代碼
要編寫 OpenLaszlo 服務(wù)器
能運(yùn)行的代碼,就必須使用 LZX 語言,LZX
是一種面向?qū)ο蟮幕跇?biāo)記的語言
,
利用
XML
和
JavaScript
語法構(gòu)建
RIA
表現(xiàn)層
,
通常這些編寫完成的代碼會(huì)經(jīng)過 OpenLaszlo 編譯器進(jìn)行編譯,最后可作為獨(dú)立的 swf 文件或部署在服務(wù)器上運(yùn)行。
LZX
語言使用開發(fā)者熟悉的語法和命名方式,因此能較容易地融入現(xiàn)有編程環(huán)境。
LZX
語言具有繼承、封裝、多態(tài)等面向?qū)ο笳Z言所具有的特性。通常,一個(gè)標(biāo)簽就等于實(shí)例化了一個(gè)類,比如 <view> 就是 LzView 的實(shí)例。值得注意的是,和基于 DHTML/JavaScript 的程序有著概念上的不同,典型的 DHTML/JavaScript 程序是直接由瀏覽器解析、執(zhí)行嵌入其中的 JavaScript;而 LZX 中的 JavaScript 則是在 OpenLaszlo 服務(wù)器端編譯成客戶端 Flash 解析引擎能運(yùn)行的字節(jié)碼,再下載到瀏覽器執(zhí)行的(swf
文件
)。
LZX
程序是運(yùn)行在名為 canvas 的可視對象基礎(chǔ)上的,也就是以 <canvas> 開始并以 </canvas> 結(jié)束的標(biāo)簽中。在 canvas 中,有許多 view,這些 view 嵌套著業(yè)務(wù)邏輯、可視化特性、可編程屬性、尺寸、位置、背景顏色、不透明性、可點(diǎn)擊性、伸縮性,等等信息。view 也可以包含資源,例如圖像或視頻,也可以動(dòng)態(tài)綁定任意 XML 格式數(shù)據(jù)集。
現(xiàn)在我們就進(jìn)入代碼部分,首先觀察前三行:
???? < debug? x ="0" ?y ="400" ?width ="300" ?height ="200" />
???? < splash />
第一行代碼向我們表明了 LZX 語言的面向?qū)ο筇匦裕?span lang="EN-US">canvas 對象的 debug 屬性為了讓程序調(diào)試時(shí)能在 debugger 窗口打印出調(diào)試信息,height、width 屬性分別指定了 canvas 對象的高和寬,超過這一大小,將不會(huì)被顯示,title 屬性和 HTML 中 title 標(biāo)簽功能一樣,fontsize 屬性作為一個(gè)全局參數(shù),如果沒有明確指定,那么在 canvas 中所有的 view 都將使用該字體大小。第二行代碼實(shí)例化 Debug 對象,并規(guī)定了 debugger 的高和寬,除此以外,還定義了窗口出現(xiàn)的 x(橫坐標(biāo))、y(縱坐標(biāo)),這些都是相對坐標(biāo)。第三行定義了 splash 對象,該對象是加載應(yīng)用程序時(shí)的進(jìn)度條。
LZX
還提供了強(qiáng)大的繪圖功能,下面就讓它小試牛刀吧:
???????? < handler? name ="oninit" > ??????????????????????????????
????????????this.beginPath();
????????????this.lineTo(780,?0);
????????????this.lineTo(780,?50);
????????????this.lineTo(0,?50);
????????????this.lineTo(0,?0);
????????????this.closePath();
????????????var?g?=?this.createLinearGradient(0,0,0,50);
????????????this.globalAlpha?=?0;
????????????g.addColorStop(0,?0x666666);
????????????this.globalAlpha?=?1;
????????????g.addColorStop(1,?0xFFFF00);
????????????this.fillStyle?=?g;
????????????this.fill();???????
???????? </ handler >
???? </ drawview >
在本應(yīng)用中,我們要實(shí)現(xiàn)的是一個(gè)漸變的黃色 banner。drawview 類是專門繪圖的,handler 類捕獲了 oninit 內(nèi)置事件。我們這樣設(shè)想:手中有只畫筆,從某點(diǎn)開始,然后按照一定路徑進(jìn)行邊框描繪,最后填充顏色。同理,this.beginPath() 設(shè)置畫筆的開始點(diǎn)(0,0 坐標(biāo)),然后繪制直線到 780,0 坐標(biāo),接著再繪制到 780, 50 坐標(biāo),然后閉合方框(this 表示 drawview 自身對象實(shí)例),this.createLinearGradient(0,0,0,50) 方法是在按照 x0, y0, x1, y1 這種路徑進(jìn)行梯度過渡,this.globalAlpha、g.addColorStop() 是一系列的顏色填充設(shè)置,從 0x666666 顏色均勻過渡到 0xFFFF00 顏色,最后 this.fillStyle = g 應(yīng)用該設(shè)置,this.fill() 填充即可。
有了以上基礎(chǔ),我們開始解析可視化組件,下面是構(gòu)造邊框?yàn)榫G色的 bordergreenbox 類:
???????? < view? name ="innerbox" ?bgcolor ="0xf4f4f4" ?x ="1" ?y ="1" ?height ="${parent.height-2}" ?width ="${parent.width-2}" />
???? </ class >
class
標(biāo)簽是自定義類的基礎(chǔ),name="bordergreenbox" 屬性為類命名,extends="view" 聲明 “bordergreenbox”類是繼承自“view”(view 是最常用的類,用于組織包含在其中的元素的交互),相應(yīng)的也就繼承了“view”所有的屬性和方法。定義寬度時(shí)用到了“${}”約束符,這意味著“bordergreenbox”的寬度要受到“canvas.width-2”的約束,接著設(shè)置背景為綠色 bgcolor="0x9ae900"。為了能達(dá)到綠色邊框的效果,我們在其中嵌入另一個(gè) view,再設(shè)置顏色、相對坐標(biāo)、高、寬。
以下部分是在構(gòu)造 newPeople 類,用于讓用戶輸入基本信息:
???????? < simplelayout? spacing ="4" ?axis ="x" />
???????? < text > 姓名: </ text >< edittext? name ="userName" ?width ="60" />
???????? < text > 電話: </ text >< edittext?? name ="userPhone" ?width ="100" />
???????? < text > 電子郵件: </ text >< edittext?? name ="userEmail" ?width ="140" />
???????? < text > 地址: </ text >< edittext? name ="userAddress" ?width ="230" />
???? </ class >
和 bordergreenbox 類不同的是,newPeople 類引入了新屬性 visible="false",它的作用是讓newPeople 不可見,如果不設(shè)置該屬性則默認(rèn)為可見。我們還引入了 simplelayout 類,它的作用是均勻分布 newPeople 類中所有的對象,spacing="4" 是在定義間距為 4,axis="x" 定義按照橫向分布。text 類是用來嵌入文字的,且支持嵌入 <a>、<b>、<font> 等 HTML 標(biāo)記,而 edittext 的作用則類似 HTML 中的 input 標(biāo)簽。運(yùn)行效果如圖四。
????????????????
??????????????????????????????????? ?
?
圖四:newPeople 類
如何訪問 JSP 提供的數(shù)據(jù)源呢?在這個(gè)應(yīng)用中,分別構(gòu)建了兩個(gè)數(shù)據(jù)集,db4odata 用來獲取返回的列表數(shù)據(jù),peopleoperate 進(jìn)行業(yè)務(wù)操作,下面主要分析 db4odata:
???? < datapointer? name ="db4odtpt" ?xpath ="db4odata:/*" >
???????? < handler? name ="ondata" >
????????????canvas.bgview.rowcontainer.datapath.setPointer(this.p);?
????????????canvas.loader.setVisible(false);
????????????Debug.write("data?loaded!");
???????? </ handler >
???? </ datapointer >
dataset
是數(shù)據(jù)訪問類,src 作為資源訪問路徑指向 JSP 頁面,并規(guī)定type 為 http 協(xié)議,當(dāng)request="false" 時(shí),必須通過調(diào)用 doRequest() 方法才能訪問資源并獲取數(shù)據(jù),而為“true”時(shí),則會(huì)自動(dòng)訪問資源,一般應(yīng)設(shè)置為“false”。接下來用到了 datapointer 類,datapointer 是 dataset 的數(shù)據(jù)指針,并遵循 XPATH 語法規(guī)范訪問數(shù)據(jù),xpath="db4odata:/*" 定義 XPATH 的路徑,既 db4odata dataset 的所有子路徑。handler 類捕獲 ondata 事件(ondata 是 datapointer 對象內(nèi)置事件),并通過“.”運(yùn)算符為 bordergreenbox 類的實(shí)例 bgview 設(shè)置數(shù)據(jù)源,再隱藏一個(gè)名為 loader 的對象,代碼如下:

不錯(cuò),loader 對象僅僅寫下“loading...”,這是為了改善程序的互動(dòng)效果。接下來分析 bordergreenbox 類實(shí)例 bgview,bgview 包含了兩個(gè) view 對象。以下代碼向我們展示了第一個(gè) view,它的作用是提供列名:
???????????? < text? x ="40" > ID </ text >
???????????? < text? x ="140" > 姓名 </ text >
???????????? < text? x ="260" > 電話 </ text >
???????????? < text? x ="410" > 電子郵件 </ text >
???????????? < text? x ="620" > 地址 </ text > ??????
???????? </ view >
第二個(gè) view 對象 rowcontainer,剛才我們分析 db4odata 數(shù)據(jù)源集時(shí)捕獲的 ondata 事件嗎?不錯(cuò),一旦接收到數(shù)據(jù),rowcontainer 也就從 name="db4odtpt" 的數(shù)據(jù)指針中獲取了數(shù)據(jù):
?
???????????? < view? name ="columns" ?datapath ="${parent.datapath}" ?width ="$once{parent.width-2}" >
???????????????? < simplelayout? axis ="y" ?spacing ="1" />
???????????????? < selectionmanager? name ="selector" ?toggle ="true" />
???????????????? < view? datapath ="*" ?width ="$once{parent.width}" ?bgcolor ="0xffffff" ?onclick ="parent.selector.select(this);" >
???????????????????? < text? x ="0" ?datapath ="@userId" ??width ="110" />
???????????????????? < text? x ="115" ?multiline ="true" ?datapath ="@userName" ?width ="100" />
???????????????????? < text? x ="220" ?multiline ="true" ?datapath ="@userPhone" ?width ="130" />
???????????????????? < text? x ="355" ?multiline ="true" ?datapath ="@userEmail" ?width ="180" />
???????????????????? < text? x ="540" ?multiline ="true" ?datapath ="@userAddress" ?width ="220" />
???????????????????? < method? name ="setSelected" ?args ="amselected" > <![CDATA[ ??????
????????????????????????if?(amselected)?{?????????
????????????????????????????var?bgcolor?=?0xD5E4F3;
????????????????????????????canvas.np.sendit.userid?=?this.datapath.xpathQuery('@userId');?
????????????????????????????canvas.np.userName.setText(this.datapath.xpathQuery('@userName'));
????????????????????????????canvas.np.userPhone.setText(this.datapath.xpathQuery('@userPhone'));
????????????????????????????canvas.np.userEmail.setText(this.datapath.xpathQuery('@userEmail'));
????????????????????????????canvas.np.userAddress.setText(this.datapath.xpathQuery('@userAddress'));
????????????????????????????canvas.np.userName.setAttribute('enabled',false);???
????????????????????????}?else?{????
????????????????????????????var?bgcolor?=?0xFFFFFF;
????????????????????????????canvas.np.userName.clearText();
????????????????????????????canvas.np.userPhone.clearText();
????????????????????????????canvas.np.userEmail.clearText();
????????????????????????????canvas.np.userAddress.clearText();
????????????????????????????canvas.np.userName.setAttribute('enabled',true);
????????????????????????}
????????????????????????this.setBGColor(?bgcolor?);?
???????????????????? ]]> </ method > ?
???????????????? </ view >
???????????? </ view >
???????? < scrollbar />
???????? </ view >
clip="true"
屬性是為了讓包含在其中的子對象之間能夠很好的布局。rowcontainer 中又嵌套了 view 對象 columns,并通過父對象取得了數(shù)據(jù)路徑 datapath,接著按縱向均勻布局其中的行,selectionmanager 類似 HTML 中的 select 標(biāo)簽,一旦選中某行將觸發(fā)為其內(nèi)置屬性 selected 賦值為“true”。接下來的 view 才是真正顯示數(shù)據(jù)列表,onclick 事件也是 view 類的內(nèi)置事件,當(dāng)點(diǎn)擊了某條記錄,將聯(lián)合 selectionmanager 進(jìn)行操作,所以在這里為 selectionmanager 傳入了選中的某條記錄。datapath="@userId" 用于綁定 XML 數(shù)據(jù)中的 userId 屬性,并自動(dòng)顯示。剛才說到由于 selectionmanager 和 view 是緊密聯(lián)系的,所以在這里重寫了 view 的 setSelected 抽象方法,并傳入了布爾類型數(shù)據(jù)。在 <![CDATA[ ]]> 之間的代碼,OpenLaszlo 將忽略其中的特殊字符(例如“<”符號),np 是之前我們構(gòu)造的 newPeople 類的實(shí)例,接下來會(huì)講到,而 canvas.np.sendit.userid = this.datapath.xpathQuery('@userId') 則是在進(jìn)行賦值操作,雖然 newPeople 類的實(shí)例是不可見的,但卻隱含的傳入了數(shù)據(jù),canvas.np.userName.setAttribute('enabled',false) 是動(dòng)態(tài)創(chuàng)建的屬性,為了區(qū)分“新增”、“修改”操作(新增可編輯“用戶名”而修改則不能)。var bgcolor 是在聲明局部變量,和 Java 語言不同的是,if 語句內(nèi)聲明的局部變量也能在語句之外調(diào)用,所以 this.setBGColor(bgcolor) 不會(huì)出現(xiàn)任何異常。
想必大家很關(guān)心 newPeople 類實(shí)例 np 是什么樣子,接下來會(huì)講解到如何添加和修改數(shù)據(jù)并提交給 JSP 處理:
???????? < button? name ="sendit" ?height ="24" ?width ="40" ?text ="提交" ? >
???????????? < attribute? name ="userid" ?value ="0" />
???????????? < attribute? name ="action" ?value ="null" />
???????????? < handler? name ="onclick" > <![CDATA[
????????????????var?username?=?parent.userName.getText();
????????????????var?usermobile?=?parent.userPhone.getText();
????????????????var?useremail?=?parent.userEmail.getText();
????????????????var?useraddress?=?parent.userAddress.getText();
????????????????var?usernamenabled?=?parent.userName.getAttribute('enabled');
????????????????function?send(action){
????????????????????peopleoperate.setQueryParam('action',action);
????????????????????peopleoperate.setQueryParam('userId',userid);
????????????????????peopleoperate.setQueryParam('userName',username);
????????????????????peopleoperate.setQueryParam('userPhone',usermobile);
????????????????????peopleoperate.setQueryParam('userAddress',useraddress);
????????????????????peopleoperate.setQueryParam('userEmail',useremail);
????????????????????peopleoperate.doRequest();
????????????????????canvas.loader.setVisible(true);
????????????????????parent.setVisible(false);
????????????????????canvas.bgview.setY(85);
????????????????}
????????????????if?(username!=''?&&?usermobile!=''?&&?useremail!=''?&&?useraddress!=''){
????????????????????if?(action?==?'add'?&&?usernamenabled?==?true){
????????????????????????Debug.write('addPeople');
????????????????????????send('addPeople');
????????????????????}?else?if?(action=='update'){
????????????????????????Debug.write('updatePeople');
????????????????????????send('updatePeople');
????????????????????}
????????????????}????????
????????????????userid?=?0;????
???????????? ]]> </ handler >
???????? </ button >
???? </ newPeople >
在此我們引入了 button 類,接著構(gòu)造了兩個(gè)屬性,userid 用于在修改時(shí)傳遞用戶 ID,而 action 則用于確定是何種業(yè)務(wù)操作。接著捕獲了 button 類的 onclick 事件,聲明局部變量以便接下來發(fā)送,function send(action){…} 是構(gòu)造的內(nèi)部方法,用于發(fā)送請求,peopleoperate.setQueryParam() 是在對 peopleoperate 數(shù)據(jù)集創(chuàng)建請求參數(shù),最后 peopleoperate.doRequest() 發(fā)出請求。構(gòu)造好內(nèi)部方法后,開始判斷是哪種業(yè)務(wù)操作,并分別傳入 'addPeople' 和 'updatePeople' 參數(shù),待提交完成后 parent.setVisible(false) 隱藏 np。
我們在前面提到了當(dāng)點(diǎn)擊了 columns 對象中的某一行將自動(dòng)為 np 對象填入值,而這個(gè)時(shí)候 np 是隱藏的,不錯(cuò),需要增加一個(gè)按鈕來顯示 np 以便進(jìn)行修改:
???????? < handler? name ="onclick" >
????????????parent.np.setVisible(true);
????????????parent.bgview.setY(115);
????????????canvas.np.sendit.action?=?'update';
???????? </ handler >
???? </ button >
新增和修改的操作差不多,而刪除則傳入用戶 ID, peopleoperate.setQueryParam('action','delPeople') 直接刪除。
到此,頁面代碼也完成得差不多了,啟動(dòng)您的服務(wù)器。運(yùn)行效果如圖五:
?????????????????
???????????? 圖五:
openlaszloWITHdb4o
應(yīng)用
程序
Tips
在開發(fā) OpenLaszlo 過程中會(huì)遇到不少意想不到的問題,最常見的是提交數(shù)據(jù)后 debugger 打印出“data conversion error……”信息,檢查程序后未發(fā)現(xiàn)任何異常,很讓人困惑,其實(shí)你只需在服務(wù)器端返回一個(gè)簡單的 XML 即可,哪怕是“<ok/>”標(biāo)簽。
您的應(yīng)用程序在運(yùn)行時(shí)是可以隨時(shí)點(diǎn)擊鼠標(biāo)右鍵查看源代碼的,如圖六:
???????????????????????????????????????????????????????????????
??????????????? ? 圖六:程序?qū)傩?span lang="EN-US">
這對安全構(gòu)成了威脅,特別是部署后實(shí)際運(yùn)行的應(yīng)用。OpenLaszlo 為我們考慮到了這點(diǎn),只需修改被部署的應(yīng)用的“WEB-INF\lps\config\lps.properties”文件,把“allowRequestSOURCE”參數(shù)設(shè)置為“false”即可。
提高 OpenLaszlo 開發(fā)效率原則:
1.???
只做自己擅長的事
OpenLaszlo
只擅長做表現(xiàn)層,不要奢求在界面上處理一些復(fù)雜邏輯,這些要交給后臺處理。也不要用它來做類似于博客等以文字為主的應(yīng)用,體現(xiàn)不出優(yōu)勢,反而體現(xiàn)出劣勢。
2.???
做好自己該做的事
類似于客戶端數(shù)據(jù)校驗(yàn)的功能,前臺該做好的,就不要交給后臺去判斷數(shù)據(jù)是否有效,前臺每次提交都要保證自己是沒有問題的,和后臺的結(jié)合應(yīng)該是無障礙的。
3.???
不要過分追求效果
不要為了 RIA 而 RIA,界面的過多動(dòng)態(tài)效果,只會(huì)讓用戶眼花繚亂,而且加大了代碼量,增加了性能問題,損害了用戶體驗(yàn),只有簡單中有一點(diǎn)新奇、靜中有動(dòng)才是境界。
提高 OpenLaszlo 運(yùn)行效率原則:
1.???
dataset
的請求(request)屬性永遠(yuǎn)是 false
只有在事件中才進(jìn)行 doRequest()。
2.???
盡量少用約束符${}來指定視圖間的位置關(guān)系
比如:<view name="myview" x="${parent.b.x}" .../> 因?yàn)槌绦蛟诔跏蓟^程中要評估表達(dá)式的值,而且生成約束 constraints,這樣對性能產(chǎn)生很大影響。
3.???
需要數(shù)據(jù)來生成視圖內(nèi)容的組件盡量不用嚴(yán)格數(shù)據(jù)綁定
這樣做是為了減少程序編譯時(shí)間合減少服務(wù)期端傳送過來的文件尺寸。正確的做法是將組件的 datapath 置為空,即定義組件的 datapath="",而在用戶事件或者在 datapointer 中的 ondata 事件中用 component.datapath.setPointer(this.p) 中進(jìn)行運(yùn)行時(shí)綁定。
4.???
通過事件給組件填充數(shù)據(jù)
combobox
、list 等組件的數(shù)據(jù)只在需要時(shí)填充,通過打開窗口或者點(diǎn)擊按鈕的事件來為這些組件填充內(nèi)容。只要填充了一次,下次如果數(shù)據(jù)沒變,就不會(huì)再重復(fù)生成視圖。
5.???
使用 initstage="defer"
OpenLaszlo
官方文檔推薦使用 initstage="defer" 來阻止某些不是馬上用到的視圖的生成,而在需要的時(shí)候才 complete,但筆者試過,不太好掌握時(shí)機(jī),而且會(huì)讓程序變的互相耦合,效果不甚理想。
6.???
使用 dataoption="lazy"
list
組件有一個(gè)很有用的屬性:dataoption="lazy",這個(gè)屬性可以使列表中的數(shù)據(jù)更新起來非常迅速,尤其是在大數(shù)據(jù)量的情況下。它的原理在于把部分視圖進(jìn)行了緩存,而不是全部銷毀和新建,可惜 tree 組件對于這個(gè)屬性不管用。
7.???
盡量降低視圖的層次
盡可能的減少視圖的嵌套層次,能直接放在 canvas 下,就不要放在其他視圖里面,而且window 和 modaldailog 應(yīng)該嚴(yán)格的直接放在 canvas 里面。這樣做是為了加快程序的渲染速度,并且簡化編程時(shí)路徑引用,方便查看代碼結(jié)構(gòu)。
8.???
盡量少用 state/animator
用這些會(huì)增加內(nèi)存占用和代碼量,而用 node 的 animate 方法卻可以輕松的控制視圖運(yùn)動(dòng),而且沒有額外的內(nèi)存占用。
9.???
控制單個(gè) canvas 文件的代碼規(guī)模
一個(gè) canvas 文件代碼行數(shù)最好控制在 1000 行以內(nèi),其中 include 進(jìn)來的方法、資源、自定義組件的代碼數(shù)目不算在內(nèi),這樣做是為了獲得較快的界面初始化時(shí)間,和方便的代碼維護(hù)。
10.
盡量采用 SOLO 方式部署
如果不需要 RPC 等特殊功能,建議采用 SOLO 方式部署應(yīng)用,將已經(jīng)寫好的 OpenLaszlo應(yīng)用編譯成 swf 文件,在 html 文件中包裹,這樣可避免用戶第一次請求 lzx 文件的長時(shí)間等待,也避免了服務(wù)期重起后重新編譯 lzx 文件,還可以減少 OpenLaszlo Server 部署時(shí)對服務(wù)器空間的占用(盡管才十幾兆)。
11.
模塊化應(yīng)用
將具有獨(dú)立功能的應(yīng)用模塊單獨(dú)分離出來,即用一個(gè)包含 canvas 的 lzx 文件配合其他組件來實(shí)現(xiàn)一個(gè)小模塊,各個(gè)模塊之間導(dǎo)航用 loadURL() 來完成,各個(gè)模塊共享 Session 以及后臺數(shù)據(jù),實(shí)現(xiàn)模塊之間的通訊。
結(jié)論
通過上面的介紹,想必您已經(jīng)體會(huì)到 OpenLaszlo 與 db4o 結(jié)合起來做程序是多么的有趣。如果在不借助第三方框架,用傳統(tǒng)的 JSP+JavaScript 與 JDBC 技術(shù)開發(fā),相信其代碼量會(huì)遠(yuǎn)遠(yuǎn)超過前者。OpenLaszlo與 db4o 的設(shè)計(jì)目標(biāo)都是為節(jié)約開發(fā)周期而努力,相信他們也做到了,剩下的就看開發(fā)者是如何利用其優(yōu)勢的,您準(zhǔn)備好了嗎?
關(guān)于作者
Rosen Jiang
來自成都,是 db4o 和 OO 的忠實(shí) fans,RIA 倡導(dǎo)者,是 2007 年 db4o 的 dvp 獲得者之一。你可以通過 rosener_722@hotmail.com 和他聯(lián)系。
Lwz7512
來自北京
,是一名 OpenLaszlo Developer,他
是
OpenLaszlo
在中國的User Group負(fù)責(zé)人,也是Openlaszlo中國開發(fā)者社區(qū)創(chuàng)辦者,
你可以通過
rabbit69@126.com
和他聯(lián)系。
參考資料
資源
OpenLaszlo
官方網(wǎng)站 http://www.openlaszlo.org/
db4o
官方網(wǎng)站 http://www.db4o.com/
Openlaszlo
中國開發(fā)者社區(qū) http://www.openria.cn/
中國RIA開發(fā)者論壇 http://www.riachina.com/
學(xué)習(xí)
Rich Internet Applications
的技術(shù)選項(xiàng):
http://www-128.ibm.com/developerworks/cn/web/wa-richiapp/index.html
Rich Internet Applications and
http://www.javalobby.org/articles/ajax-ria-overview
Introducing OpenLaszlo
http://www.xml.com/pub/a/2006/10/11/introducing-open-laszlo.html
OpenLaszlo
文檔中心
http://www.openlaszlo.org/documentation
在 OpenLaszlo 應(yīng)用程序中使用 Apache Derby,第 1 部分:使用 Derby 提供數(shù)據(jù)
http://www-128.ibm.com/developerworks/cn/views/opensource/tutorials.jsp?cv_doc_id=110109
在 OpenLaszlo 應(yīng)用程序中使用 Apache Derby,第 2 部分:存儲(chǔ)和嵌入數(shù)據(jù)
http://www-128.ibm.com/developerworks/cn/views/opensource/tutorials.jsp?cv_doc_id=110110
使用 OpenLaszlo 創(chuàng)建 Web 富客戶端
http://www-128.ibm.com/developerworks/cn/xml/wa-openlaszlo/index.html
Openlaszlo
開發(fā)規(guī)范
http://www.openria.cn/posts/list/49.page
面向?qū)ο髷?shù)據(jù)庫 db4o 之旅,第 1 部分:初識 db4o http://www-128.ibm.com/developerworks/cn/java/j-lo-db4o1
面向?qū)ο髷?shù)據(jù)庫 db4o 之旅,第 2 部分:db4o 查詢方式http://www-128.ibm.com/developerworks/cn/java/j-lo-db4o2
《程序員》雜志版權(quán)所有!引用、轉(zhuǎn)貼本文應(yīng)注明本文來自《程序員》雜志。