8.3.4 支付

吃免费披萨这事儿并不常见。如果 Spizza 披萨店让他们的顾客不提供支付信息就订购披萨的话,估计他们也维持不了多久。在披萨流程要结束的时候,最后的子流程提示用户输入他们的支付信息。这个简单的流程如图 8.5 所示。

像订单子流程一样,支付子流程也使用 <input> 元素接收一个 Order 对象作为输入。

你可以看到,进入支付子流程的时候,用户会到达 takePayment 状态。这是一个视图状态,在这里用户可以选择使用信用卡、支票或现金进行支付。提交支付信息后,将进入 verifyPayment 状态。这是一个行为状态,它将校验支付信息是否可以接受。

使用 XML 定义的支付流程如下所示:

程序清单 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('_', ' '));
  }
}

在面对支付表单的时候,用户可能提交支付也可能会取消。根据做出的选择,支付子流程将以名为 paymentTaken 或 cancel 的 <end-state> 结束。就像其他的子流程一样,不论哪种 <end-state> 都会结束子流程并将控制交给主流程。但是所采用 <end-state> 的 id 将决定主流程中接下来的转移。

现在,我们已经依次介绍了披萨流程及其子流程,并看到了 Spring Web Flow的很多功能。在我们结束 Spring Web Flow 话题之前,让我们快速了解一下如何对流程及其状态的访问增加安全保护。

Last updated