吃免费披萨这事儿并不常见。如果 Spizza 披萨店让他们的顾客不提供支付信息就订购披萨的话,估计他们也维持不了多久。在披萨流程要结束的时候,最后的子流程提示用户输入他们的支付信息。这个简单的流程如图 8.5 所示。
你可以看到,进入支付子流程的时候,用户会到达 takePayment 状态。这是一个视图状态,在这里用户可以选择使用信用卡、支票或现金进行支付。提交支付信息后,将进入 verifyPayment 状态。这是一个行为状态,它将校验支付信息是否可以接受。
程序清单 8.10 支付子流程有一个视图状态和一个行为状态
<?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">
<input name="order" required="true"/>
<view-state id="takePayment" model="flowScope.paymentDetails">
<on-entry>
<set name="flowScope.paymentDetails"
value="new com.springinaction.pizza.domain.PaymentDetails()" />
<evaluate result="viewScope.paymentTypeList"
expression="T(com.springinaction.pizza.domain.PaymentType).asList()" />
</on-entry>
<transition on="paymentSubmitted" to="verifyPayment" />
<transition on="cancel" to="cancel" />
</view-state>
<action-state id="verifyPayment">
<evaluate result="order.payment" expression=
"pizzaFlowActions.verifyPayment(flowScope.paymentDetails)" />
<transition to="paymentTaken" />
</action-state>
<!-- End state -->
<end-state id="cancel" />
<end-state id="paymentTaken" />
</flow>
在流程进入 takePayment 视图时,元素将构建一个支付表单并使用 SpEL 表达式在流程作用域内创建一个 PaymentDetails 实例,这是支撑表单的对象。它也会创建视图作用域的 paymentTypeList 变量,这个变量是一个列表包含了 PaymentType 枚举(如程序清单 8.11 所示)的值。在这里,SpEL 的 T() 操作用于获得 PaymentType 类,这样就可以调用静态的 asList() 方法。
程序清单 8.11 PaymentType 枚举定义了用户可用的支付选项
package com.springinaction.pizza.domain;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.text.WordUtils;
public enum PaymentType {
CASH, CHECK, CREDIT_CARD;
public static List<PaymentType> asList() {
PaymentType[] all = PaymentType.values();
return Arrays.asList(all);
}
@Override
public String toString() {
return WordUtils.capitalizeFully(name().replace('_', ' '));
}
}
现在,我们已经依次介绍了披萨流程及其子流程,并看到了 Spring Web Flow的很多功能。在我们结束 Spring Web Flow 话题之前,让我们快速了解一下如何对流程及其状态的访问增加安全保护。