快速啟動(dòng)一個(gè)Java Web編程框架
RSF,不像其他的Java Web框架,主要側(cè)重于標(biāo)記和網(wǎng)頁(yè)設(shè)計(jì)師的作用。網(wǎng)頁(yè)設(shè)計(jì)師不會(huì)被框架產(chǎn)生的標(biāo)記而限制,也不是被迫圍繞內(nèi)嵌代碼或是偽代碼來(lái)設(shè)計(jì)。模板是純粹的XHTML不需要框架知識(shí)來(lái)創(chuàng)建或是維護(hù)。這個(gè)創(chuàng)建了完全分離的顯示和Java代碼隱藏。網(wǎng)頁(yè)設(shè)計(jì)師和開(kāi)發(fā)者可以獨(dú)立工作,而且不需要協(xié)調(diào)他們的工作,這個(gè)你將在示例程序中看到。
RSF目的在于用零服務(wù)器環(huán)境創(chuàng)建一個(gè)框架,這樣可以通過(guò)在循環(huán)的***扔掉組件樹(shù)來(lái)節(jié)省寶貴的服務(wù)器資源。這個(gè)有別于很多常見(jiàn)的Java框架,例如JSF,憑借框架執(zhí)行的***個(gè)動(dòng)作來(lái)恢復(fù)使用從先前要求中出現(xiàn)的組件樹(shù)。Session狀態(tài)是以此來(lái)減小較低利用的服務(wù)器資源。
RSF目的是通過(guò)遵循一個(gè)嚴(yán)格的POST->GET重定向以便保留所有的GET請(qǐng)求冪等來(lái)遵循在服務(wù)器上的正確而有效的瀏覽器行為。這樣,POST純粹是用來(lái)發(fā)送數(shù)據(jù)到服務(wù)器上的,而GET是用來(lái)返回?cái)?shù)據(jù)到瀏覽器上的。這個(gè)可以解決很多問(wèn)題,就是其他框架所面對(duì)的瀏覽器返回鈕行為或是深層鏈接問(wèn)題。
Recipe List Application
為了演示這些RSF核心組件的主要目的,我們來(lái)構(gòu)建一個(gè)非常簡(jiǎn)單的recipe list應(yīng)用程序。這個(gè)程序?qū)?chuàng)建一個(gè)項(xiàng)目列表,通過(guò)允許用戶通過(guò)網(wǎng)絡(luò)形式添加更多的項(xiàng)目。這個(gè)簡(jiǎn)單的任務(wù)將展示很多的功能包括:模板建設(shè),鏈接行為,簡(jiǎn)單的國(guó)際化和表格粘貼。
為了開(kāi)始這個(gè)簡(jiǎn)單的程序,首先你需要為RSF準(zhǔn)備好一個(gè)環(huán)境。RSF的wiki網(wǎng)站有一個(gè)很棒的指導(dǎo)來(lái)安裝RSF Development Environment,但是不在本文的討論之內(nèi)。一旦完成安裝,你可以通過(guò)在程序中創(chuàng)建XHTML模板來(lái)開(kāi)始程序了。如上述所提到的,這些都是純粹的XHTML模板,用它們唯一所關(guān)心的外觀所建立的。對(duì)于這個(gè)簡(jiǎn)單的程序,要有兩頁(yè),所以你需要?jiǎng)?chuàng)建兩個(gè)XHTML模板:
recipelist.html
|
itemForm.html
|
正如以上所看到的,這些是幾乎完全有效的XHTML文件,除了額外的一個(gè)單一屬性,rsf:id=""。這個(gè)是RSF在模板中所代表的唯一機(jī)制。事實(shí)上,這些模板可以在任何網(wǎng)頁(yè)瀏覽器(是忽略額外屬性的瀏覽器)中看到并且可以被驗(yàn)證。任何在模板中的文本或是其他的特性包括rsf:id屬性將通過(guò)RSF被覆蓋,所以模板可以包含如你所希望的"假數(shù)據(jù)"。這是極其有益的,通過(guò)允許假內(nèi)容的存在,讓設(shè)計(jì)者與開(kāi)發(fā)者對(duì)標(biāo)記結(jié)構(gòu)的意圖進(jìn)行溝通。恰當(dāng)?shù)膔sf:id值列表是唯一的契約可以讓設(shè)計(jì)者和開(kāi)發(fā)者必須互相維持。只要相同的ID以語(yǔ)義上相同的方法來(lái)運(yùn)用,這個(gè)想法就會(huì)工作。
rsf:id標(biāo)簽指定一個(gè)ID讓RSF rendering engine有地方連線它的數(shù)據(jù)。帶有冒號(hào)(:)的ID使用是一個(gè)特殊的協(xié)議就是告訴rendering engine這個(gè)XHTML節(jié)點(diǎn)可能會(huì)重復(fù)。為了支持國(guó)際化,另一個(gè)特殊的標(biāo)簽協(xié)議是用于直接將文本從一個(gè)標(biāo)準(zhǔn)的Java屬性組合中提取出來(lái)。這個(gè)使得開(kāi)發(fā)者通過(guò)簡(jiǎn)單定義一個(gè)特殊的rsf:id="msg=property_key"直接連線rsf:id到一個(gè)properties bundle key 。對(duì)于這個(gè)應(yīng)用程序,所有的頁(yè)面文本都被拖動(dòng)到以下的屬性捆綁中。
messages.properties |
一旦你開(kāi)始使用這些模板,你必須為每一個(gè)模板創(chuàng)建一個(gè)Component Producer。在RSF中的一個(gè)component producer是一種機(jī)制讓Java中組件樹(shù)可以在其中構(gòu)建。每一個(gè)producer執(zhí)行ViewComponentProducer接口并且有一個(gè)相應(yīng)的ViewID,可以與模板的文件名相匹配。重載方法fillComponents是組件樹(shù)構(gòu)建的地方,用以在模板中符合rsf:ids。參數(shù)UIContainer tofill作為組件樹(shù)(這里可以添加所有的組件)的一個(gè)父元素。producer將為recipe list的項(xiàng)目構(gòu)建組件樹(shù),如下:
|
有了這個(gè)producer,一些主要的概念被采用了,還有一些RSF的內(nèi)置組件。上述的RecipeListService簡(jiǎn)單的恢復(fù)了代表每個(gè)recipe list項(xiàng)目的字符串列表。以前,根據(jù)研究結(jié)果表明用于國(guó)際化的信息包文本可以直接通過(guò)模板來(lái)利用。但是,如果你需要做的不僅僅是輸出靜態(tài)文本,你可以選擇使用RSF的UIMessage組件來(lái)執(zhí)行包查找。這里,在從服務(wù)器檢索recipe項(xiàng)目的列表之后,你想要顯示項(xiàng)目的總數(shù),可以使用"current_items_count"信息包。使用UIMessage組件,你可以查找綁定的字符串"current_items_count",編排文本格式添加size()到一個(gè)占位符,并且附加它到帶有rsf:id="current_count"的DOM節(jié)點(diǎn)。
下一步是從服務(wù)器上顯示每個(gè)項(xiàng)目。如以上所提到的,當(dāng)創(chuàng)建rsf:id屬性到designate(在DOM中重復(fù)的元素)的時(shí)候,你使用冒號(hào)標(biāo)記。在模板中,你想要對(duì)每一個(gè)在recipe list上的項(xiàng)目重復(fù)一個(gè)< li>元素。要做到這一點(diǎn), 把rsf:id="current_items:"(注意***的冒號(hào)) 給在模板中的元素。還有另一個(gè)注意的是顯示的分離。在Java中構(gòu)建的組件樹(shù)不會(huì)關(guān)注使用哪些標(biāo)記標(biāo)簽;它只知道DOM元素是被重復(fù)的。通過(guò)設(shè)計(jì)者的自由裁量,< p>很容易用來(lái)代替< li>。為了創(chuàng)建匹配的組件樹(shù)項(xiàng)目,你可以創(chuàng)建一個(gè)UIBranchContainer組件。這個(gè)組件可以指示rendering engine,其中在DOM中項(xiàng)目被"綁定"允許循環(huán)的發(fā)生。每個(gè)反復(fù)的循環(huán)都要?jiǎng)?chuàng)建一個(gè)新的UIBranchContainer來(lái)告訴組件樹(shù)有多少個(gè)< li>DOM節(jié)點(diǎn)你需要去創(chuàng)建。
一旦你有了分支的< li>,你需要輸出文本項(xiàng)目。使用UIBranchContainer行作為一個(gè)父體(parent),你使用UIOutput來(lái)輸出recipe list項(xiàng)目的文本到DOM元素,用rsf:id="row_item"。通過(guò)設(shè)置父體到UIBranchContainer,你會(huì)使rsf:id="row_item"元素作為一個(gè)子rsf:id="row_item:"元素來(lái)呈現(xiàn)。
在producer中的***一步是創(chuàng)建一個(gè)內(nèi)部鏈接到itemform.html網(wǎng)頁(yè)。所有鏈接通過(guò)RSF來(lái)進(jìn)行內(nèi)部管理。為了創(chuàng)建鏈接,附加組件樹(shù)上一個(gè)UIInternalLink組件到模板的rsf:id="add_item"上。既然你不以GET參數(shù)形式來(lái)傳送數(shù)據(jù),你可以利用RSF的SimpleViewParameters。但是,創(chuàng)建自定義的ViewParameters可以傳遞你希望的數(shù)據(jù),但是這超出了本程序的范圍。
下一個(gè)你創(chuàng)建的producer將構(gòu)建組件樹(shù)來(lái)處理允許recipe項(xiàng)目被添加到列表上的表格:
|
這個(gè)簡(jiǎn)單的producer構(gòu)建了需要處理一個(gè)成功的POST的表格元素和滾條。首先,使用RFS組件UIForm添加一個(gè)表格組件到組件樹(shù)中,通過(guò)使用在模板中相同的rsf:id="form"。下一步,添加一個(gè)組件,UIInput,到UIForm 元素中,這個(gè)可以運(yùn)行用戶可以接收的輸入。同樣的用UICommand組件來(lái)構(gòu)建一個(gè)提交按鈕。UIInput 和UICommand組件同時(shí)采用一個(gè)第三方字符串參數(shù)來(lái)創(chuàng)建一個(gè)有價(jià)值的binding。這就是RFS的Expression Language的形成。這個(gè)要比在JSF中同樣的EL簡(jiǎn)單得多,RSF的EL僅僅指定一個(gè)簡(jiǎn)單的bean路徑。這樣,當(dāng)按下提交按鈕時(shí),在調(diào)用被UICommand value binding 定義的RecipeListBean.processActionSubmit()之前,在UIInput中的值被直接傳遞到RecipeListBean 的"item"屬性。
這個(gè)Producer的***一塊就是NavigationCaseReporter接口的執(zhí)行。記住RSF通過(guò)一個(gè)重定向的GET,遵循每個(gè)POST提交。默認(rèn)情況下,GET請(qǐng)求會(huì)遵循來(lái)自它們的相同看法。為了重定向用戶到不同的地方,可以利用RSF的NavigationCases。Navigation cases被JSF的同樣的命名功能所激發(fā)并允許來(lái)自POST提交的簡(jiǎn)單的流。在表格中,在成功的添加一個(gè)項(xiàng)目到列表中之后,你想重新定向recipe項(xiàng)目的列表。NavigationCase告訴RSF當(dāng)POST綁定方法RecipeListBean.processActionSubmit的時(shí)候,返回字符串"success"然后GET 重定向需要返回RecipeListProducer。除了這個(gè)簡(jiǎn)單的方法之外,RSF也允許其他更先進(jìn)的創(chuàng)建流的方法。
RecipeListBean.java ... |
***一步包括添加eans到在web.xml中定義過(guò)的Spring定義中。這個(gè)遵循Spring框架的反向控制方法而且非常的直截了當(dāng)。所有這些配置和整個(gè)源代碼提供,以供參考。雖然這個(gè)程序非常簡(jiǎn)單平常,但是它強(qiáng)調(diào)了RSF的一些核心組件。
【編輯推薦】
- 使用jQuery和PHP構(gòu)建一個(gè)受Ajax驅(qū)動(dòng)的Web頁(yè)面
- 視頻教程:ASP.NET Web開(kāi)發(fā)詳解
- .NET平臺(tái)下Web測(cè)試工具橫向比較
【責(zé)任編輯:彭凡 TEL:(010)68476606】