整合JSF與BEEHIVE PAGE FLOW

來源:互聯網
上載者:User
js   JSF對通過關聯組件和事件來構建頁面而說是非常棒的,但是,與所有現有的技術一樣,它需要一個控制器來分離出頁面間的導航決策,並提供到業務層的連結。它擁有一個基本的導航處理常式,可以用功能完備的處理常式來替換它。Page Flow為建立可重用的封裝頁面流提供了基礎,並可以與視圖層並行工作。它是一個功能完備的導航處理常式,將JSF頁面作為最優先的處理對象。本文將討論如何整合這兩種技術來利用二者的優點。

  構建Beehive/JSF應用程式

  要構建Beehive/JSF應用程式,首先要啟動Page Flow,然後添加對JSF的支援。起點是從基本的支援NetUI(Beehive中包含Page Flow的組件)的項目開始。根據指導構建基本的支援NetUI的Web應用程式。在本文中,我們暫且稱之為“jsf-beehive”,可以在 http://localhost:8080/jsf-beehive 上獲得。

  接下來,安裝並配置JSF。Page Flow可以使用任何與JavaServer Faces 1.1相容的實現,並針對兩種主流實現進行了測試:Apache MyFaces和JSF Reference Implementation。根據下面的指導在新的Web應用程式中安裝JSF:MyFaces v1.0.9及更高版本,JSF Reference Implementation v1.1_01,或者其他實現。之後,可以使用WEB-INF/faces-config.xml中的一個簡單入口啟動Page Flow整合,入口在<application>標籤之下,<navigation-rule>標籤之上:

<factory> <application-factory>  org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory </application-factory></factory>

  添加了這些就為頁面流提供了一個機會,使其可以提供自己的JSF架構對象版本來定製其行為。通常來說,只有在使用頁面流功能的時候,JSF行為才會被修改;JSF的基本行為不會改變。

  基本整合

  JSF中頁面流的最基本用處是引發(調用)來自JSF頁面的動作。JSF頁面可以處理頁面內事件,而頁面流動作則是從一個頁面導航到另一頁面的方法。首先,在Web應用程式中建立一個名為“example”的目錄,在其中建立一個頁面流量控制器類:

package example;import org.apache.beehive.netui.pageflow.Forward;import org.apache.beehive.netui.pageflow.PageFlowController;import org.apache.beehive.netui.pageflow.annotations.Jpf;@Jpf.Controller(  simpleActions={    @Jpf.SimpleAction(name="begin", path="page1.faces")  })public class ExampleController extends PageFlowController{  @Jpf.Action(    forwards={      @Jpf.Forward(name="success", path="page2.faces")    }  )  public Forward goPage2()  {    Forward fwd = new Forward("success");    return fwd;  }}

  在這個頁面流中有兩個動作:跳轉到page1.faces的begin動作和跳轉到page2.faces的goPage2動作。將goPage2作為一個方法動作(而不是簡單動作)的原因是稍後將會對其進行擴充。

  在構造頁面的時候,應當以.jsp為副檔名建立page1和page2;JSF servlet處理每個.faces請求,並最終跳轉到相關的JSP。所以,跳轉到page1.faces最終將顯示page1.jsp,如下:

<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %><%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <html> <body>   <f:view>     <h:form>       <h:panelGrid>         <h:outputText value="Page 1 of page flow #{pageFlow.URI}"/>         <h:commandLink action="goPage2" value="Go to page 2"/>       </h:panelGrid>     </h:form>   </f:view> </body></html>

  從JSF頁面引發一個動作很簡單:使用命令組件的action屬性中的動作名字就可以了。在上面的例子中,commandLink指向goPage2動作。使用頁面流整合,這意味著goPage2動作會在example.ExampleController中運行。

  就是這樣。要實驗的話,構建應用程式,點擊 http://localhost:8080/jsf-beehive/example/ExampleController.jpf ,這將通過begin動作跳轉到page1.faces。單擊連結“Go to page 2”,會引發goPage2動作並跳轉到page2.faces。

  後台Bean

  Page Flow架構可以管理與JSF頁面相關的後台bean(backing bean)。該類是放置與頁面相關的事件處理常式和狀態的方便場所。可以把它看作是集中放置與頁面互動時所啟動並執行所有代碼的單一場所。當點擊一個JSF頁面時,Page Flow會判斷是否有具有同樣名稱和包的類,例如,page /example/page1.faces的example.page1類。如果存在這樣的類,並且它用@Jpf.FacesBacking進行注釋並擴充了FacesBackingBean,它就會建立該類的一個執行個體。當離開JSF頁面而轉到一個動作或者其它任何頁面時,後台bean會被銷毀。後台bean與JSF頁面共存亡。

  綁定到後台bean中的屬性

  下面是page1.faces的一個非常簡單的後台bean,以及屬性someProperty。檔案名稱是page1.java:

package example;import org.apache.beehive.netui.pageflow.FacesBackingBean;import org.apache.beehive.netui.pageflow.annotations.Jpf;@Jpf.FacesBackingpublic class page1 extends FacesBackingBean{  private String _someProperty = "This is a property value from"                                  + getClass().getName() + ".";  public String getSomeProperty()  {      return _someProperty;  }  public void setSomeProperty(String someProperty)  {      _someProperty = someProperty;  }}

  在JSF頁面(page1.jsp)中,可以利用backing綁定上下文來綁定到這個屬性:

  <h:outputText value="#{backing.someProperty}"/>

  上面的例子顯示了someProperty(最終在後台bean上調用getSomeProperty())的值。類似地,設定這個值:

  <h:inputText value="#{backing.someProperty}"/>

  注意,在這個例子中,後台bean中沒有出現事件處理常式或組件引用。這就縮短了代碼;後台bean是放置頁面所有的處理常式和組件引用的好地方。

  從後台bean引發頁面流動作

  在上面的“基本整合”部分,我們直接從JSF組件引發頁面流動作。通常情況下,只需這樣即可;當單擊一個按鈕或者連結時,會運行一個動作並跳轉到另一個頁面上。如果想在調用控制器之前運行一些與頁面相關的代碼,或者如果希望頁面可以在幾個動作之間進行動態選擇的話,可以在命令處理常式(JSF頁面所啟動並執行一個Java方法)中引發一個動作。下面是一個命令處理常式的例子,可以把它放到後台bean page2.java中(或者其它任何可公開訪問的bean中):

public StringchooseNextPage(){  return "goPage3";}

  這是一個非常簡單的命令處理常式,它選擇了goPage3動作。可以用標準的JSF方式從一個JSF命令組件綁定到這個命令處理常式:

<h:commandButton action="#{backing.chooseNextPage}"                  value="Submit"/>

  當單擊連結時,會運行chooseNextPage命令處理常式,它會選擇引發goPage3動作。還可以對命令處理常式方法使用一個特殊的頁面流注釋——@Jpf.CommandHandler:

@Jpf.CommandHandler( raiseActions={      @Jpf.RaiseAction(action="goPage3") })public String chooseNextPage(){ return "goPage3";}

  該注釋使支援Beehive的工具可以知道命令處理常式引發了後台bean中的哪個動作,並允許擴充JSF動作處理的能力(參見下面“從JSF頁面向頁面流發送資料”部分)。

  從後台bean訪問當前頁面流或共用流

  在某些情況下,您或許想直接從後台bean訪問當前頁面流或一個活動的共用流。為此,只需建立一個適當類型的欄位,並使用@Jpf.PageFlowField或@Jpf.SharedFlowField對其進行適當注釋:

@Jpf.CommandHandler( raiseActions={      @Jpf.RaiseAction(action="goPage3") })public String chooseNextPage(){ return "goPage3";}

  這些欄位將在建立後台bean的時候被初始化。無需手動對其進行初始化。下面的例子使用了自動初始化的ExampleController欄位。在這個例子中,“show hints”單選鈕的事件處理常式在頁面流中設定了一個普通優先順序。

@Jpf.PageFlowFieldprivate ExampleController myController;@Jpf.SharedFlowField(name="sharedFlow2") // "sharedFlow2" is a                               // name defined in the                              // page flow controllerprivate ExampleSharedFlow mySharedFlow;

  在很多情況下,頁面不需要直接與頁面流或者共用流進行互動;使用其它方法從頁面流向JSF頁面傳遞資料就足夠了,反之亦然。下面我將給出一些例子。

  從頁面流量控制器訪問後台bean

  您不能從頁面流量控制器訪問後台bean!至少,這不容易做到,這是有意為之的。後台bean與JSF頁面緊密相關,當您離開頁面的時候,後台bean會被銷毀。正如頁面流量控制器不應瞭解頁面細節一樣,它也不應瞭解後台bean。當然了,可以從後台bean向控制器傳遞資料(稍後將會介紹),甚至可以傳遞後台bean執行個體本身,但是在大多數情況下,後台bean的內容是不應當泄露給控制器的。

  生命週期方法

  通常,當後台bean發生某些事情的時候,比如當它被建立或銷毀時,我們希望能運行代碼。在Page Flow架構的生命週期中,它會對後台bean調用一些方法:

  • onCreate():建立bean時
  • onDestroy():銷毀bean時(從使用者會話移除)
  • onRestore():這個需要詳細解釋一下。我說過,當您離開頁面的時候,後台bean會被銷毀。在大多數情況下是這樣的,但是如果頁面流使用了navigateTo特性(它使您可以再次訪問先前顯示的頁面),在您離開頁面之後,Page Flow架構會保留後台bean一小段時間,以防它需要還原。當通過@Jpf.Forward或@Jpf.SimpleAction使用navigateTo=Jpf.NavigateTo.currentPage或navigateTo=Jpf.NavigateTo.previousPage還原一個JSF頁面時,頁面的組件樹及其後台bean都被Page Flow架構還原。當這種情況發生時,onRestore()就被調用。

  不管要在哪個時期運行代碼,只需重寫適當的方法:

protected void onCreate(){ /*some create-time logic */}

  當重寫這些方法時,不需要調用空的super版本。

  在JSF頁面和頁面流之間傳遞資料

  現在我們該看看如何在JSF頁面和頁面流之間傳遞資料了。

  從頁面流向JSF頁面發送資料

  通常,您會想要利用頁面流的資料來初始化一個頁面。為此,可以向page2.faces的Forward添加“action outputs”:

@Jpf.Action( forwards={  @Jpf.Forward(    name="success", path="page2.faces",    actionOutputs={      @Jpf.ActionOutput(name="message", type=String.class,required=true)    }  ) })public Forward goPage2(){  Forward fwd = new  Forward("success");   fwd.addActionOutput("message", "Got the message.");  return fwd;}

  做完這些之後,可以直接從JSF頁面或者後台bean將該值作為頁面輸入來訪問。(如果您不喜歡鍵入冗長的注釋,可以省去斜體的。它們主要用於再次檢查添加的物件類型是否正確,確定不缺失類型。)

  可以在頁面中利用JSF表示語言中的頁面流pageInput綁定上下文綁定到這個值:

<h:outputText value="#{pageInput.message}"/>

  注意,可以利用pageFlow和sharedFlow綁定上下文綁定到頁面流量控制器自身或者任何可用的共用流的屬性:

<h:outputText value="#{pageFlow.someProperty}"/><h:outputText value="#{sharedFlow.mySharedFlow.someProperty}"/>

  最後,要想從後台bean訪問頁面輸入,只需在bean類代碼中的任意地方調用getPageInput:

String message = (String) getPageInput("message");

  從JSF頁面向頁面流發送資料

  還可以隨著頁面流所引發的動作發送資料。很多動作將要求表單bean作為輸入;通常,表單bean用於從頁面擷取資料送到控制器。首先,讓我們構建一個動作來接收表單bean並跳轉到頁面:

@Jpf.Action(   forwards={       @Jpf.Forward(name="success", path="page3.faces")   })public Forward goPage3(NameBean nameBean){    _userName = nameBean.getFirstName() + ' ' +                 nameBean.getLastName();    return new Forward("success");}

  該動作包含一個NameBean,它是一個將getters/setters作為其firstName和lastName屬性的表單bean類。它設定一個成員變數儲存完整名字,之後跳轉到page3.faces。我們知道,可以直接從JSF頁面或者它的後台bean引發一個動作。在這兩種情況下,都可以向動作發送表單bean。下面讓我們依次看看每種情況。

  從後台bean發送表單bean

  要從後台bean中的命令處理常式發送表單bean,需要使用一個特定的注釋。下面給出了page2.java中的情況:

private ExampleController.NameBean _nameBean;protected void onCreate(){    _nameBean = new ExampleController.NameBean();}public ExampleController.NameBean getName(){    return _nameBean;}@Jpf.CommandHandler(    raiseActions={        @Jpf.RaiseAction(action="goPage3",              outputFormBean="_nameBean")    })public String chooseNextPage(){    return "goPage3";}

  在這個例子中,JSF頁面可以用它選擇的任何方式填充_nameBean的值(例如,通過將h:inputText值綁定到#{backing.name.firstName}和#{backing.name.lastName})。之後它使用@Jpf.RaiseAction上的outputFormBean屬性來標記_nameBean應當被傳遞到動作goPage3。

  從JSF頁面發送表單bean

  從JSF頁面直接發送表單bean很容易,只要您可以通過資料繫結運算式得到bean值。這是通過在commandButton組件內部添加名為submitFormBean的h:attribute組件來實現的:

<h:commandButton action="#{backing.chooseNextPage}"                  value="Submit directly from page">    <f:attribute name="submitFormBean" value="backing.name" /></h:commandButton>

  在這裡,為了使表單bean發送到動作goPage3,按鈕綁定到後台bean的“name”屬性(getName)。

  結束語

  本文展示了如何將JSF在構建頁面方面的豐富特性與Beehive Page Flow在控制頁面間導航方面的強大功能相結合。二者的整合非常容易,但是卻會對應用造成深遠的影響:它將JSF頁面與應用級邏輯相分離,並把頁面帶入Page Flow所提供的功能領域中。JSF頁面得到了清楚的任務:作為單個(如果有足夠能力的話)視圖元素參與到應用程式的流中。文中沒有展示JSF頁面中具有事件處理功能且控制器中具有複雜的導航邏輯的完備應用程式。但是隨著應用程式的複雜程度提高,它就會更加需要責任的劃分以及頁面流添加給JSF的進階流功能。您可以花幾分鐘嘗試一下——很快您就將意識到這樣做所帶來的好處。



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。