配置好 Spring Web MVC 的環境後,接下來就可以往裡面加入 Spring Web Flow 2.0 的配置。不過,要搞明白 Spring Web Flow 2.0 的配置,必須先要了解相關的理論知識。
FlowRegistry
FlowRegistry 是存放 flow 的倉庫,每個定義 flow 的 XML 文檔被解析後,都會被分配一個唯一的 id ,並以 FlowDefinition 對象的形式存放在 FlowResigtry 中。 FlowRegistry 配置方式可參看清單 8。
說明
以下的示例清單中的 XML 配置元素默認使用了 webflow 名字空間,這也是 Spring Web Flow 習慣上的名字空間,參看教程後面 webflow-config.xml 文件,可以更多了解 webflow 名字空間。
清單 8 FlowRegistry 的配置
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/flows/shopping.xml" id=”shopping”/>
</webflow:flow-registry>
每個 flow 都必須要有 id 來標識,如果在配置中省略,那麼該 flow 默認的 id 將是該定義文件的文件名去掉後綴所得的字符串。
FlowExecutor
FlowExecutor 是 Spring Web Flow 的一個核心接口,啟動某個 flow ,都要通過這個接口來進行。從配置角度來說,只要保證有個 FlowExecutor 就可以了, Spring Web Flow 的默認行為已經足夠。默認配置參看清單9。
清單 9 FlowExecutor 的配置
<webflow:flow-executor id="flowExecutor" />
哪個 flow 被執行了?
FlowRegistry 中注冊的 flow 可能會有多個,但前面介紹過,每個 flow 都會有 id ,沒有配置的,也會有個默認值, FlowExecutor 就是通過 id 來找出要執行的 flow 。至於這個 id ,則是要由用戶來指定的。在默認配置情況下,如果客戶端發送了如下URL請求:
http://localhost:8080/CartApp/spring/shopping
則從 Spring Web Flow 的角度來看,這個 URL 就表示客戶想要執行一個 id 為“ shopping ”的 flow ,於是就會在 FlowRegistry 中查找名為“ shopping ”的 flow,由FlowExecutor負責執行。
Spring Web Flow 如何與 Spring Web MVC 整合在一起?
客戶端發送的請求,先會由 servlet 容器(本教程示例中即為 Tomcat )接收, servlet 容器會找到相應的應用程序(本教程中即為 CartApp ),再根據 web.xml 的配置找到出符合映射條件的 servlet 來處理。 Spring Web MVC 中處理請求的 servlet 是 DispatcherServlet ,如果請求的路徑滿足 DispatcherServlet 的映射條件,則 DispatcherServlet 會找出 Spring IoC 容器中所有的 HandlerMapping ,根據這些 HandlerMapping 中匹配最好的 handler (一般情況下都是 controller ,即控制器)來處理請求。當 Controller 處理完畢,一般都會返回一個 view (視圖)的名字,DispatcherServlet再根據這個view的名字找到相應的視圖資源返回給客戶端。
搞清楚 Spring Web MVC 處理請求的流程後,基本上就可以明白要整合 Spring Web MVC 與 Spring Web Flow 所需要的配置了。為了讓客戶端的請求變成執行某個 flow 的請求,要解決以下幾個問題:
需要在某個 HandlerMapping 中配置負責處理 flow 請求的 handler (或 controller )
該handler (或 controller )要負責啟動指定的 flow
flow 執行過程中以及執行完成後所涉及的視圖應呈現給客戶端
FlowHandler 和 FlowController
現在,需要一種接收執行 flow 的請求,然後根據請求來啟動相應 flow的handler (處理器), Spring Web Flow 2.0 提供了兩種方案可供選擇。第一種方案是自己編寫實現了 FlowHandler 接口的類,讓這個類來實現這個功能。第二種方案是使用一個現成的叫做 FlowController 的控制器。第一種方案靈活性比較大,在許多場合可能也是唯一的選擇,但對每個 flow 都需要編寫相應的 FlowHandler 。本教程的示例采用第二種方案,對 FlowHandler 的介紹可參看 Spring Web Flow 2.0 自帶的文檔。 FlowController 其實是個適配器,一般來講,我們只要明白 FlowController 可根據客戶端請求的結尾部分,找出相應的 flow 來執行。配置 FlowController只需指定FlowExecutor即可,具體配置見清單10:
清單 10 FlowController 的配置
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
另外還需在 HandlerMapping 中指明 /shopping.do 請求由 flowController 來處理,配置見清單11:
清單 11 在 viewMappings 中添加配置
<bean
id="viewMappings"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/shopping.do=flowController
</value>
</property>
…...
</bean>
需要指出的是,不管設成 /shopping.do 還是設成 /shopping ,或者 /shopping.htm ,效果都是一樣的, flowController 都會去找 id 為 shopping的flow來執行。
FlowBuilder Services
清單 8 所示 FlowRegistry 的配置,其中省略了 flow-registry 元素中一項比較重要的屬性, flow-builder-services 。 flow-builder-services 屬性的配置指明了在這個 flow-registry “倉庫”裡的 flow 的一些基本特性,例如,是用 Unified EL 還是 OGNL 、 model (模型)對象中的數據在顯示之前是否需要先作轉換,等等。在本示例中,我們需要在 flow-builder-services 屬性中指明 Spring Web Flow 中所用到的 view ,由 Spring Web MVC 的“ View Resolver ”來查找,由 Spring Web MVC 的“ View Class”來解析,最後呈現給客戶。具體配置參看清單12:
清單 12 flow-builder-services 配置
<webflow:flow-builder-services id="flowBuilderServices"
view-factory-creator="mvcViewFactoryCreator"/>
<bean
id="mvcViewFactoryCreator"
class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="viewResolver"/>
</bean>
Spring Web Flow 2.0 配置小結
所有這些配置的目的無非是兩個:一是要讓客戶端的請求轉變成 flow 的執行,二是要讓 flow 執行過程中、或執行結束後得到的視圖能返還給客戶端。如果對這裡的講解還不是很清楚,可先看下一節實際的配置,再回過頭來看本章內容,以加深理解。