Web開發“菊花寶典”OperaMasks系列之一

OperaMasks2.0開發實例入門之一:HelloWorld

1. 前言

本系列文章將從原始的HelloWorld應用講起,逐步深入,到後面的在線酒店預訂等應用,來介紹OperaMasks2.0應用的實際開發。 在閱讀本文之前,我建議你閱讀《OperaMasks2.0的神奇魔力》系列文章。

2. 實例介紹

幹我們這行的,面對一個新的技術的時候,總是習慣於從經典的HelloWorld程序開始,實際上這也是最有效的入門方法,這裏我們也世俗的從HelloWorld實例開發入手,畢竟它太經典了。
例子比較簡單,在一個輸入頁面中輸入,然後再另一個頁面中顯示你剛纔的輸入。
效果圖(1):輸入頁面
效果圖(2):結果頁面

3. 開發與運行環境

開發環境
選擇1:基於Eclipse的集成開發工具ApusicStudio,她能夠很好的支持AOM的可視化開發(如下圖),利用她開發AOM應用時,會自動幫你加入AOM的相關包和基本配置文件,並且內置Apusic應用服務器開發調試環境,而ApusicServer又自帶最新的AOM包,所以,你可以迅速的開發,部署和運行你的AOM應用。所以筆者強烈建議使用ApusicStudio+Apusic
選擇2:當然,你也可以使用MyEclipse,Eclipse甚至Editplus來開發應用。
(1)選擇1:應用服務器: Apusic5.1(已內置OperaMasks2.0引擎) ,下載地址:點這裏
(2)選擇2:Web容器:Tomcat6 ; OperaMasks2.0:下載地址:點這裏
OperaMasks2作爲一款優秀的開發框架,並沒有和哪個應用服務器有綁定的行爲,所以,筆者這裏採用的是Tomcat6作爲本例運行的WEB容器。

4. 應用的JAR包

OK,現在讓我們正式開始應用的編寫。 首先,用你熟悉的工具建立一個標準的Web應用,起名爲aom-example-hello,然後下載OperaMasks2,將解壓後的根目錄的jar文件及其lib目錄下的jar文件拷貝到你建立的這個應用的WEB-INF/lib目錄(因爲本例沒有使用spring,所以,沒有把spring目錄中的jar包拷貝出來)。
注意:如果你下載的OperaMasks版本低於2.0 m2,並且你想把開發的應用運行在Tomcat中,需要做些小小的調整: 1)打開拷貝到應用的WEB-INF/lib目錄。 2)把elite.jar中的javax目錄刪除。 3)把javaee.jar拷貝到你的tomcat下的lib目錄中。
調整後的應用WEB-INF/lib目錄看起來是這個樣子:
如果你使用的服務器是Apusic5.1最新版,就無需任何改動,他內置了AOM引擎。

5. 配置文件

從OperaMasks下載目錄裏,打開blank示例的war包,裏面有OperaMasks需要使用的4個配置文件,直接拿出來拷貝到應用的WEB-INF目錄底下(web.xml ,faces-config.xml,jsf-ui.tld,operamasks.xml)。
鑑於篇幅的原因,我就不具體貼出這4個文件的內容了,基本上,程序沒有什麼特別的地方,這些配置文件你是不需要改動的。

6. 背景知識

實現表示層和業務層的分離,這是J2EEWeb應用一直以來的理想,可惜衆多的Web框架並沒有真正實現這個目標。大多數框架的Web開發技術“腳本”味道很濃,在頁面中混淆了大量用於顯示邏輯的HTML 和用於業務邏輯的Java 代碼,使得頁面設計與程序開發無法分離;另一個更大的缺陷是腳本不能重用,這常常導致開發者不得不在頁面之間進行復制-粘貼操作,進而導致同一段代碼出現多個版本,從而使得程序的調試和設計極其錯綜複雜。而標籤庫作爲一個補充,將Java代碼從頁面中剝離,也只是有限地實現了表現與邏輯的分離,始終沒有擺脫代碼和HTML頁面揉和的問題。
著名的MVC模式強調視圖層,控制層,業務層的分離,雖然傳統的WEB開發框架都超着這個方向努力,然而他們大多數仍是這樣一些工作:將頁面中控件的值取出打包成 Java Bean;再無非就是在幫助你完成頁面導航的過程中,輔助你進行頁面參數的傳遞與分析。這樣一種“簡單 MVC”架構,是無法完全解決“視圖層,控制層與業務數據完全解耦”這個問題的。 一旦你的需求超越了框架的能力,那麼,你將面對的依然是:不得不在展現層中嵌入大量的 Script 代碼,可能是Java代碼片斷,也可能是大量tag-lib及EL表達式的引入。
例如,下面的代碼是大多數傳統框架的代碼形式:
<w:textField value="#{helloBean.txt}"></w:textField>
可以看出,傳統的開發框架的視圖層是多麼的“強勢”,表面看其來好像是控制層邏輯helloBean決定了頁面上txt的輸出,其實helloBean只是掛了一個控制層的名而已,其幕後還是頁面決定了自己顯示,控制權在自己,如果它不調用#{helloBean.txt},你這個所謂的控制層,不就對視圖失去了控制?並且,這裏用戶還會寫上自己許多的Java片段,JS代碼,EL表達式,各種自定義標籤等等,進一步厄殺了控制層的作用,同時導致其MVC結構慘不忍睹,到後來用戶都不知道頁面複雜到什麼程度了。 那麼在OperaMasks中,情況是如何的呢?OperaMasks2.0提出了一個新的編程思想:IoVC--“Inversion of View-Control”,即“視圖控制反轉”,換言之:它能夠把對“View(即 UI 視圖)的控制力”注入到後面的控制邏輯中。這樣一來,你在編寫控制邏輯的過程中,對 View 擁有足夠的控制力,從而能夠將展現層與控制邏輯,業務邏輯完全的解耦。
例如,OperaMasks2.0下的頁面代碼形式:
@Bind(id=”txt”)
private String txt;
這裏通過Annotation方式,將控制層和頁面的txt控件進行了綁定,而頁面層不知道這個事情,控制頁面的顯示及其內容是由控制層的類來完成的,這個類就是一個LiteBean。

7. hello.xhtml

上面講了環境的配置,也簡單了介紹了一些背景知識,下面我們開始程序的編寫,我們從輸入頁面hello.xhtml入手。
這個頁面比較簡單,一個輸入框,一個按鈕。頁面代碼如下:
 
<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns:f="http://java.sun.com/jsf/core"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:w="http://www.apusic.com/jsf/widget"
        xmlns:ajax="http://www.apusic.com/jsf/ajax"
        xmlns:layout="http://www.apusic.com/jsf/layout"
        renderKitId="AJAX">
     <w:head>
         <w:stylesheet src="/resources/css/example.css" />
    </w:head>
    <w:page title="HelloWorld Example">
    <p/>
    <h1>HelloWorld Example</h1>
    <hr noshade="noshade" />
    <p/>
        <w:form>
             <layout:panelGrid columns="2">
                 <w:textField id="txt"></w:textField>
                 <w:button id="btnSubmit" />
            </layout:panelGrid>
        </w:form>
    </w:page>
</f:view>
 
(1)這裏使用了Css文件,使得頁面更加美觀一些,你可以使用任何自己想要的CSS。
(2)爲了讓兩個控件在一行裏顯示,使用一個佈局組件。
(3)這是一個文本控件,用於你填入文本。
(4)你單擊該控件後,會導航到結果頁面。

8. result.xhtml

結果頁面主要用來顯示你剛纔的輸入:
 
<?xml version="1.0" encoding="UTF-8"?>
<f:view xmlns:f="http://java.sun.com/jsf/core"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:w="http://www.apusic.com/jsf/widget"
        xmlns:ajax="http://www.apusic.com/jsf/ajax"
        xmlns:layout="http://www.apusic.com/jsf/layout"
        renderKitId="AJAX">
    <w:head>
        <w:stylesheet src="/resources/css/example.css" />
    </w:head>
    <w:page title="HelloWorld Example">
    <p/>
    <h3>HelloWorld Example Result</h3>
    <hr noshade="noshade" />
    <p/>
        <w:form>
            <b>Your input is :</b>  
             <h:outputLabel id="message"/>
        </w:form>
    </w:page>
</f:view>
 
(1)輸出信息用的outputLabel控件。

9. HelloBean.java

現在,我們開始編寫我們的後臺控制邏輯層的代碼,首先我們看看控制視圖hello.xhtml的HelloBean的內容:
 
package org.operamasks.example.hello;

import org.operamasks.faces.annotation.Accessible;
import org.operamasks.faces.annotation.Action;
import org.operamasks.faces.annotation.Bind;
import org.operamasks.faces.annotation.Label;
import org.operamasks.faces.annotation.ManagedBean;
import org.operamasks.faces.annotation.ManagedBeanScope;

1@ManagedBean(scope = ManagedBeanScope.SESSION)
public class HelloBean {

2@Bind
3@Accessible
private String txt;

4@Action
5@Label("OK")
public String btnSubmit() {
6return  "view:result";
}
}
(1)@ManagedBean這個Annotation指出,當前這個類HelloBean是個LiteBean(也可稱之爲ManagedBean),這個Bean的作用域範圍是Session,這樣,在整個會話期間都可以訪問這個bean。
(2)@Bind指出,當前的HelloBean需要控制頁面中一個元素,即通過HelloBean中的變量txt來控制頁面中一個id=txt元素。這裏,如果bean的變量和頁面的元素名字不一樣,需要對這個標註增加一個id屬性,來明確告訴AOM2引擎,例如:
@Bind(id="txt")
private String myTxt;
id就是我們在頁面中那個元素的id。
(3)@Accessible的意思是,其他的LiteBean能夠訪問到這個屬性。因爲,我們需要在另外一個LiteBean中訪問HelloBean的txt屬性的值,以便在結果頁面中輸出,所以使用了這個標註。
(4)@Action指出這個方法是個一個事件響應,那有人問了,那這個LiteBean中有可能有許多方法被標註爲@Action,那我又怎麼知道哪個方法響應哪個控件啊? 對,問得好,這裏體現了約定大於配置這麼一條規則,例如,本例中,這個btnSubmit方法被標註爲@Action,如果,這個這個標註沒有指定id,那麼框架會自動尋找視圖中相同的id元素,進行事件的響應,同時,如果沒有指定該標註的event屬性,也會採用約定的事件進行相應。例如,本例的控件是個button,他的默認事件是click事件。比較完整的一個寫法類似如下:
 
@Action(id="bntSubmit",event=”ondbclick”)
public String myFuncation() {
        return "view:result";
}
 
(5)這裏可以決定Button的顯示的內容。
(6)按鈕按下後,我們希望頁面導航到下一個result頁面,因此通過返回view:的方式,告訴AOM2引擎,這個方法過後,需要顯示視圖result。
 

10. ResultBean.java

本例並不是想用最簡單的方式來實現一個HelloWorld,所以可能熟悉OperaMasks2的人,認爲一個HelloBean足以,只要在OperaMasks.xml增加一個配置,讓HelloBean同樣找到result.xhtml,就可以控制那個頁面的顯示了,那種情況確實比較方便,當你熟悉了OperaMasks2之後,自然會去那麼做。
不過這裏,爲了讓思路簡單些,便於入門的理解,這個例子還是針對每個視圖都產生一個後臺的控制邏輯。 我們來看看ResultBean 的代碼編寫:
 
package org.operamasks.example.hello;

import org.operamasks.faces.annotation.BeforePhase;
import org.operamasks.faces.annotation.Bind;
import org.operamasks.faces.annotation.ManagedBean;
import org.operamasks.faces.annotation.ManagedBeanScope;
import org.operamasks.faces.annotation.ManagedProperty;

@ManagedBean(scope = ManagedBeanScope.REQUEST)
public class ResultBean {
     @Bind
     @ManagedProperty("#{HelloBean.txt}")
    private String message;
}
 
(1)這裏設置bean的作用域範圍爲request,表明當前請求範圍內有效,因爲這個頁面時僅在被訪問時,需要顯示內容,不想HelloBean需要把保存起來(Session範圍),以供其他LiteBean調用其值,所以,ResultBean的範圍設置成REQUEST即可。
(2)這個LiteBean需要控制頁面message元素的顯示,利用@Bind進行綁定。
(3)使用這個@ManagedProperty標註的目的是:1,我不需要再增加這個變量的set/get方法。2,並且該標註中的EL表達式,直接作爲該屬性的初始化值。這樣,我們就達到了把HelloBean中的txt的值,即用戶輸入的值傳遞到了第二個LiteBean中,並通過Bind的作用,控制了視圖中id爲txt元素的值的顯示。

11. 打包運行

OK,到這裏,代碼我們也寫完了,把應用打包成war文件,放到tomcat的webapps目錄中就可以。啓動tomcat,啓動瀏覽器,在地址欄中敲入[url]http://localhost:8080/aom-example-hello/hello.jsf[/url]就可以看例子的運行效果了。
 
 
在輸入框中輸入文本,點擊按鈕,會觸發HelloBean的事件響應(HelloBean中的btnSubmit方法),該方法通過返回view:result將視圖導航到下一個結果顯示頁面。
那麼這個結果頁面顯示時,其值是由ResultBean控制的,而該LiteBean在初始化的時候,通過訪問HelloBean的txt屬性獲得了用戶的輸入,並把該值賦給了message變量,頁面上的message元素取得該值,就顯示了用戶的在上一個頁面的輸入。
 

12. 只用HelloBean

有人可能說,這麼簡單的例子搞兩個bean,是不是太麻煩了,如果你實在不願意再多寫一個ResultBean,那麼你也可以這麼做:
  • 輸出頁面(result.xhtml)的txt的id也寫成txt
    <b>Your input is :</b><h:outputLabel id="txt"/>
  • 修改operamasks.xml文件,增加一條,讓你的HelloBean能夠找到result.xhtml
    <view-mapping>
    <url-pattern>/result.xhtml</url-pattern>
    <model-bean>HelloBean</model-bean>
    </view-mapping>
    OK,這樣也就可以不要resultBean來運行了,這種方式下,hello.xhtml和result.xhtml兩個視圖是由同一個控制類HelloBean來進行控制的。
 

13. 有趣的一點

另外順帶提一下,作爲程序員的你,可能對頁面的佈局十分不感冒,當然,本例的頁面十分簡單,不存在這樣的情況,當頁面一複雜,頁面的佈局和設計就不是我們的強項了,而美工則是這方面的專家,傳統的開發模式下,美工對於諸如struts這樣的頁面是不理解的,尤其加入了大量的表達式和代碼片段之後,不僅如此,即使是程序員之間,也存在這樣的問題,記得我剛開始參加革命工作的時候,一次去客戶那裏幫客戶調整頁面,當我打開由上一個程序員編寫的頁面時,我面對的是一片片的雷區,大量的控制邏輯混雜在頁面中,讓我不知道該怎麼修改,一個不小心,就導致頁面不工作了。
OK,讓我們用Dreamweaver來開發這個頁面,看情況如何?
  • 首先使用一個網頁編輯器,例如Dreamweaver來進行頁面的設計:
  • 設計時,記得組件都要設置一個id屬性,然後,使用一個jsfc屬性來標記這個組件實際運行時所代表的AOM組件,例如:
    <?xml version="1.0" encoding="UTF-8"?>
    <f:view xmlns:f="http://java.sun.com/jsf/core"
            xmlns="http://www.w3.org/1999/xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:w="http://www.apusic.com/jsf/widget"
            xmlns:ajax="http://www.apusic.com/jsf/ajax"
            xmlns:layout="http://www.apusic.com/jsf/layout"
            renderKitId="AJAX">
        <w:head>
            <w:stylesheet src="/resources/css/example.css" />
        </w:head>
        <w:page title="HelloWorld Example">
        <p/>
        <h1>HelloWorld Example Using Dreamwave </h1>
        <hr noshade="noshade" />
        <p/>
            <w:form>
                 <label>
                    <input type="text" id="txt" jsfc="w:textField" name="textfield" />
                </label>
                <label>
                   <input type="submit" name="Submit" id="btnSubmit" jsfc="w:button"/>
                </label>
            </w:form>
        </w:page>
    </f:view>
    (1)form中的內容是由美工在其他網頁編輯環境中編輯的,可以看到這些元素是標準的html元素。
  • 寫好這個頁面後,直接放入應用中,在瀏覽器中敲入[url]http://localhost:8080/aom-example-hello/hello_dreamwave.jsf[/url]看看實際運行的效果:
竟然一樣可以運行。是不是有點意思,這樣以後你和美工MM的工作將會變得更加愉快了。對了,因爲你的頁面改成了hello_dreamave.xhtml,默認約定是HelloBean能夠找到hello.xhtml,爲了讓後臺的控制邏輯(HelloBean)能夠找到你這個頁面進行控制,別忘了在operamasks.xml中增加一個配置:
 
<view-mapping>    
<url-pattern>/hello_dreamwave.xhtml</url-pattern>    
<model-bean>HelloBean</model-bean></view-mapping>

14. 示例應用的運行包及代碼

Tomcat版本:aom-example-hello(for-tomcat).zip,裏面包含了源代碼。
其他參考文件:
1.Apusic版本:aom-example-hello(for-apusic).zip(需要Apusic5.1tp5版本),如果你下載的是Apusic5.1tp4,則把最新的AOM解壓後的包,放入Apusic安裝目錄下的lib目錄中。
2.空的war包:aom-example-blank.war
3.Tomcat下運行應用時需要的:javaee.jar
4.OperaMasks官方網站:[url]www.operamasks.org[/url]
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章