多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > php框架 > 框架設計 > 《Spring實戰(zhàn)》學習筆記-第八章:使用Spring Web Flow

《Spring實戰(zhàn)》學習筆記-第八章:使用Spring Web Flow

來源:程序員人生   發(fā)布時間:2016-06-22 08:55:44 閱讀次數(shù):3839次

第4版的第8章內容與第3版基本1致。

本章內容:

  • 創(chuàng)建會話式web利用程序
  • 定義流程狀態(tài)和行動
  • 保護web流程

互聯(lián)網的1個奇特的地方就在于它很容易讓人迷失。有如此多的內容可以查看和瀏覽,而超鏈接是其強大魔力的核心所在。

有時候,web利用程序需要控制web沖浪者的導向,引導他們1步步地訪問利用。比如電子商務網站的付款流程,從購物車開始,利用程序會引導你順次經過配送詳情、賬單信息和終究的定單確認。

Spring Web Flow是1個web框架,它適用于元素規(guī)定流程運行的程序。本章中,我們將會探索它是如何用于Spring Web框架平臺的。

其實我們可使用任何的Web框架編寫流程化的利用程序,比如使用Struts構建特定的流程。但是這樣沒有辦法將流程與實現(xiàn)分開,你會發(fā)現(xiàn)流程的定義分散在組成流程的各個元素中,沒有特定的地方能夠完全地描寫全部流程。

Spring Web Flow是Spring MVC的擴大,它支持開發(fā)基于流程的利用程序,可以將流程的定義和實現(xiàn)流程行動的類和視圖分離開來。

在介紹Spring Web Flow的時候,我們會暫且放下Spittr樣例,而使用生產披薩定單的web程序。

使用的第1步是在項目中進行安裝,那末就從安裝開始吧。

在Spring中配置Spring Web Flow

Spring Web Flow是基于Spring MVC構建的,這就意味著所有的流程要求都需要經過Spring MVC的DispatcherServlet。我們需要在Spring利用上下文中配置1些Bean來處理流程要求并履行流程。

現(xiàn)在還沒有支持使用Java來配置Spring Web Flow,所以沒得選,只能在XML中進行配置。有1些Bean會使用Spring Web Flow的Spring配置文件命名空間來進行聲明,因此我們需要在上下文定義XML文件中添加相應的命名空間:

<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" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config⑵.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans⑶.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context⑶.0.xsd">

聲明了命名空間后,就能夠準備裝配Web Flow的Bean了。

編寫流程履行器

顧名思義,流程履行器(flow executor )就是用來驅動流程的履行。當用戶進入到1個流程時,流程履行器會為該用戶創(chuàng)建并啟動1個流程履行器的實例。當流程暫停時(例如為用戶展現(xiàn)視圖時),流程履行器會在用戶履行操作后恢復流程。

在Spring中,元素可以創(chuàng)建1個流程履行器:

雖然流程履行器負責創(chuàng)建和履行流程,但它其實不負責加載流程定義。這個要由流程注冊表(flow registry)負責,下面會創(chuàng)建它。

配置流程注冊表

流程注冊表的工作就是加載流程定義,并讓流程履行器可使用它們。可以在Spring中使用進行配置:

<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows"> <flow:flow-location-pattern value="/**/*-flow.xml" /> flow:flow-registry>

正如這里聲明的,流程注冊表會在/WEB-INF/flows目錄下尋覓流程定義,這個路徑是由base-path屬性指明的。根據(jù)元素,任何以-flow.xml結尾的XML文件都會被視為流程定義。

所有的流程都是通過其ID來進行援用的。使用元素,流程的ID就是相對base-path的路徑,或是雙星號所代表的路徑,以下圖展現(xiàn)了流程ID是如何計算的:
在使用流程定位模式時,流程定義文件相對于基本路徑的路徑將用作流程的id

另外,你也能夠不使用base-path屬性,直接顯式地聲明流程定義文件的位置:

<flow:flow-registry id="flowRegistry"> <flow:flow-location path="/WEB-INF/flows/springpizza.xml" /> flow:flow-registry>

這里使用了而不是,path屬性直接指定了/WEB-INF/flows/springpizza.xml為流程定義文件。當這樣定義時,流程的ID是從流程定義文件的文件名中獲得的,這就是springpizza。

如果你希望更顯示地指定流程ID,那末可以通過元素的id屬性來進行設置。例如,要設定pizza作為流程ID,可以這樣進行配置:

<flow:flow-registry id="flowRegistry"> <flow:flow-location id="pizza" path="/WEB-INF/flows/springpizza.xml" /> flow:flow-registry>

處理流程要求

正如前面的章節(jié)中提到的,DispatcherServlet會將要求分發(fā)給控制器,但是對流程而言,你需要FlowHandlerMapping來幫助DispatcherServlet將流程要求發(fā)送給Spring Web Flow。FlowHandlerMapping的配置以下:

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> <property name="flowRegistry" ref="flowRegistry" /> bean>

FlowHandlerMapping裝配了注冊表的援用,這樣它就知道如何將要求的URL匹配到流程上。例如,如果有1個ID為pizza的流程,F(xiàn)lowHandlerMapping就會知道如果要求的URL是/pizza的話,就會將其匹配到這個流程上。

但是,F(xiàn)lowHandlerMapping的工作僅僅是將流程要求定向到Spring Web Flow,響應要求的是FlowHandlerAdapter,它同等于Spring MVC的控制器,會對流程要求進行響應并處理。FlowHandlerAdapter可以像下面這樣裝配成1個Spring Bean:

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> <property name="flowExecutor" ref="flowExecutor" /> bean>

這個處理適配器就是DispatcherServlet和Spring Web Flow之間的橋梁。它會處理流程要求并管理基于這些要求的流程。在這里,它裝配了流程履行器的援用,而后者是為要求履行流程的。

現(xiàn)在已配置了Spring Web Flow所需的Bean和組件,下面所需的就是真實的定義流程了。首先了解下流程的組成元素。

流程組件

在Spring Web Flow中,流程是由3個主要元素組成的:狀態(tài)(state)、轉移(transition)和流程數(shù)據(jù)(flow data)。狀態(tài)是流程中事件產生的地點。如果將流程想象成公路旅行,那末狀態(tài)就是路途上的城鎮(zhèn)、路邊飯店和風景點等。流程中的狀態(tài)是業(yè)務邏輯履行、做出決策或將頁面展現(xiàn)給用戶的地方,而不是在公路旅行中買薯片或可樂這些行動。

如果說流程狀態(tài)是公路上停下來的地點,那末轉移就是連接這些點的公路。在流程上,需要通過轉移從1個狀態(tài)到達另外一個狀態(tài)。

在城鎮(zhèn)間旅行的時候,可能需要購買1些記念品、留下1下回想。類似的,在流程處理進程中,它要搜集1些數(shù)據(jù):流程當前狀態(tài)等。或許你很想將其稱為流程的狀態(tài),但是我們定義的狀態(tài)已有了另外的含義。

狀態(tài)

Spring Web Flow定義了5種不同的狀態(tài),以下表所示。通過選擇Spring Web Flow的狀態(tài)幾近可以把任意的安排功能構造成會話式的Web利用程序。雖然其實不是所有的流程都需要下表中的狀態(tài),但終究你可能會常常使用其中幾個。

狀態(tài)類型 作用
行動(Action) 流程邏輯產生的地方
決策(Decision) 決策狀態(tài)將流程分為兩個方向,它會基于流程數(shù)據(jù)的評估結果肯定流程方向
結束(End) 結束狀態(tài)是流程的最后1站,進入End狀態(tài),流程就會終止
子流程(Subflow) 子流程狀態(tài)會在當前正在運行的流程上下文中啟動1個新的流程
視圖(View) 視圖狀態(tài)會暫停流程并約請用戶參與流程

首先了解下這些流程元素在Spring Web Flow定義中是如何表現(xiàn)的。

視圖狀態(tài)

視圖狀態(tài)用來為用戶展現(xiàn)信息并使用戶在流程中發(fā)揮作用。實際的視圖實現(xiàn)可以是Spring支持的任意視圖類型,但通常是用JSP來實現(xiàn)的。

在流程定義文件中,用來定義視圖狀態(tài):

<view-state id="welcome" />

在這個簡單的示例中,id屬性有兩個含義。其1,它定義了流程中的狀態(tài)。其2,由于這里沒有其他地方指定視圖,那末它就指定了流程到達這個狀態(tài)時要展現(xiàn)的邏輯視圖名稱為welcome。

如果要顯示地指定另外1個視圖名稱,那末就能夠使用view屬性:

<view-state id="welcome" view="greeting" />

如果流程為用戶展現(xiàn)了1個表單,你希望指定表單所綁定的對象,可使用model屬性:

<view-state id="takePayment" model="flowScope.paymentDetails"/>

這里指定了takePayment視圖將綁定流程范圍內的paymentDetails對象。

行動狀態(tài)

視圖狀態(tài)包括流程利用的用戶,而行動狀態(tài)則是利用程序本身在履行任務。行動狀態(tài)1般會觸發(fā)Spring所管理Bean的1些方法,并跟你講方法調用的履行結果轉移到另外一個狀態(tài)。

在流程定義文件中,行動狀態(tài)使用元夙來聲明:

<action-state id="saveOrder"> <evaluate expression="pizzaFlowActions.saveOrder(order)" /> <transition to="thankYou" /> action-state>

雖然沒有嚴格要求,但是元素1般都有1個子元素,該元素給出了行動狀態(tài)要做的事情,expression屬性指定了進入這個狀態(tài)時要評估的表達式。本例中,給出的是SpEL表達式,這表明它將會找到ID為pizzaFlowActions的Bean,并調用其saveOrder()方法。

決策狀態(tài)

流程有可能會依照線性履行下去,從1個狀態(tài)到另外一個狀態(tài),沒有其他的替換線路。但是更常見的是流程在某1個點根據(jù)流程當前情況進入不同的分支。

決策狀態(tài)能夠使得在流程履行時產生兩個分支,它會評估1個Boolean表達式,根據(jù)結果是true還是false在兩個狀態(tài)轉移當選擇1個。在流程定義文件中,使用元夙來定義決策狀態(tài):

<decision-state id="checkDeliveryArea"> <if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)" then="addCustomer" else="deliveryWarning" /> decision-state>

其實不是單獨工作的,元素是其核心,它是進行表達式評估的地方,如果表達式結果為true,流程會轉向then屬性指定的狀態(tài),為false會轉向else指定的狀態(tài)中。

子流程狀態(tài)

或許你不會將利用程序的所有邏輯都寫在1個方法里,而是將其分散到多個類、方法1起其他結構中。

一樣的,將流程分成獨立的部份也是個不錯的主張。元素允許在1個正在履行的流程中調用另外一個流程:

<subflow-state id="order" subflow="pizza/order"> <input name="order" value="order"/> <transition on="orderCreated" to="payment" /> subflow-state>

這里,元素作為子流程的輸入被用于傳遞定單對象。如果子流程結束的狀態(tài)ID為orderCreated,那末本流程就會轉移到ID為payment的狀態(tài)。

結束狀態(tài)

最后,所有的流程都要結束。這就是流程轉移到結束狀態(tài)時所做的。元素指定了流程的結束:

<end-state id="customerReady" />

當流程到達時,流程就會結束。接下來產生甚么要取決于以下幾個因素:
- 如果結束的流程是個子流程,那末調用它的流程將會從處繼續(xù)履行。的ID將會用作時間觸發(fā)從開始的轉移。
- 如果設置了view屬性,那末就會渲染指定的視圖。視圖可以是相對流程的路徑,也能夠是流程模板,使用externalRedirect:前綴的會重定向到流程外部的頁面,而使用flowRedirect:前綴的則會重定向到另外1個流程。
- 如果結束的流程不是子流程也沒有配置view屬性,那末這個流程就會結束。閱讀器最后將會加載流程的基本URL地址,同時,由于沒有活動的流程,所以會開始1個新的流程實例。

需要注意的是1個流程可能有多個結束狀態(tài)。由于子流程的結束狀態(tài)ID肯定了激活的事件,所以或許你會希望以多種結束狀態(tài)來結束子流程,從而能夠在調用流程中觸發(fā)不同的事件,即便不是在子流程中,也有可能在結束流程后,根據(jù)流程的履行情況有多個顯示頁面供選擇。

下面看1下流程是如何在狀態(tài)間遷移的,如何在流程中通過定義轉移來完成道路鋪設。

轉移

如前文所述,轉移連接了流程中的狀態(tài)。流程中除結束狀態(tài)外的每一個狀態(tài),最少需要1個轉移,這樣就知道在狀態(tài)完成時的走向。1個狀態(tài)或許有多個轉移,分別表示當前狀態(tài)結束時可以履行的不同路徑。

轉移是通過元夙來定義的,作為其他狀態(tài)元素(、和)的子元素。最簡單的情勢就是元素在流程中指定下1個狀態(tài):

<transition to="customerReady" />

屬性to用于指定流程中的下1個狀態(tài)。如果元素只使用了to屬性,那末這個轉移就會是當前狀態(tài)的默許轉移選項,如果沒有其他可用轉移的話,就會使用它。

更加常見的轉移定義是基于事件的觸發(fā)來進行的。在視圖狀態(tài),事件通常會是用戶采取的動作。在行動狀態(tài),事件是評估表達式得到的結果。而在子流程狀態(tài),事件取決于子流程結束狀態(tài)的ID。在任意事件中,你可使用on屬性來指定觸發(fā)轉移的事件:

<transition on="phoneEntered" to="lookupCustomer"/>

在示例中,如果觸發(fā)了phoneEntered事件流程,就會進入lookupCustomer狀態(tài)。

在拋出異常時,流程也可能進入另外一種狀態(tài)。例如,如果沒有找到顧客的記錄,你可能希望流程轉移到1個顯示注冊表單的視圖狀態(tài),以下面:

<transition on-exception="com.springinaction.pizza.service.CustomerNotFoundException" to="registrationForm" />

屬性on-exception和屬性on10分類似,它是指定了要產生轉移的異常而不是1個事件。

全局轉移

在創(chuàng)建完流程后,或許你會發(fā)現(xiàn)有些狀態(tài)使用了1些通用的轉移。例如在全部流程中到處都有以下轉移:

<transition on="cancel" to="endState" />

與其在多個流程狀態(tài)中重復通用的轉移,不如將其作為的子元素,從而作為全局轉移

<global-transitions> <transition on="cancel" to="endState" /> global-transitions>

定義完全局轉移,流程中所有的狀態(tài)都會默許具有這個cancel轉移。

流程數(shù)據(jù)

當流程從1個狀態(tài)到達另外一個狀態(tài)時,它會帶走1些數(shù)據(jù)。有時這些數(shù)據(jù)很快就會被使用,比如直接展現(xiàn)給用戶,有時這些數(shù)據(jù)需要在全部流程中傳遞并在流程結束時使用。

聲明變量

流程數(shù)據(jù)是保存在變量中的,而變量可以在流程的任意位置進行援用,并且可以以多種方式進行創(chuàng)建。其中最簡單的方式就是使用元素:

<var name="customer" class="com.springinaction.pizza.domain.Customer"/>

這里創(chuàng)建了1個新的Customer實例并將其放在customer變量中,這個變量可以在流程的任意狀態(tài)下進行訪問使用。

作為行動狀態(tài)的1部份或說作為視圖狀態(tài)的入口,也能夠使用元夙來創(chuàng)建變量:

<evaluate result="viewScope.toppingsList" expression="T(com.springinaction.pizza.domain.Topping).asList()" />

這里元素計算了1個SpEL表達式,并將結果放到toppingsList變量中,這個變量是視圖作用域的。

類似的,元素也能夠設置變量的值:

<set name="flowScope.pizza" value="new com.springinaction.pizza.domain.Pizza()" />

元素與元素類似,都是講變量設置為表達式計算的結果。這里我們設置了1個流程范圍的pizza變量,它的值為Pizza對象的新實例。

流程數(shù)據(jù)的作用域

流程中所攜帶的數(shù)據(jù)都有其各自的生命周期,這取決于保存數(shù)據(jù)的變量本身的作用域,以下表:

范圍 生命周期
Conversation 最高層級的流程開始時創(chuàng)建,在最高層級的流程結束時燒毀。由最高層級的流程和其所有的子流程所同享
Flow 當流程開始時創(chuàng)建,在流程結束時燒毀。只在創(chuàng)建它的流程中是可見的
Request 當1個要求進入流程時創(chuàng)建,流程返回時燒毀
Flash 流程開始時創(chuàng)建,流程結束時燒毀。在視圖狀態(tài)解析后,才會被清除
View 進入視圖狀態(tài)時創(chuàng)建,退出這個狀態(tài)時燒毀,只在視圖狀態(tài)內可見

當使用元素聲明變量時,變量始終是流程作用域的,也就是在流程作用域內定義變量。當使用或時,作用域通過name或result屬性的前綴指定。例如,將1個值賦給流程作用域的theAnswer變量:

<set name="flowScope.theAnswer" value="42"/>

到目前為止,我們已看到了Web流程的所有原材料,下面要將其進行整合了,完成1個完全的流程。

組合起來:披薩流程

首先從構建1個高層次的流程開始,它定義了訂購披薩的整體流程,然后將其拆分為多個子流程。

定義基本流程

當顧客訪問Spizza網站時,他們需要進行用戶辨認、選擇1個或多個披薩添加到定單、提供支付信息,然后提交定單,等待披薩上來,以下圖:
網上購買披薩的流程

下面展現(xiàn)Spring Web Flow的XML流程定義來實現(xiàn)披薩定單的整體流程:

<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⑵.3.xsd"> <var name="order" class="com.springinaction.pizza.domain.Order" /> <subflow-state id="identifyCustomer" subflow="pizza/customer"> <output name="customer" value="order.customer" /> <transition on="customerReady" to="buildOrder" /> subflow-state> <subflow-state id="buildOrder" subflow="pizza/order"> <input name="order" value="order" /> <transition on="orderCreated" to="takePayment" /> subflow-state> <subflow-state id="takePayment" subflow="pizza/payment"> <input name="order" value="order" /> <transition on="paymentTaken" to="saveOrder" /> subflow-state> <action-state id="saveOrder"> <evaluate expression="pizzaFlowActions.saveOrder(order)" /> <transition to="thankCustomer" /> action-state> <view-state id="thankCustomer"> <transition to="endState" /> view-state> <end-state id="endState" /> <global-transitions> <transition on="cancel" to="endState" /> global-transitions> flow>

流程定義中的第1件事就是聲明order變量。每次流程開始的時候都會創(chuàng)建1個Order實例。Order類會包括關于定單的所有信息、顧客信息、訂購的披薩和支付信息等。

package com.springinaction.pizza.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Configurable; @Configurable("order") public class Order implements Serializable { private static final long serialVersionUID = 1L; private Customer customer; private Listpizzas; private Payment payment; public Order() { pizzas = new ArrayList(); customer = new Customer(); } //getters and setters }

流程定義的主要組成部份是流程的狀態(tài),默許情況下,流程定義文件中的第1個狀態(tài)會是流程訪問的第1個狀態(tài)。本例中就是identifyCustomer狀態(tài)(1個子流程)。也能夠通過元素的start-state屬性來指定任意狀態(tài)為開始狀態(tài):

<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⑵.3.xsd" start-state="identifyCustomer"> ... flow>

辨認顧客、構建披薩定單和支付這樣的活動比較復雜,其實不合適將其直接放在1個狀態(tài),而是以元素展現(xiàn)的。

流程變量order將在前3個狀態(tài)中進行填充并在第4個狀態(tài)中進行保存。identifyCustomer子流程使用了元夙來填充order的customer屬性,將其設置為調用顧客子流程收到的輸出。buildOrder和takePayment狀態(tài)使用了不同的方式,它們使用將order流程變量作為輸入,這些子流程就可以在其內部填充order對象。

在定單得到顧客、披薩和支付信息后,就能夠對其進行保存。saveOrder是處理這個任務的行動狀態(tài)。它使用來調用ID為pizzaFlowActions的Bean的saveOrder()方法,并將保存的定單對象傳遞進來。定單完成保存后會轉移到thankCustomer。

thankCustomer狀態(tài)是1個簡單的視圖狀態(tài),后臺使用了/WEB-INF/flows/pizza/thankCustomer.jsp文件進行展現(xiàn):

<html xmlns:jsp="http://java.sun.com/JSP/Page"> <jsp:output omit-xml-declaration="yes" /> <jsp:directive.page contentType="text/html;charset=UTF⑻" /> <head><title>Spizzatitle>head> <body> <h2>Thank you for your order!h2> Finish ]]> body> html>

該頁面提供了1個完成流程的鏈接,它展現(xiàn)了用戶與流程交互的唯1辦法。

Spring Web Flow為視圖的用戶提供了1個flowExecutionUrl變量,它包括了流程的URL。結束鏈接將1個_eventId參數(shù)關聯(lián)到URL上,以便返回到Web流程時觸發(fā)finished事件。這個事件將會使流程到達結束狀態(tài)。

流程將會在結束狀態(tài)完成。由于在流程結束后沒有下1步做甚么具體信息,流程將會重新從identifyCustomer狀態(tài)開始,以準備接受下1個定單。

下面還要定義identifyCustomer、buildOrder、takePayment這些子流程。

搜集顧客信息

對1個顧客,需要搜集其電話、住址等信息,以下面的流程圖:
識別顧客流程

這個流程不再是線性的,而是有了分支。例如在查找顧客后,流程可能結束,也可能轉到注冊表單。一樣的,在checkDeliveryArea狀態(tài),顧客可能會被告警,也多是不被告警。

程序清單:

<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⑵.0.xsd"> <input name="order" required="true" /> <view-state id="welcome"> <transition on="phoneEntered" to="lookupCustomer" /> <transition on="cancel" to="cancel" /> view-state> <action-state id="lookupCustomer"> <evaluate result="order.customer" expression="pizzaFlowActions.lookupCustomer(requestParameters.phoneNumber)" /> <transition to="registrationForm" on-exception="com.springinaction.pizza.service.CustomerNotFoundException" /> <transition to="customerReady" /> action-state> <view-state id="registrationForm" model="order" popup="true"> <on-entry> <evaluate expression="order.customer.phoneNumber = requestParameters.phoneNumber" /> on-entry> <transition on="submit" to="checkDeliveryArea" /> <transition on="cancel" to="cancel" /> view-state> <decision-state id="checkDeliveryArea"> <if test="pizzaFlowActions.checkDeliveryArea(order.customer.zipCode)" then="addCustomer" else="deliveryWarning" /> decision-state> <view-state id="deliveryWarning"> <transition on="accept" to="addCustomer" /> <transition on="cancel" to="cancel" /> view-state> <action-state id="addCustomer"> <evaluate expression="pizzaFlowActions.addCustomer(order.customer)" /> <transition to="customerReady" /> action-state> <end-state id="cancel" /> <end-state id="customerReady" /> flow>

下面將這個流程定義分解成1個個的狀態(tài)。

詢問電話號碼

welcome狀態(tài)是1個很簡單的視圖狀態(tài),它歡迎訪問Spizza網站的顧客并要求輸入電話。它有兩個轉移:如果從視圖觸發(fā)phoneEntered事件,就會定向到lookupCustomer,另外1個就是在全局轉移中定義用來響應cancel事件的cancel轉移。

頁面代碼:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <html> <head> <title>Spring Pizzatitle> head> <body> <h2>Welcome to Spring Pizza!!!h2> <form:form> <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" /> <input type="text" name="phoneNumber" /> <br /> <input type="submit" name="_eventId_phoneEntered" value="Lookup Customer" /> form:form> body> html>

這個簡單的表單用來讓用戶輸入電話號碼,有兩個特殊的部份,首先是隱藏的_flowExecutionKey輸入。當進入視圖狀態(tài)時,流程暫停并等待用戶采取1些行動。當用戶提交表單時,流程履行鍵會在_flowExecutionKey輸入域中返回,并在流程暫停的位置進行恢復。

還需要注意提交按鈕的名稱_eventId_部份是Spring Web Flow的1個線索,它表明了接下來要觸發(fā)事件。當點擊這個按鈕提交表單時,就會觸發(fā)phoneEntered事件,進而轉移到lookupCustomer。

查找顧客

當歡迎顧客的表單提交后,顧客的電話號碼將包括在要求參數(shù)中,并用于查詢顧客。lookupCustomer狀態(tài)的元素是查找產生的位置。它將電話號碼從要求參數(shù)中抽取出來,并傳遞到pizzaFlowActions Bean的lookupCustomer()方法中。該方法要末返回Customer對象,要末拋出CustomerNotFoundException異常。

在前1種情況下,Customer對象會被設置到customer變量中(通過result屬性)并默許的轉移將流程帶到customerReady狀態(tài)。如果沒有查到顧客,那末會拋出異常,流程會轉移到registrationForm狀態(tài)。

注冊新顧客

registrationForm要求用戶填寫配送地址:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head><title>Spring Pizzatitle>head> <body> <h2>Customer Registrationh2> <form:form commandName="order"> <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/> <b>Phone number: b><form:input path="customer.phoneNumber"/><br/> <b>Name: b><form:input path="customer.name"/><br/> <b>Address: b><form:input path="customer.address"/><br/> <b>City: b><form:input path="customer.city"/><br/> <b>State: b><form:input path="customer.state"/><br/> <b>Zip Code: b><form:input path="customer.zipCode"/><br/> <input type="submit" name="_eventId_submit" value="Submit" /> <input type="submit" name="_eventId_cancel" value="Cancel" /> form:form> body> html>

該表單綁定到了Order.customer對象上。

檢查配送區(qū)域

顧客提供了地址后,需要確認住址是不是在配送范圍內,因此使用了決策狀態(tài)。

決策狀態(tài)checkDeliveryArea有1個元素,它將顧客的郵編傳遞到pizzaFlowActions Bean的checkDeliveryArea()方法中,該方法會返回1個Boolean值。

如果顧客在配送范圍內,那末流程將轉移到addCustomer狀態(tài),否則進入deliveryWarning視圖狀態(tài)。deliveryWarnin視圖:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head><title>Spring Pizzatitle>head> <body> <h2>Delivery Unavailableh2> <p>The address is outside of our delivery area. The order may still be taken for carry-out.p> <a href="${flowExecutionUrl}&_eventId=accept">Accepta> | <a href="${flowExecutionUrl}&_eventId=cancel">Cancela> body> html>

其中有兩個鏈接,允許用戶繼續(xù)定單或取消定單。通過使用與welcome狀態(tài)相同的flowExecutionUrl變量,這些鏈接分別觸發(fā)流程中的accept和cancel事件。如果發(fā)送的是accept事件,那末流程會轉移到addCustomer狀態(tài)。否則,子流程會轉移到cancel狀態(tài)。

存儲顧客數(shù)據(jù)

addCustomer有1個元素,它會調用pizzaFlowActions.addCustomer()方法,將order.customer流程參數(shù)傳遞進去。

1旦這個流程完成,就會履行默許轉移,流程會轉移到ID為customerReady的結束狀態(tài)。

結束流程

當customer流程完成所有的路徑后,會到達customerReady的結束狀態(tài)。當調用它的披薩流程恢復時,它會接收到1個customerReady事件,這個事件將使得流程轉移到buildOrder狀態(tài)。

注意,customerReady結束狀態(tài)包括了1個元素。在流程中,它同等于Java的return語句。它會從子流程中傳遞1些數(shù)據(jù)到調用流程。例如,元素返回customer變量,這樣披薩流程中的identifyCustomer子流程狀態(tài)就能夠將其指定給定單。

另外,如果用戶在任意地方觸發(fā)了cancel事件,將會通過cancel狀態(tài)結束流程,這也會在披薩流程中觸發(fā)cancel事件并致使轉移到披薩流程的結束狀態(tài)。

構建定單

下面就是肯定顧客想要甚么樣的披薩,提示用戶創(chuàng)建披薩并將其放入定單,如圖:
通過訂單子流程添加披薩

可以看到,showOrder狀態(tài)位于定單子流程的中心位置。這是用戶進入這個流程時的狀態(tài),也是用戶添加披薩定單后轉移的目標狀態(tài)。它展現(xiàn)了定單確當前狀態(tài),并允許用戶添加其他的披薩到定單中。

添加披薩定單時,會轉移到createPizza狀態(tài)。這是1個視圖狀態(tài),允許用戶對披薩進行選擇。

在showOrder狀態(tài),用戶可以提交定單,也能夠取消。

<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⑵.0.xsd"> <input name="order" required="true" /> <view-state id="showOrder"> <transition on="createPizza" to="createPizza" /> <transition on="checkout" to="orderCreated" /> <transition on="cancel" to="cancel" /> view-state> <view-state id="createPizza" model="flowScope.pizza"> <on-entry> <set name="flowScope.pizza" value="new com.springinaction.pizza.domain.Pizza()" /> <evaluate result="viewScope.toppingsList"
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 在线播放人成午夜免费视频 | 日本h片无遮挡在线观看 | 亚洲国产成人久久一区www妖精 | 91久久夜色精品 | 亚洲国产成人精品一区91 | 日本一区二区三区不卡在线视频 | 久久综合九色综合欧洲色 | 天码毛片一区二区三区入口 | 日韩爱爱视频 | 亚洲 欧美 日韩在线一区 | 欧美日韩在线播一区二区三区 | 免费亚洲一区 | 欧美一级成人一区二区三区 | 噜噜片| 欧美国产一区二区二区 | 日韩欧美在线观看视频一区二区 | 欧美色图校园春色 | 成人免费视频一区 | 国产一区亚洲一区 | 精品国产免费福利片 | 性激烈的欧美三级视频中文字幕 | 日本护士xxxxxx. | 欧美精品v国产精品v | 波多野一区二区三区在线 | 嗯啊在线观看免费影院 | 最近中文字幕无免费视频 | 欧美黄色一级片视频 | 最近高清中文字幕在线国语5 | 校园春色亚洲激情 | 欧美成人精品高清在线观看 | 国产精品视频白浆免费视频 | 日韩色小说 | 欧美高清成人videosex | 精品一区二区三区自拍图片区 | 国产日韩欧美中文字幕 | 国产成人91一区二区三区 | 国产精品日韩一区二区三区 | 亚洲色图欧美 | 日本护士handjob | 精品国产三级v | 成人叼嘿视频免费网站 |