Spring Web Flow為JSF開發人員提供了什麼

工程 | Keith Donald | 2007年4月21日 | ...

Spring Web Flow,很像Spring Framework本身,是一種獨特的整合技術。我們的大多數使用者將其視為一個通用的ApplicationController,可以嵌入到任何環境中。我們支援基於Servlet和Portlet的應用程式,並提供了與領先的Web框架Struts、Spring MVC和Java Server Faces的整合。我甚至知道有團隊在Flex環境中使用Spring Web Flow。在這些環境中,Spring Web Flow都整合為導航邏輯實現和應用程式狀態管理提供了更好的模型。

我們的使用者喜歡這樣做,因為他們可以編寫一次控制流並在任何地方重用它。在這個動態變化的 Web 框架時代,Spring Web Flow 為他們提供了一個統一的現代框架,可以學習和構建相關的知識、工具和擴充套件。從一開始,它就被設計成扮演這個角色,我非常高興地看到 Web Flow 在多個層面上不斷發展和整合。

我們的整合正在不斷增長的一個重要領域是與 Java Server Faces (JSF) 社群的合作。從 Spring Web Flow 1.0.3 開始,我們的 JSF 整合已經達到了 Spring 社群所期望的水平,並滿足了實際工作中 JSF 開發人員最迫切的需求。本部落格將詳細介紹整合增強功能,向您展示 Spring Web Flow 為 JSF 開發人員帶來的不同之處。

契合度

Spring Web Flow 是一個控制器框架,提供了一種在 Web 應用程式中實現使用者介面控制流的語言和執行時。 Java Server Faces 是一個使用者介面元件框架,它包含一個標準 API 和兩個實現——Sun 參考實現和 Apache MyFaces。作為 JCP 支援的標準 API 規範,JSF 提供了擴充套件點,允許產品供應商插入並憑藉其擴充套件進行競爭。當作為 JSF 擴充套件使用時,Spring Web Flow 接管了兩項職責:處理檢視導航規則和管理與持續使用者互動(也稱為會話)相關的狀態。這種整合將 Web Flow 在導航和狀態管理方面的優勢與 JSF 作為不斷發展的使用者介面元件庫生態系統的優勢結合起來。所有 JSF 元件和檢視在 Web Flow 整合後仍可正常工作。有了 Web Flow,JSF 開發人員可以受益於一個功能強大得多的導航模型,該模型可以緩解傳統上手動管理會話狀態的痛點。

我可以繼續詳細介紹 Web Flow 的特定功能集。但與其這樣做,我將嘗試重點介紹對 JSF 開發人員影響最大的功能。

在導航處理領域,Web Flow 提供了

  • 能夠實現動態導航規則,這些規則可以隨時更改,無需伺服器重啟
  • 在流程定義語言中內建了完整的向前、向後、重新整理、重定向和遞迴導航功能
  • 透過流程定義概念實現導航邏輯的模組化和封裝

基本上,Web Flow 解決了這位可憐的靈魂在使用 JSF 的基本導航功能時遇到的所有問題。正如我們的一位資深使用者所指出的,Web Flow 可以完全取代 JSF 的預設“以轉發為中心”的導航模型。

Jeremy Grelle:我一直在將 SWF 用作 JSF 導航規則的完全替代品,即使是對於我們更簡單的頁面和選單。我很高興能夠走到這一步,因為對於我的團隊來說,在多個地方定義導航規則會有點太混亂了。

在狀態管理領域,Web Flow 引入了幾個會話範圍,它們是對 JSF 現有的請求、會話和應用程式範圍的補充。這些範圍是

  • 會話範圍 - 一個託管範圍,其生命週期持續到使用者對話結束
  • 流程範圍 - 一個託管範圍,其生命週期持續到會話中執行的流程結束
  • Flash 範圍 - 一個託管範圍,其生命週期持續到參與流程的檢視結束
這些範圍是“託管”的,因為 Web Flow 會自動為您清理它們。會話範圍非常適合儲存模型狀態,以便在使用者互動(如賬戶註冊嚮導)結束時持久化。Flash 範圍已被證明對使用 Ajax 庫(如 Ajax4JSF 和 ICEFaces)的使用者非常有用,在這些庫中,來自同一檢視的多個請求是常態。在這種情況下,Flash 範圍允許跨來自同一頁面的細粒度 Ajax 請求操作模型狀態,然後在下次導航時自動清除。

回到我們資深使用者的話

Jeremy Grelle:我發現即使使用 JSF 的簡單頁面,您通常也需要一些東西來管理您的模型在頁面多個請求之間的狀態……JSF 社群中存在許多解決此問題的方法(Tomahawk 的 saveState 標籤、Shale 的對話方塊架等),但我個人認為 SWF 的多個範圍是最健壯和最優雅的解決方案。

方法

希望到目前為止,您對 Web Flow 作為 JSF 擴充套件提供的功能有了很好的瞭解。現在,我想更詳細地介紹一下整合的工作原理,然後展示如何開始將 Web Flow 和 JSF 一起使用。

要理解 Web Flow 如何整合到 JSF 中,首先需要了解 Web Flow 的基本構造。Spring Web Flow 中控制器功能的單元——例如賬戶註冊嚮導或客戶主/詳細資訊編輯器——稱為流程定義。此類控制器的執行時例項稱為流程執行。在執行時啟動新的流程執行,以允許單個使用者參與應用程式的對話。流程執行負責選擇使用者的初始檢視,然後響應使用者事件來執行應用程式行為並確定要顯示的下一個檢視。它還管理與使用者對話相關的狀態。

將 Web Flow 與 JSF 整合的一個重要部分是將流程執行生命週期融入 JSF 生命週期。這部分是透過實現一個自定義 PhaseListener 來實現的,該監聽器負責在客戶端請求時啟動新的流程執行,以及在 JSF 檢視恢復期間恢復現有的流程執行。

例如,透過訪問一個 URL,如


https://:8080/accounts/servlet.faces?_flowId=register-account-flow

...您將啟動一個新的“register-account-flow”。請求首先到達 FacesServlet,然後啟動 JSF 生命週期。在任何檢視恢復之前,FlowPhaseListener 會啟動“register-account-flow”,該流程最終確定要顯示的初始 JSF 檢視。

一旦選擇了初始 JSF 檢視,它就會被渲染。渲染通常發生在 Spring Web Flow 的預設“始終在暫停時重定向”設定的自動重定向之後,該設定將選定的檢視與一個 URL 相關聯,該 URL 可以安全地重新整理並在稍後返回,而不會出現瀏覽器警告。

當發生渲染時,JSF UI 元件可以完全訪問在 Web Flow 的任何會話範圍中管理的 Bean,以及訪問您的標準 JSF 會話和應用程式範圍。元件值繫結是透明的,這意味著 JSF 檢視開發人員不需要知道 Bean 在哪個範圍中管理,他們只需要知道 Bean 的名稱。此功能是透過實現另一個 JSF 擴充套件點——一個自定義 VariableResolver——來實現的。

在參與流程執行的檢視渲染之後,使用者決定要做什麼。如果她決定單擊瀏覽器重新整理按鈕,那也沒關係——流程執行會在其穩定的 URL 上重新整理,並且相同的 JSF 檢視會重新渲染。如果她決定執行一些觸發同一頁面的 Ajax 請求的操作,那也沒關係——流程執行會再次自動恢復,並且參與 Ajax 呼叫的 JSF 元件可以以執行緒安全的方式無縫地更新流程管理的 State(無雙關之意)。

一旦使用者決定呼叫 UI 命令,例如透過單擊命令連結,標準的 JSF 回發生命週期就會啟動。在處理完 UI 元件驗證和更新模型值之後,JSF 操作結果會被視為一個事件,針對恢復的流程執行的檢視狀態發出。然後,流程將接管,透過呼叫適當的應用程式行為並根據流程定義的導航規則選擇下一個檢視來處理該事件。此 Web Flow 導航步驟由 JSF 整合中的最後一個關鍵構造——一個自定義 NavigationHandler——來處理。

總而言之,從 JSF 檢視和元件開發者的角度來看,這只是標準的 JSF——無論您使用的是 JSP 還是帶有 XYZ 元件提供商的 Facelets,這都沒關係。Web Flow 執行會自動為您恢復,並且對會話狀態的訪問完全透明。Web Flow 事件只是標準的 JSF UI 命令結果。從控制器開發者的角度來看,一切都是 Web Flow。因此,faces-config.xml 中冗長且受限的導航規則被模組化、簡潔的流程定義所取代,這些定義基於更豐富的流程定義語言。最終,您將獲得原生 JSF 元件模型的所有優勢,以及 Web Flow 導航模型的所有優勢。

入門

在 JSF 環境中開始使用 Spring Web Flow 的最佳方法是下載 1.0.3 版本並部署 sellitem-jsf 示例,該示例也可在網上進行測試。該示例可作為 Eclipse Dynamic Web Project 匯入,以便在 Eclipse 中輕鬆部署。此外,該示例支援 Spring IDE 2.0,這是一個 Eclipse 外掛,其中包括一個圖形化 Web Flow 編輯器

為了結束本文,我將簡要介紹如何在 JSF 環境中使用 sellitem-jsf 示例開始使用 Web Flow。

設定 Faces Config(樣板程式碼)

要整合 Web Flow,必須將上述自定義整合構件新增到 faces-config.xml 中。


<application>
    <navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler>
    <variable-resolver>org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver</variable-resolver>
</application>

<lifecycle>
    <phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener>
</lifecycle> 
編寫流程定義(核心)

然後,您需要定義您的控制器邏輯的流程定義。這是“sellitem”流程定義,這是一個 4 步結賬流程,帶有一個動態導航規則,最終以確認銷售交易結束。


<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">

	<var name="sale" class="org.springframework.webflow.samples.sellitem.Sale" scope="conversation" />

	<start-state idref="enterPriceAndItemCount" />

	<view-state id="enterPriceAndItemCount" view="/priceAndItemCountForm.jsp">
		<transition on="submit" to="enterCategory"/>
	</view-state>

	<view-state id="enterCategory" view="/categoryForm.jsp">
		<transition on="submit" to="requiresShipping" />
	</view-state>

	<decision-state id="requiresShipping">
		<if test="${conversationScope.sale.shipping}" then="enterShippingDetails" else="processSale" />
	</decision-state>

	<view-state id="enterShippingDetails" view="/shippingDetailsForm.jsp">
		<transition on="submit" to="processSale" />
	</view-state>

	<action-state id="processSale">
		<bean-action bean="saleProcessor" method="process">
			<method-arguments>
				<argument expression="conversationScope.sale" />
			</method-arguments>
		</bean-action>
		<transition on="success" to="showCostOverview" />
	</action-state>

	<end-state id="showCostOverview" view="/costOverview.jsp" />

</flow>
設定 Web Flow Config(樣板程式碼)

流程定義應在登錄檔中註冊,以便它們可以執行。


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:flow="http://www.springframework.org/schema/webflow-config"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd">

	<!-- Launches, continues, and refreshes flow executions -->
	<flow:executor id="flowExecutor" registry-ref="flowRegistry"/>
	
	<!-- Creates the registry of flow definitions eligible for execution in this application -->
	<flow:registry id="flowRegistry">
		<flow:location path="/WEB-INF/flows/sellitem-flow.xml" />
	</flow:registry>

</beans>
啟動流程執行

註冊後,只需將瀏覽器指向 FacesServlet 並將流程識別符號作為輸入即可啟動流程。


https://:8080/sellitem-jsf/servlet.faces?_flowId=sellitem-flow

值得注意的是,您可以配置流程定義和執行 URL 的格式——例如,啟用 REST 風格的 URL,而不是預設的基於請求引數的 URL。

實現 JSF 檢視

如前所述,JSF 檢視只是普通的 JSF 檢視,無論是基於 JSP 還是 Facelet 的,它們都具有標準的 JSF 繫結表示式來訪問會話狀態,以及標準的 UI 命令來發出 Web Flow 事件。sellitem-jsf 示例使用基於 JSP 的檢視。


<f:view>
<div id="content">
	<h2>Enter price and item count</h2>
	<hr>
	<table>
		<h:form id="priceAndItemCountForm">
			<tr>
				<td>Price:</td>
				<td>
					<h:inputText id="price" value="#{sale.price}" required="true">
					  <f:validateDoubleRange minimum="0.01"/>
					</h:inputText>
				</td>
				<td>
					<h:message for="price" errorClass="error"/>
				</td>
			</tr>
			<tr>
				<td>Item count:</td>
				<td>
					<h:inputText id="itemCount" value="#{sale.itemCount}" required="true">
					  <f:validateLongRange minimum="1"/>
					</h:inputText>
				</td>
				<td>
					<h:message for="itemCount" errorClass="error"/>
				</td>
			</tr>
			<tr>
				<td colspan="2" class="buttonBar">
					<h:commandButton type="submit" value="Next" action="submit"/>
				</td>
				<td></td>
			</tr>
		</h:form>
	</table>
</div>
</f:view>

就這樣!您可以試用該應用程式,親自看看 Web Flow 如何處理導航和應用程式控制器邏輯,而 JSF UI 元件則負責內容渲染以及資料繫結和驗證行為。這確實是一個絕佳的組合。

未來

我們並非偶然達到這一點,而是透過與客戶日常合作,在我們的論壇和支援中心使用 Spring Web Flow 和 JSF 構建應用程式才得以實現。特別感謝 Jeremy Grelle、James Clinton、Ed Burns、Craig McClanahan 和 Colin Sampaleanu 為 Spring Web Flow JSF 整合所做的貢獻——它現在非常穩定。

Spring Web Flow 1.1 的開發已經開始,更高級別的整合是其令人興奮的路線圖中的一個主要主題。在 JSF 方面,值得注意的是,我們將支援在流程定義中使用統一表達式語言 (EL),並支援利用 Spring 2.0 作為 JSF 管理 Bean 的全面提供商,覆蓋所有範圍——包括 Spring Web Flow 提供的會話範圍。這項工作以及為所有環境的 Web Flow 使用者帶來好處的新核心功能,例如對會話範圍持久化上下文的支援。請參與論壇上的1.1 路線圖討論,以獲取更多資訊並參與其中!

我想借此機會鼓勵那些已經在 JSF 環境中使用 Spring Web Flow 的人分享您的經驗——給我發郵件,在這裡發表評論,在 JSF 中心寫文章,告訴 JSF 社群的領導者您的經驗。您的實際經驗可以幫助影響 JSF 2.0 規範的方向,因為該規範的負責人已經徵求了社群反饋。Interface21 已收到 JSF 規範負責人 Ed Burns 的邀請,加入 JSF 2.0 專家組,這認可了 Web Flow 作為創新 JSF 擴充套件的貢獻。我們已接受邀請,並熱衷於將已被證明在導航和狀態管理方面行之有效的方法回饋給 JSF 2.0,同時繼續開闢新領域並保持在任何環境中的可用性。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有