在Spring 中配置 Web Flow
<?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.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd"> ? <!-- 装配流程执行器,负责创建和执行流程 --> <flow:flow-executor id="flowExector" /> ? <!-- 配置流程注册表,负责加载流程定义,供流程执行器使用 --> <flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows"> <!-- 在 base-path 下查找所有匹配的文件作为流程定义 --> <flow:flow-location-pattern value="*-flow.xml"/> </flow:flow-registry> <!-- 帮助 Dispatcher 将流程请求发送给 Spring Web Flow --> <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> <property name="flowRegistry" ref="flowRegistry" /> </bean> ? <!-- 负责响应流程的请求并进行处理 --> <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> <property name="flowExecutor" ref="flowExecutor" /> </bean> ? </beans>
流程的组件
1、状态
Spring Web Flow 定义了五种不同类型的状态
- 行为(Action): 行为状态时流程逻辑发生的地方
- 决策(Decision): 决策流程将流程分成两个方向,基于流程数据确定流程方向
- 结束(End): 结束状态是流程的最后一站,进入此状态后流程终止
- 子流程(Subflow): 子流程状态会在当前正在运行的流程上下文中启动一个新的流程
- 视图(View): 视图状态会暂停流程并邀请用户参与流程
视图状态
视图状态用于为用户展现信息并使用户在流程中发挥作用。实际的视图通常是 JSP 来实现的
在 xml 中定义 <view-state id="welcomt" view="greeting" model="flowScope.paymentDetails" />
如果没有显示指定 view 属性,那么它的值与 id 相同
行为状态
行为状态一般会触发 Spring 所管理的 bean 的一些方法并根据方法调用的执行结果转移到另一个状态
在 xml 中定义
<action-state id="saveOrder"> <evalute expression="pizzaFlowActions.saveOrder(order)" /> <transition to="thankYou" /> </action-state>
决策状态
决策状态能够在流程执行时产生两个分支。决策状态将评估一个 Boolean 类型的表达式,然后在两个状态转移中选择一个
在 xml 中定义
<decision-state id="checkDeliveryArea"> <if test="pizzFlowActions.checkDeliverArea(customer.zipCode)" then="addCustomer" else="deliveryWarning" /> </decision-state>
子流程状态
子流程状态允许在一个正在执行的流程中调用另一个流程
在 xml 中定义
<subflow-state id="order" subflow="pizza/order"> <input name="order" value="order" /> <transition on="orderCreated" to="payment" /> </subflow-state>
结束状态
结束状态指定了流程的结束
在 xml 中声明: <end-state id="customerReady" />
2、转移
转移连接了流程中的状态。流程中除结束状态之外的每个状态,至少都需要一个转移状态,分别对应于当前状态结束时可以执行的不同的路径
一般使用<transition>
元素来进行定义,作为各种状态元素的的子元素(如上面之前定义内容)
<transition on="phoneEntered" to="lookupCustomer" />
on
属性指定触发转移的事件,to
属性指定流程的下一个状态,异常状态跳转是将on
属性改为on-exception="CustomException"
如果转移在多个状态中被使用,可以定义一个全局转移,这样流程中的所有状态都默认拥有此转移
<global-transitions> <transition on="cancel" to="endState" /> </global-transitions>
3、流程数据
流程数据保存在变量中,而变量可以在流程的各个地方进行引用,它能够以多种方式创建
<var name="customer" class="com.pizza.domain.Customer" />
,并且其中的 class 必须实现 Serializable 接口
创建一个新的 Customer 实例并将其放在 customer 变量中
<evaluate resul="viewScope.toppingsList" expression="T(com.pizza.domain.Topping).asList()" />
计算了一个 (SpEL) 表达式并将结果放到了名为 toppingsList 变量中
<set name="flowScope.pizza" value="com.pizza.domain.Pizza()" />
定义流程数据的作用域
Spring Web Flow 定义了五种不同作用域
- Conversation: 最高层级的流程开始时创建,结束时销毁。被其及其所有子流程共享
- Flow: 流程开始时创建,结束时销毁。只有在创建它的流程中可见
- Request: 当一个请求进入流程时创建,流程返回时销毁
- Flash: 流程开始时创建,结束时销毁。在视图状态渲染结束时被清除
- View: 进入状态视图时创建,退出这个状态时销毁。只有在视图状态内可见
使用<var>
元素声明变量时,变量始终是流程作用域的,也就是在定义变量的流程内有效
使用<set>
或<evaluate>
时,作用域通过 name 或 result 属性的前缀指定,如
<set name="flowScope.theAnswer" value="42" />
使用之前介绍的这些流程组件,即可将其组装起来形成一个成熟且完善功能的 web 流程
下面展示一个简单的流程文件(订购披萨流程)
<?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.3.xsd" start-state="identifyCustomer"> ? <var name="order" class="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>