javascript
Spring Web Flow实例教程
目錄:
1.參考文獻(xiàn)
參考1:http://www.ibm.com/developerworks/cn/education/java/j-spring-webflow/section3.html
參考2:http://lib.iteye.com/blog/299142
示例代碼:http://dl.dbank.com/c0n9qasa5r
2.購(gòu)物車(chē)用例
要了解 Spring Web Flow 是什么東西,最好的辦法莫過(guò)于查看示例,一個(gè)簡(jiǎn)化的購(gòu)物車(chē)的流程如下圖所示:
上圖 所示流程用 Spring Web Flow 2.0 的配置文件表示如下清單 1:
清單 1 用 Spring Web Flow 語(yǔ)義表達(dá)購(gòu)物車(chē)流程
……<flow>
<view-state id="viewCart">
<transition on="submit" to="viewOrder"/>
</view-state>
<view-state id="viewOrder">
<transition on="confirm" to="viewConfirmed"/>
</view-state>
<view-state id="viewConfirmed">
<transition on="returnToIndex" to="returnToIndex"/>
</view-state>
<end-state id="returnToIndex"/>
</flow>
配置1中省略了許多技術(shù)細(xì)節(jié),展示的只是一個(gè)業(yè)務(wù)的流程,主要是為了讓大家對(duì) Spring Web Flow 的語(yǔ)義有個(gè)初始的印象。從配置 1 中,應(yīng)注意到一個(gè)很重要的特征—— Spring Web Flow 語(yǔ)義與 Servlet API 無(wú)關(guān)。更確切地講, Spring Web Flow 語(yǔ)義關(guān)注的是業(yè)務(wù)的流程,并未與 Sun 公司的 Web 規(guī)范緊密結(jié)合,這種描述是更高層次的抽象,差不多是在建模的角度來(lái)描述業(yè)務(wù)流程。
不過(guò), Spring Web Flow 也并非只有抽象,現(xiàn)在還沒(méi)有哪一種工具或語(yǔ)言可以將一個(gè)模型直接轉(zhuǎn)換成相應(yīng)的應(yīng)用程序。 Spring Web Flow 更像是抽象建模和技術(shù)細(xì)節(jié)的混血兒,相比于湮沒(méi)在繁多的控制器和視圖中的 Web MVC 應(yīng)用來(lái)講, Spring Web Flow 提供了如清單 1 所描述的更高層次的抽象,但同時(shí)它也整合了像 Unified EL 這樣的工具來(lái)控制技術(shù)上的細(xì)節(jié)。
Spring Web Flow 的基本元素
Flow 可看作是客戶(hù)端與服務(wù)器的一次對(duì)話( conversation )。 Flow 的完成要由分多個(gè)步驟來(lái)實(shí)現(xiàn),在 Spring Web Flow 的語(yǔ)義中,步驟指的就是 state 。Spring Web Flow 提供了五種 state ,分別是 Action State 、 View State 、 Subflow State 、 Decision State 、 End State ,這些 state 可用于定義 flow 執(zhí)行過(guò)程中的各個(gè)步驟。除了 End State 外,其他 state 都可以轉(zhuǎn)換到別的 state ,一般通過(guò)在 state 中定義 transition 來(lái)實(shí)現(xiàn)到其他 state 的轉(zhuǎn)換,轉(zhuǎn)換的發(fā)生一般由事件( event )來(lái)觸發(fā)。
3.什么情況下可以使用 Spring Web Flow?
前面講了, Spring Web Flow 提供了描述業(yè)務(wù)流程的抽象能力,但對(duì)一種 Web 開(kāi)發(fā)技術(shù)而言,僅有這些是不夠的。同時(shí), Spring Web Flow 是不是能夠取代其他 Web MVC 技術(shù)?或者在任何情況下都應(yīng)優(yōu)先使用 Spring Web Flow ?要回答這些問(wèn)題,先來(lái)看一下 Spring Web Flow 所著力解決的技術(shù)問(wèn)題。
3.1.Web 應(yīng)用程序的三種范圍
Java Servlet 規(guī)范為 Web 應(yīng)用程序中用到的各種對(duì)象規(guī)定了三種范圍( scope ),分別是 request 范圍、 session 范圍和 application 范圍。
現(xiàn)實(shí)開(kāi)發(fā)中最令人頭痛的莫過(guò)于 session 范圍, Java Servlet 規(guī)范指明可在 web.xml 中按如下方式配置 session 的有效時(shí)間為100分鐘,如下清單 2所示:
清單 2 web.xml 中 session 的配置
<session-timeout>100</session-timeout>
</session-config>
然而,現(xiàn)實(shí)中的 session 范圍更像是“雞肋”,把大量數(shù)據(jù)放入 session 會(huì)導(dǎo)致嚴(yán)重的效率問(wèn)題,在分布式的環(huán)境中處理 session 范圍更是一不小心就會(huì)出錯(cuò),但拋棄 session 又會(huì)給開(kāi)發(fā)帶來(lái)許多不便。 request 范圍雖說(shuō)能存放量大的數(shù)據(jù),但有效范圍有限。擺在開(kāi)發(fā)者面前的很多用例都要求一種比 request 范圍要長(zhǎng),但又比 session 范圍要短的這么一種有效范圍。
3.2.Spring Web Flow 的解決方案
針對(duì) Java Servlet 規(guī)范中的這個(gè)缺陷, Spring Web Flow 2.0 中提供了以下兩種范圍:
subflow 定義:被其他 flow 所調(diào)用的 flow 即可稱(chēng)為 subflow。
由于 flow 是由開(kāi)發(fā)人員自己定義的,可根據(jù)業(yè)務(wù)的需求自由改變, flow 范圍和 conversation 范圍的使用也就突破了 Java Servlet 規(guī)范中 session 范圍和 request 范圍的局限,真正做到了自由定制。
3.3.并非所有情形都適用 Spring Web Flow
可以看出, Spring Web Flow 所著力解決的問(wèn)題即是客戶(hù)端與服務(wù)器的對(duì)話( conversation )問(wèn)題,這個(gè)范圍比 request 要長(zhǎng),而比 session 要短。為實(shí)現(xiàn) conversation 范圍(即 flow 范圍),需要付出效率上的代價(jià),因此,并非所有 Web 應(yīng)用都適合使用 Spring Web Flow 。 Seth Ladd 等人所著 Expert Spring MVC and Web Flow 一書(shū),對(duì)何時(shí)使用Spring Web Flow,列出了如下表格。
表 1 何時(shí)使用 Spring Web Flow| 解決方案 | 何時(shí)使用 |
| Spring MVC Controller | 某個(gè)單獨(dú)的、只需較少業(yè)務(wù)邏輯就可創(chuàng)建的頁(yè)面,同時(shí)該頁(yè)面不是 flow 的一部分 |
| Spring MVC SimpleFormController | 某個(gè)只涉及表單提交的頁(yè)面,如一個(gè)搜索框 |
| Spring MVC AbstractWizardFormController | 由一系列導(dǎo)航頁(yè)面組成的業(yè)務(wù)過(guò)程 |
| Spring Web Flow | 任何比較復(fù)雜的、有狀態(tài)的、需要在多個(gè)頁(yè)面之間跳轉(zhuǎn)的業(yè)務(wù)過(guò)程 |
3.4.Spring Web Flow 的其他特點(diǎn)
Web Flow 作為一個(gè)單獨(dú)的概念被提出來(lái),也可算是 Spring Web Flow 的一大亮點(diǎn)。目前大多數(shù) Web MVC 框架都把重點(diǎn)把在各種 controller 和形形色色的 view 技術(shù)上面,對(duì) Web 應(yīng)用流程本身的關(guān)注是不夠的, Web Flow 的提出就提供了一層抽象,設(shè)計(jì)者就可以從 Web Flow 抽象層面來(lái)進(jìn)行設(shè)計(jì)、開(kāi)發(fā)。當(dāng)然,?Web Flow 不能理解為只是 Web 頁(yè)面間的跳轉(zhuǎn)流程,定義 Spring Web Flow 的語(yǔ)義并非只限于頁(yè)面之間的跳轉(zhuǎn),而可以是 Web 應(yīng)用中的各種行為。由此,用例的模型建構(gòu)好以后,就可直接從該模型轉(zhuǎn)換到相應(yīng)的 Web Flow,開(kāi)發(fā)人員的設(shè)計(jì)變得更加直觀、有效。
另外,在 Spring Web Flow 中重用 Web Flow 是比較容易的。在定義 flow 、 state 時(shí)可通過(guò)繼承某個(gè)已有的 flow 或 state ,來(lái)避免重復(fù)定義。同時(shí),一個(gè) flow 可以調(diào)用其它 flow ,就跟一般程序語(yǔ)言中在某個(gè)函數(shù)內(nèi)部調(diào)用其它函數(shù)一樣方便。
4.配置 Spring Web MVC
Spring Web Flow 2.0 就是 Spring Web MVC 的一個(gè)擴(kuò)展,如果粗略一些來(lái)講,所謂 flow 就相當(dāng)于 Spring Web MVC 中一種特殊的 controller ,這種 controller 可通過(guò) XML 文件加以配置,因此在使用 Spring Web Flow 2.0 前須先對(duì) Spring Web MVC進(jìn)行配置,步驟如下:4.1.聲明 DispatcherServlet 并指定配置文件
為使用 Spring Web MVC ,須在 web.xml 中聲明 DispatcherServlet ,見(jiàn)清單 3?:
清單 3 聲明 DispatcherServlet 和指定配置文件 <servlet><servlet-name>CartServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/web-application-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
4.2.添加 DispatcherServlet 映射
要讓 DispatcherServlet 處理所有以 /spring/ 開(kāi)頭的請(qǐng)求,見(jiàn)清單4?:
清單 4 web.xml 中的 DispatcherServlet映射 <servlet-mapping><servlet-name>CartServlet</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>
4.3.創(chuàng)建 web-application-config.xml
開(kāi)發(fā)基于 Spring Web Flow 的應(yīng)用往往會(huì)有大量的配置,這些配置全放在一個(gè)文件中是不合適的。本示例參考?Spring Web Flow 2.0 自帶示例(可以找找看),將不同功能的配置文件分開(kāi)。其中?web-application-config.xml 用于配置與 Web 應(yīng)用全局相關(guān)的內(nèi)容,?Spring Web MVC 的相關(guān)配置放在 webmvc-config.xml 中,教程后面要添加的?Spring Web Flow 的配置則放在 webflow-config.xml 中。在 web-application-config.xml 中用 import 元素導(dǎo)入其他的配置文件。 web-application-config.xml的內(nèi)容見(jiàn)清單 5:
清單 5 web-application-config.xml
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- 搜索 samples.webflow 包里的 @Component 注解,并將其部署到容器中 -->
<context:component-scan base-package="samples.webflow" />
<!-- 啟用基于注解的配置 -->
<context:annotation-config />
<import resource="webmvc-config.xml"/>
</beans> 注意:xml文件內(nèi)容最好頂行頂格寫(xiě),不然可能會(huì)出現(xiàn)一些錯(cuò)誤。
加入注解功能是出于最后運(yùn)行 Web Flow 示例的需要(后面使用到的時(shí)候會(huì)指明),在這里只要知道注解功能已被啟用就可以了。
4.4.創(chuàng)建 webmvc-config.xml
webmvc-config.xml 主要用于配置 Spring Web MVC 。所要做的就是添加一個(gè)?viewResolver (視圖解析器),用于將視圖名解析成真實(shí)的視圖資源。另外,再配置好URL 請(qǐng)求的 handler (處理器),用于將 URL 請(qǐng)求定向到某個(gè)控制器,在本例中,用到的是 UrlFilenameViewController。
清單 6 webmvc-config.xml
?
<?xml version="1.0" encoding="UTF-8"?><beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="viewMappings"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="defaultHandler">
<!-- UrlFilenameViewController 會(huì)將 "/index" 這樣的請(qǐng)求映射成名為 "index" 的視圖 -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
</beans>
4.5.創(chuàng)建 index.jsp
現(xiàn)在的 index.jsp 只是顯示一行文字。
清單 7 index.jsp
<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Cart Application</title>
</head>
<body>
<h1>Hello!</h1>
</body>
</html>
4.6.運(yùn)行應(yīng)用程序
將應(yīng)用程序發(fā)布到 Tomcat 容器,再通過(guò) http://localhost:8080/CartApp/spring/index.jsp 訪問(wèn) index.jsp 頁(yè)面(應(yīng)用程序所在文件夾名是 CartApp ),測(cè)試 Spring Web MVC 配置是否正確。如果一切正常,可得到如下頁(yè)面:?
4.7.示例代碼
CartApp2示例代碼下載地址:http://www.dbank.com/download/CartApp2.rar?f=c0n9qasa5r&i=2&h=1321056539&v=7a3a7609
?
5.0.配置 Spring Web Flow 2.0 的基礎(chǔ)
配置好 Spring Web MVC 的環(huán)境后,接下來(lái)就可以往里面加入 Spring Web Flow 2.0 的配置。不過(guò),要搞明白 Spring Web Flow 2.0 的配置,必須先要了解相關(guān)的理論知識(shí)。5.1.FlowRegistry
FlowRegistry 是存放 flow 的倉(cāng)庫(kù),每個(gè)定義 flow 的 XML 文檔被解析后,都會(huì)被分配一個(gè)唯一的 id ,并以 FlowDefinition 對(duì)象的形式存放在 FlowResigtry 中。 FlowRegistry 配置方式可參看清單 8。
清單 8 FlowRegistry 的配置
<webflow:flow-registry id="flowRegistry"><webflow:flow-location path="/WEB-INF/flows/shopping.xml" id=”shopping”/>
</webflow:flow-registry>
說(shuō)明:以下的示例清單中的 XML 配置元素默認(rèn)使用了 webflow 名字空間,這也是 Spring Web Flow 習(xí)慣上的名字空間,參看教程后面 webflow-config.xml 文件,可以更多了解 webflow 名字空間。
每個(gè) flow 都必須要有 id 來(lái)標(biāo)識(shí),如果在配置中省略,那么該 flow 默認(rèn)的 id 將是該定義文件(xml文件)的文件名去掉后綴所得的字符串(例如本例中如果去掉id="shopping",那么flow的id就是shopping.xml去掉后綴名.xml后的shopping作為id)。
5.2.FlowExecutor
FlowExecutor 是 Spring Web Flow 的一個(gè)核心接口,啟動(dòng)某個(gè) flow ,都要通過(guò)這個(gè)接口來(lái)進(jìn)行。從配置角度來(lái)說(shuō),只要保證有個(gè) FlowExecutor 就可以了, Spring Web Flow 的默認(rèn)行為已經(jīng)足夠。默認(rèn)配置參看清單9。清單 9 FlowExecutor 的配置
<webflow:flow-executor id="flowExecutor" />5.3.哪個(gè) flow 被執(zhí)行了?
FlowRegistry 中注冊(cè)的 flow 可能會(huì)有多個(gè),但前面介紹過(guò),每個(gè) flow 都會(huì)有 id ,沒(méi)有配置的,也會(huì)有個(gè)默認(rèn)值,?FlowExecutor 就是通過(guò) id 來(lái)找出要執(zhí)行的 flow?。至于這個(gè) id ,則是要由用戶(hù)來(lái)指定的。在默認(rèn)配置情況下,如果客戶(hù)端發(fā)送了如下URL請(qǐng)求:http://localhost:8080/CartApp/spring/shopping。則從 Spring Web Flow 的角度來(lái)看,這個(gè) URL 就表示客戶(hù)想要執(zhí)行一個(gè) id 為“ shopping ”的 flow?,于是就會(huì)在 FlowRegistry 中查找名為“ shopping ”的 flow,由FlowExecutor負(fù)責(zé)執(zhí)行。
5.4Spring Web Flow 如何與 Spring Web MVC 整合在一起?
客戶(hù)端發(fā)送的請(qǐng)求,先會(huì)由 servlet 容器(本教程示例中即為 Tomcat )接收, servlet 容器會(huì)找到相應(yīng)的應(yīng)用程序(本教程中即為 CartApp ),再根據(jù) web.xml 的配置找到出符合映射條件的 servlet 來(lái)處理。?Spring Web MVC 中處理請(qǐng)求的 servlet 是 DispatcherServlet ,如果請(qǐng)求的路徑滿(mǎn)足 DispatcherServlet 的映射條件,則 DispatcherServlet 會(huì)找出 Spring IoC 容器中所有的 HandlerMapping ,根據(jù)這些 HandlerMapping 中匹配最好的 handler (一般情況下都是 controller ,即控制器)來(lái)處理請(qǐng)求。當(dāng) Controller 處理完畢,一般都會(huì)返回一個(gè) view (視圖)的名字,DispatcherServlet再根據(jù)這個(gè)view的名字找到相應(yīng)的視圖資源返回給客戶(hù)端。
搞清楚 Spring Web MVC 處理請(qǐng)求的流程后,基本上就可以明白要整合 Spring Web MVC 與 Spring Web Flow 所需要的配置了。為了讓客戶(hù)端的請(qǐng)求變成執(zhí)行某個(gè) flow 的請(qǐng)求,要解決以下幾個(gè)問(wèn)題:
5.5.FlowHandler 和 FlowController
現(xiàn)在,需要一種接收?qǐng)?zhí)行 flow 的請(qǐng)求,然后根據(jù)請(qǐng)求來(lái)啟動(dòng)相應(yīng) flow的handler (處理器), Spring Web Flow 2.0 提供了兩種方案可供選擇。第一種方案是自己編寫(xiě)實(shí)現(xiàn)了 FlowHandler 接口的類(lèi),讓這個(gè)類(lèi)來(lái)實(shí)現(xiàn)這個(gè)功能。第二種方案是使用一個(gè)現(xiàn)成的叫做 FlowController 的控制器。第一種方案靈活性比較大,在許多場(chǎng)合可能也是唯一的選擇,但對(duì)每個(gè) flow 都需要編寫(xiě)相應(yīng)的 FlowHandler 。本教程的示例采用第二種方案,對(duì) FlowHandler 的介紹可參看 Spring Web Flow 2.0 自帶的文檔。 FlowController 其實(shí)是個(gè)適配器,一般來(lái)講,我們只要明白 FlowController 可根據(jù)客戶(hù)端請(qǐng)求的結(jié)尾部分,找出相應(yīng)的 flow 來(lái)執(zhí)行。配置 FlowController只需指定FlowExecutor即可,具體配置見(jiàn)清單10:
清單 10 FlowController 的配置 <bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController"><property name="flowExecutor" ref="flowExecutor"/>
</bean>
另外還需在 HandlerMapping 中指明 /shopping.do 請(qǐng)求由 flowController 來(lái)處理,配置見(jiàn)清單11:
清單 11 在 viewMappings 中添加配置 <bean id="viewMappings"class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- /shopping.do 請(qǐng)求由 flowController 來(lái)處理 -->
<property name="mappings">
<value> /shopping.do=flowController </value>
</property>
<span style="white-space:pre"> </span>......
</bean> 需要指出的是,不管設(shè)成 /shopping.do 還是設(shè)成 /shopping ,或者 /shopping.htm ,效果都是一樣的, flowController 都會(huì)去找 id 為 shopping的flow來(lái)執(zhí)行。
5.6.FlowBuilder Services
清單 8?所示 FlowRegistry 的配置,其中省略了 flow-registry 元素中一項(xiàng)比較重要的屬性, flow-builder-services 。 flow-builder-services 屬性的配置指明了在這個(gè) flow-registry “倉(cāng)庫(kù)”里的 flow 的一些基本特性,例如,是用 Unified EL 還是 OGNL 、 model (模型)對(duì)象中的數(shù)據(jù)在顯示之前是否需要先作轉(zhuǎn)換,等等。在本示例中,我們需要在 flow-builder-services 屬性中指明 Spring Web Flow 中所用到的 view ,由 Spring Web MVC 的“ View Resolver ”來(lái)查找,由 Spring Web MVC 的“ View Class”來(lái)解析,最后呈現(xiàn)給客戶(hù)。具體配置參看清單12:
清單 12 flow-builder-services 配置 <!--Web Flow 中的視圖通過(guò) MVC 框架的視圖技術(shù)來(lái)呈現(xiàn) --><webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" />
<!-- 指明 MVC 框架的 view resolver ,用于通過(guò) view 名查找資源 -->
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="viewResolver" />
</bean>
5.7.Spring Web Flow 2.0 配置小結(jié)
所有這些配置的目的無(wú)非是兩個(gè):一是要讓客戶(hù)端的請(qǐng)求轉(zhuǎn)變成 flow 的執(zhí)行,二是要讓 flow 執(zhí)行過(guò)程中、或執(zhí)行結(jié)束后得到的視圖能返還給客戶(hù)端。如果對(duì)這里的講解還不是很清楚,可先看下一節(jié)實(shí)際的配置,再回過(guò)頭來(lái)看本章內(nèi)容,以加深理解。6.在購(gòu)物車(chē)示例應(yīng)用中配置 Spring Web Flow
實(shí)現(xiàn)示例應(yīng)用的購(gòu)物車(chē)流程,可按以下步驟操作:6.1.在 /WEB-INF/lib 目錄下導(dǎo)入相關(guān)類(lèi)庫(kù)
將以下幾個(gè) jar 包導(dǎo)入 /WEB-INF/lib 目錄:- org.springframework.webflow-2.0.2.RELEASE.jar
- org.springframework.js-2.0.2.RELEASE.jar
- org.springframework.binding-2.0.2.RELEASE.jar
- jboss-el.jar
6.2.在 webmvc-config.xml 中添加配置
Spring Web MVC 相關(guān)的配置前面已經(jīng)分析過(guò)了,完整的配置見(jiàn)清單 13?:
清單 13 webmvc-config.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView">
</property>
<property name="prefix" value="/WEB-INF/jsp/">
</property>
<property name="suffix" value=".jsp">
</property>
</bean>
<bean id="viewMappings"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- /shopping.do 請(qǐng)求由 flowController 來(lái)處理 -->
<property name="mappings">
<value> /shopping.do=flowController </value>
</property>
<property name="defaultHandler">
<!-- UrlFilenameViewController 會(huì)將 "/index" 這樣的請(qǐng)求映射成名為 "index" 的視圖 -->
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
</beans>
6.3.添加配置文件 webflow-config.xml
在 /WEB-INF/config 目錄下添加 webflow-config.xml 文件, schema 名字空間可直接復(fù)制清單 14?中的內(nèi)容。
清單 14webflow-config.xml <?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:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
<webflow:flow-executor id="flowExecutor" />
<!-- 所有 flow的定義文件它的位置在這里進(jìn)行配置, flow-builder-services 用于配置 flow 的特性 -->
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/shopping.xml" id="shopping" />
<webflow:flow-location path="/WEB-INF/flows/addToCart.xml" id="addToCart" />
</webflow:flow-registry>
<!--Web Flow 中的視圖通過(guò) MVC 框架的視圖技術(shù)來(lái)呈現(xiàn) -->
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" />
<!-- 指明 MVC 框架的 view resolver ,用于通過(guò) view 名查找資源 -->
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="viewResolver" />
</bean>
</beans>
webflow-config.xml 創(chuàng)建完成以后,不要忘記在 web-application-config.xml 中添加 import 元素,將 webflow-config.xml 文件導(dǎo)入。
清單 15 在 web-application-config.xml 中導(dǎo)入 webflow-config.xml <import resource="webflow-config.xml"/>6.4.添加 flow 定義文件 shopping.xml
在 /WEB-INF/flows 目錄下創(chuàng)建 shopping.xml 文件,描述了圖 2 所示的流程。
清單 16 shopping.xml <?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-2.0.xsd">
<!-- view-state中的view對(duì)應(yīng)jsp文件夾中的jsp頁(yè)面,on是觸發(fā)事件,to對(duì)應(yīng)state id -->
<view-state id="viewCart" view="viewCart">
<transition on="submit" to="viewOrder">
</transition>
</view-state>
<view-state id="viewOrder" view="viewOrder">
<transition on="confirm" to="orderConfirmed">
</transition>
</view-state>
<view-state id="orderConfirmed" view="orderConfirmed">
<transition on="returnToIndex" to="returnToIndex">
</transition>
</view-state>
<end-state id="returnToIndex" view="externalRedirect:servletRelative:/index.jsp">
</end-state>
</flow>
與清單 1 相比,在 view-state 元素中指定了 view 屬性的名字,這個(gè)名字也是 Spring Web MVC 中 viewResolver (在webmvc-config.xml中定義)所查找的 view 的名字。從清單 16 的配置中可以知道,這三個(gè) view-state 元素所對(duì)應(yīng)的視圖資源分別應(yīng)該是: viewCart.jsp 、 viewOrder.jsp 和 orderConfirmed.jsp 。清單 16 中最后的 end-state 指明了當(dāng) flow 執(zhí)行結(jié)束后跳轉(zhuǎn)到初始的 index.jsp 頁(yè)面,在此處的 view 屬性的名字需要解釋一下。?externalRedirect 用在 view 名字中,表示所指向的資源是在 flow 的外部, servletRelative 則表明所指向資源的路徑起始部分與 flow 所在 servlet 相同。 Spring Web Flow 2.0還提供了其他幾個(gè)關(guān)鍵詞用于重定向,這里就不多介紹了。
在webmvc-config.xml中定義的viewResolver如下所示:
<bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView">
</property>
<property name="prefix" value="/WEB-INF/jsp/">
</property>
<property name="suffix" value=".jsp">
</property>
</bean>
這表示所有view-state中的view屬性同名對(duì)應(yīng)到了/WEB-INF/jsp目錄下的.jsp文件。
6.5.添加三個(gè) jsp 頁(yè)面
在 /WEB-INF/jsp 目錄下創(chuàng)建三個(gè) flow 所需的視圖資源。以下清單中只有viewCart.jsp給出完整的代碼,其他兩個(gè)只給出 jsp 頁(yè)面中 body 元素以?xún)?nèi)的代碼,其余省略。清單 17 viewCart.jsp
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>View Cart</title>
</head>
<body>
<h1>View Cart</h1>
<a href="${flowExecutionUrl}&_eventId=submit">Submit</a>
</body>
</html> 清單 18 viewOrder.jsp <h1>Order</h1>
<a href="${flowExecutionUrl}&_eventId=confirm">Confirm</a> 清單 19 orderConfirmed.jsp
<h1>Order Confirmed</h1>
<a href="${flowExecutionUrl}&_eventId=returnToIndex">Return to index</a>
這幾個(gè)頁(yè)面都使用了變量 flowExecutionUrl ,表示 flow 執(zhí)行到當(dāng)前狀態(tài)時(shí)的 URL 。?flowExecutionUrl 的值已經(jīng)由 Spring Web Flow 2.0 框架的代碼進(jìn)行賦值,并放入相應(yīng)的 model 中供 view 訪問(wèn)。 flowExecutionUrl 的值包含 flow 在執(zhí)行過(guò)程中會(huì)為每一狀態(tài)生成的唯一的 key ,因此不可用其他手段來(lái)獲取。請(qǐng)求參數(shù)中 _eventId 的值與清單 16 中 transition 元素的 on 屬性的值是對(duì)應(yīng)的,在接收到_eventId參數(shù)后,相應(yīng)transition會(huì)被執(zhí)行。
6.6.修改 index.jsp 頁(yè)面
在 index.jsp 頁(yè)面中添加啟動(dòng) flow 的鏈接,從 webmvc-config.xml 配置文件中可以看出,要啟動(dòng) flow ,只需提供 /shopping.do 鏈接即可。清單 20 index.jsp <h1>Hello!</h1><br/>
<a href="shopping.do">View Cart</a>
6.7.運(yùn)行應(yīng)用程序
將應(yīng)用程序發(fā)布到 Tomcat 服務(wù)器,訪問(wèn) index.jsp ,并啟動(dòng) flow ,測(cè)試頁(yè)面的跳轉(zhuǎn)。效果如圖 5所示:
圖 4 flow 運(yùn)行效果————————————————————————————————————————————————————
6.8示例程序源代碼
CartApp3源代碼下載地址:http://www.dbank.com/download/CartApp3.rar?f=c0n9qasa5r&i=1&h=1321062828&v=60993861
7.用 Unified EL 實(shí)現(xiàn)業(yè)務(wù)邏輯
到現(xiàn)在為止,這個(gè)購(gòu)物車(chē)應(yīng)用只是實(shí)現(xiàn)了頁(yè)面之間的跳轉(zhuǎn),接下來(lái)我們要實(shí)現(xiàn)與業(yè)務(wù)邏輯相關(guān)的功能。由于本教程的重點(diǎn)在于介紹如何應(yīng)用 Spring Web Flow ,所實(shí)現(xiàn)的業(yè)務(wù)比較簡(jiǎn)單,與實(shí)際應(yīng)用有較大的距離,請(qǐng)讀者諒解。業(yè)務(wù)的邏輯涉及到數(shù)據(jù)的獲取、傳遞、保存,相關(guān)的業(yè)務(wù)功能函數(shù)的調(diào)用等內(nèi)容,這些功能的實(shí)現(xiàn)都可用 Java 代碼來(lái)完成,但定義 Spring Web Flow 的語(yǔ)法與 Java 是無(wú)關(guān)的,這就要求 Spring Web Flow 提供與 Java 代碼的整合機(jī)制。要了解這種機(jī)制,關(guān)鍵在于搞清楚兩個(gè)問(wèn)題:
- 業(yè)務(wù)邏輯代碼在什么時(shí)候被調(diào)用?
- 業(yè)務(wù)邏輯代碼在調(diào)用后得到的數(shù)據(jù)如何保存、傳遞?
7.1.業(yè)務(wù)邏輯代碼在什么時(shí)候被調(diào)用?
在 Spring Web Flow 中,業(yè)務(wù)邏輯代碼的執(zhí)行可由以下三種情形來(lái)觸發(fā):- 客戶(hù)端請(qǐng)求中包含了 _eventId 參數(shù)
- 執(zhí)行到框架自定義的切入點(diǎn)
- 執(zhí)行到 <action-state> 元素
7.1.1客戶(hù)端請(qǐng)求中包含了 _eventId 參數(shù)
這種方式一般用在 state 之間的 transition ,通過(guò)指定 _eventId 參數(shù)的值,表明了客戶(hù)的行為,從而導(dǎo)致相應(yīng)事件的發(fā)生,在 Spring Web Flow 的定義文件中可以通過(guò) evaluate 元素來(lái)指定要處理的業(yè)務(wù)邏輯。參看清單21:
清單 21 transition 示例 <transition on="submit"><evaluate expression="validator.validate()" />
</transition>
清單 21 的代碼表示,當(dāng)客戶(hù)端的請(qǐng)求中包含“ _eventId=submit ”,則 evaluate 元素中 expression 屬性所指明的表達(dá)式會(huì)被執(zhí)行,即 validator 對(duì)象的validate 方法會(huì)得到調(diào)用。
7.1.2執(zhí)行到框架自定義的切入點(diǎn)
Spring Web Flow 定義了 5 個(gè)切入點(diǎn),通過(guò) flow 定義文件的配置,可在這 5 個(gè)切入點(diǎn)插入相關(guān)業(yè)務(wù)邏輯代碼。
表 2 Spring Web Flow 自定義的切入點(diǎn)
| 切入點(diǎn)名稱(chēng) | XML 元素名稱(chēng) | 觸發(fā)時(shí)刻 |
| flow start | on-start | flow 執(zhí)行之前 |
| state entry | on-entry | 進(jìn)入某個(gè) state 之后,做其他事情之前 |
| view render | on-render | 在進(jìn)入 view 的 render 流程之后,在 view 真正 render出來(lái)之前 |
| state exit | on-exit | 在退出 state 之前 |
| flow end | on-end | flow 執(zhí)行結(jié)束之后 |
清單 22 on-render 元素 <view-state id="viewCart" view="viewCart" >
<on-render>
<evaluate expression="productService.getProducts()" result="viewScope.products"/>
</on-render>
</view-state>
7.1.3執(zhí)行到 <action-state> 元素
Spring Web Flow 中的這個(gè) <action-state> 是專(zhuān)為執(zhí)行業(yè)務(wù)邏輯而設(shè)的 state?。如果某個(gè)應(yīng)用的業(yè)務(wù)邏輯代碼即不適合放在 transition 中由客戶(hù)端來(lái)觸發(fā),也不適合放在 Spring Web Flow 自定義的切入點(diǎn),那么就可以考慮添加 <action-state> 元素專(zhuān)用于該業(yè)務(wù)邏輯的執(zhí)行。示例代碼參看清單23:
清單 23 action-state 示例<action-state id="addToCart">
<evaluate expression="cart.addItem(productService.getProduct(productId))"/>
<transition to="productAdded"/>
</action-state>
7.2.業(yè)務(wù)邏輯代碼在調(diào)用后得到的數(shù)據(jù)如何保存、傳遞?
Spring Web Flow 的定義中可直接使用表達(dá)式語(yǔ)言( Expression Language ),前面的代碼都是用的 Unified EL ,對(duì)于習(xí)慣用 OGNL 的開(kāi)發(fā)人員,可通過(guò) flow-builder-services 的配置改成使用 OGNL 。不管是哪一種表達(dá)式語(yǔ)言, Spring Web Flow 都提供了一些固定名稱(chēng)的變量,用于數(shù)據(jù)的保存、傳遞。在 Spring Web Flow 的解決方案 一節(jié)中,已經(jīng)提到 Spring Web Flow 所著力解決的問(wèn)題即是數(shù)據(jù)存取范圍的問(wèn)題,為此, Spring Web Flow 提供了兩種比較重要的范圍,一是 flow 范圍,另一個(gè)是 conversation 范圍。通過(guò) flowScope 和 conversationScope 這兩個(gè)變量, Spring Web Flow 提供了在這兩種范圍里存取數(shù)據(jù)的方法。清單 24演示了如何將業(yè)務(wù)邏輯代碼執(zhí)行的結(jié)果存放到flow范圍中。
清單 24 flowScope 示例<evaluate expression="productService.getProducts()" result="flowScope.products" />
注意:Spring Web Flow 2.0 在默認(rèn)配置下,flowScope 和 conversationScope 的實(shí)現(xiàn)依賴(lài)于 Java 序列化和反序列化技術(shù),因此存放于 flowScope 或 conversationScope 中的對(duì)象需要實(shí)現(xiàn) java.io.Serializable 接口。
Spring Web Flow 還提供了大量其他的變量,以方便數(shù)據(jù)的存取。如 viewScope 范圍即是從進(jìn)入 view-state 至退出 view-state 結(jié)束, requestScope 即和一般的 request 范圍沒(méi)什么區(qū)別,等等。另外還有一些用于獲取 flow 以外數(shù)據(jù)的變量,如 requestParameters 、 messageContext 等等。具體變量的列表可參看 Spring Web Flow自帶的文檔。為示例應(yīng)用添加商品
接下來(lái),我們要在示例應(yīng)用的 viewCart.jsp 頁(yè)面中添加商品,可按以下步驟操作:添加 ProductService 類(lèi)
ProductService 主要提供商品列表,并能根據(jù)商品的 id 查找出該商品,由于示例較簡(jiǎn)單,這里只添加了三條紀(jì)錄。見(jiàn)清單 26:清單 26 ProductService 類(lèi)
package samples.webflow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
@Service("productService")
public class ProductService {
private Map<Integer, Product> products = new HashMap<Integer, Product>();
public ProductService() {
products.put(1, new Product(1, "Bulldog", 1000));
products.put(2, new Product(2, "Chihuahua", 1500));
products.put(3, new Product(3, "Labrador", 2000));
}
public List<Product> getProducts() {
return new ArrayList<Product>(products.values());
}
public Product getProduct(int productId) {
return products.get(productId);
}
}
Service 注解表示 Spring IoC 容器會(huì)初始化一個(gè)名為 productService 的 Bean ,這個(gè) Bean 可在 Spring Web Flow 的定義中直接訪問(wèn)。(這也是為什么在web-application-config.xml中添加注解的原因)
修改 shopping.xml 文件
要在 viewCart 頁(yè)面中顯示商品,只需在 view-state 元素的 on-render 切入點(diǎn)調(diào)用 productService 的 getProducts 方法,并將所得結(jié)果保存到 viewScope 中即可。見(jiàn)清單27:清單 27 shopping.xml 需修改的部分
<!-- view-state中的view對(duì)應(yīng)jsp文件夾中的jsp頁(yè)面,on是觸發(fā)事件,to對(duì)應(yīng)state id -->
<view-state id="viewCart" view="viewCart">
<on-render>
<!-- 要在 viewCart 頁(yè)面中顯示商品,只需在 view-state 元素的 on-render 切入點(diǎn)調(diào)用 productService 的
getProducts 方法,并將所得結(jié)果保存到 viewScope 中即可 -->
<evaluate expression="productService.getProducts()" result="viewScope.products" />
</on-render>
<transition on="submit" to="viewOrder">
</transition>
</view-state>
修改 viewCart.jsp 頁(yè)面
清單 27 表明 productService 的 getProducts 方法所得的結(jié)果會(huì)存放在 viewScope 中名為 products 的變量中, jsp 頁(yè)面的代碼可直接訪問(wèn)該變量。見(jiàn)清單 28:
清單 28 修改后的 viewCart.jsp 頁(yè)面<?xml version="1.0" encoding="utf-8" ?>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>View Cart</title>
</head>
<body>
<h1>View Cart</h1>
<a href="${flowExecutionUrl}&_eventId=submit">Submit</a>
<h2>Products for Your Choice</h2>
<table>
<c:forEach var="product" items="${products}">
<tr>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
7.3.運(yùn)行應(yīng)用程序
圖 5 viewCart.jsp 頁(yè)面效果——————————————————————————————————————————
7.4.示例代碼
CartApp4示例代碼下載地址:http://www.dbank.com/download/CartApp4.rar?f=c0n9qasa5r&i=3&h=1321064658&v=11ec87d68.用 subflow 實(shí)現(xiàn)添加商品到購(gòu)物車(chē)功能
商品已經(jīng)有列表了,接下來(lái)就要增加把商品放入購(gòu)物車(chē)的功能,在本示例中用 subflow 來(lái)實(shí)現(xiàn)這一功能,操作步驟如下:8.1.實(shí)現(xiàn) Cart 和 CartItem 兩個(gè)業(yè)務(wù)類(lèi)
CartItem 表示存放于購(gòu)物車(chē)中的條目,主要記錄相應(yīng)商品及商品數(shù)量,同時(shí)不要忘記實(shí)現(xiàn) java.io.Serializable 接口,見(jiàn)清單 29:清單 29 CartItem 類(lèi)
package samples.webflow;
import java.io.Serializable;
//購(gòu)物車(chē)中的條目
public class CartItem implements Serializable {
private static final long serialVersionUID = 8388627124326126637L;
private Product product;//商品
private int quantity;//數(shù)量
public CartItem(Product product, int quantity) {
this.product = product;
this.quantity = quantity;
}
//計(jì)算該條目的總價(jià)格
public int getTotalPrice() {
return this.quantity * this.product.getPrice();
}
//增加商品的數(shù)量
public void increaseQuantity() {
this.quantity++;
}
/**
* Return property product
*/
public Product getProduct() {
return product;
}
/**
* Sets property product
*/
public void setProduct(Product product) {
this.product = product;
}
/**
* Return property quantity
*/
public int getQuantity() {
return quantity;
}
/**
* Sets property quantity
*/
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
除去相應(yīng)的屬性外, CartItem 可根據(jù)商品的數(shù)量算出該商品的總價(jià)格( getTotalPrice ),也可通過(guò) increaseQuantity 增加商品數(shù)量。
Cart 是購(gòu)物車(chē)的實(shí)現(xiàn)類(lèi),其同樣要實(shí)現(xiàn) java.io.Serializable 接口,但它沒(méi)有像 ProductService 一樣成為由 Spring IoC 容器管理的 Bean ,每個(gè)客戶(hù)的購(gòu)物車(chē)是不同的,因此不能使用 Spring IoC 容器默認(rèn)的 Singleton 模式。見(jiàn)清單 30:
package samples.webflow;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//購(gòu)物車(chē)的實(shí)現(xiàn)類(lèi)
public class Cart implements Serializable {
private static final long serialVersionUID = 7901330827203016310L;
private Map<Integer, CartItem> map = new HashMap<Integer, CartItem>();
//getItems 用于獲取當(dāng)前購(gòu)物車(chē)?yán)锏奈锲?/span>
public List<CartItem> getItems() {
return new ArrayList<CartItem>(map.values());
}
//addItem 用于向購(gòu)物車(chē)添加商品
public void addItem(Product product) {
int id = product.getId();
CartItem item = map.get(id);
if (item != null)
item.increaseQuantity();
else
map.put(id, new CartItem(product, 1));
}
//getTotalPrice 用于獲取購(gòu)物車(chē)?yán)锼猩唐返目們r(jià)格
public int getTotalPrice() {
int total = 0;
for (CartItem item : map.values())
total += item.getProduct().getPrice() * item.getQuantity();
return total;
}
} Cart 主要實(shí)現(xiàn)三個(gè)業(yè)務(wù)函數(shù), getItems 用于獲取當(dāng)前購(gòu)物車(chē)?yán)锏奈锲?#xff0c; addItem 用于向購(gòu)物車(chē)添加商品, getTotalPrice 用于獲取購(gòu)物車(chē)?yán)锼猩唐返目們r(jià)格。
8.2.在 shopping.xml 中添加配置
在 shopping flow 開(kāi)始時(shí)必須分配一個(gè) Cart 對(duì)象,由于要調(diào)用 subflow ,這個(gè) Cart 對(duì)象應(yīng)存放于 conversationScope 中。同時(shí)要添加一個(gè) subflow-state 用于執(zhí)行添加商品到購(gòu)物車(chē)的任務(wù)。清單 31 shopping.xml 中添加的配置 <var name="mycart" class="samples.webflow.Cart" />
<on-start>
<set name="conversationScope.cart" value="mycart"></set>
</on-start>
<!-- view-state中的view對(duì)應(yīng)jsp文件夾中的jsp頁(yè)面,on是觸發(fā)事件,to對(duì)應(yīng)state id -->
<view-state id="viewCart" view="viewCart">
<on-render>
<!-- 要在 viewCart 頁(yè)面中顯示商品,只需在 view-state 元素的 on-render 切入點(diǎn)調(diào)用 productService
的 getProducts 方法,并將所得結(jié)果保存到 viewScope 中即可 -->
<evaluate expression="productService.getProducts()" result="viewScope.products" />
</on-render>
<transition on="submit" to="viewOrder" />
<transition on="addToCart" to="addProductToCart" />
</view-state>
<subflow-state id="addProductToCart" subflow="addToCart">
<transition on="productAdded" to="viewCart" />
</subflow-state>
8.3.在 /WEB-INF/flows 目錄下添加 addToCart.xml
清單 31 中 subflow-state 元素的 subflow 屬性即指明了這個(gè)被調(diào)用的 flow 的 id 為“ addToCart ”,現(xiàn)在就要添加addToCart flow的定義。
清單 32 addToCart.xml<?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-2.0.xsd">
<on-start>
<set name="requestScope.productId" value="requestParameters.productId" />
</on-start>
<action-state id="addToCart">
<evaluate expression="cart.addItem(productService.getProduct(productId))" />
<transition to="productAdded" />
</action-state>
<end-state id="productAdded" />
</flow>
addToCart flow 主要由一個(gè) action-state 構(gòu)成,完成添加商品到購(gòu)物車(chē)的功能, addToCart flow 的實(shí)現(xiàn)需要有輸入?yún)?shù),即 productId 。在本示例中是通過(guò)請(qǐng)求參數(shù)來(lái)傳遞,通過(guò) requestParameters 來(lái)獲取該數(shù)值。這里還要注意到清單 32 中的 end-state 的 id 為“ productAdded ”,與清單 31 中 subflow-state 中的 transition元素的on屬性的名稱(chēng)是對(duì)應(yīng)的。
8.4.在 webflow-config.xml 中添加 addToCart.xml 的位置
新增加的 flow 不要忘記在 flow-registry 中注冊(cè)。
清單 33 flow-registry 中注冊(cè) addToCart<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/shopping.xml" id="shopping"/>
<webflow:flow-location path="/WEB-INF/flows/addToCart.xml" id="addToCart"/>
</webflow:flow-registry>
8.5.修改 viewCart.jsp 頁(yè)面
最后就可以來(lái)看在視圖中如何顯示相關(guān)的信息,并觸發(fā)相應(yīng)的 webflow 事件,見(jiàn)清單 34:
清單 34 完整的 viewCart.jsp 的代碼<?xml version="1.0" encoding="utf-8" ?>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>View Cart</title>
</head>
<body>
<h1>View Cart</h1>
<h2>Items in Your Cart</h2>
<c:choose>
<c:when test="${empty cart.items}">
<p>Your cart is empty.</p>
</c:when>
<c:otherwise>
<table border="1" cellspacing="0">
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
<c:forEach var="item" items="${cart.items}">
<tr>
<td>${item.product.description}</td>
<td>${item.quantity}</td>
<td>${item.product.price}</td>
<td>${item.totalPrice}</td>
</tr>
</c:forEach>
<tr>
<td>TOTAL:</td>
<td></td>
<td></td>
<td>${cart.totalPrice}</td>
</tr>
</table>
</c:otherwise>
</c:choose>
<a href="${flowExecutionUrl}&_eventId=submit">Submit</a>
<h2>Products for Your Choice</h2>
<table>
<c:forEach var="product" items="${products}">
<tr>
<td>${product.description}</td>
<td>${product.price}</td>
<td><a
href="${flowExecutionUrl}&_eventId=addToCart&productId=${product.id}">[add
to cart]</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
8.5.運(yùn)行效果
圖 6 添加購(gòu)物車(chē)后的效果8.6代碼實(shí)例
CartApp5代碼實(shí)例下載地址:http://www.dbank.com/download/CartApp5.rar?f=c0n9qasa5r&i=4&h=1321064658&v=7aab5c3a9.global transition 簡(jiǎn)介
顧名思義, global transition 是一種全局的 transition ,可在 flow 執(zhí)行的各個(gè) state 中被觸發(fā)。
清單 35 global-transitons<global-transitions>
<transition on="cancelShopping" to="returnToIndex"/>
</global-transitions> 客戶(hù)端請(qǐng)求中如果包含 _eventId=cancelShopping ,則會(huì)重新回到 index.jsp 頁(yè)面。
轉(zhuǎn)載于:https://www.cnblogs.com/zhanghaiyang/p/7213566.html
總結(jié)
以上是生活随笔為你收集整理的Spring Web Flow实例教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: libreoffice
- 下一篇: SFTP例子2----使用JSch实现S