20、使用Spring Web Flow(2)(Spring笔记)

三、组合起来:披萨流程

这里我们通过订购披萨的过程对流程进行说明。我们首先从构建一个高层次的流程开始,它定义了订购披萨的整体过程。接下来,我们会将这个流程拆分成子流程,这些子流程在较低层次定义了细节。

3.1 定义基本流程

一个新的披萨店决定允许用户在线订购以减轻店面电话的压力。当顾客访问Pizza站点时,他们需要进行用户识别,选择一个或更多披萨添加到订单中,提供支付信息然后提交订单并等待披萨送过来。如图所示。

20、使用Spring Web Flow(2)(Spring笔记)_第1张图片
1

下面给出实现披萨订单的整体流程:




    
    
    
    
      
      
    
    
    
    
      
      
    
        
    
    
      
            
    
        
    
        
        
    
    
    
      
    
                
    
    
    
    
      
    

说明:在流程定义中,首先第一件事就是order变量的声明。每次流程开始的时候,都会创建一个Order实例。

package com.springinaction.pizza.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Configurable;

@Configurable("order")
public class Order implements Serializable {
   private static final long serialVersionUID = 1L;
   private Customer customer;//顾客
   private List pizzas;//pizza
   private Payment payment;//支付详情

   public Order() {
      pizzas = new ArrayList();
      customer = new Customer();
   }

//getter 和setter方法这里省略
}

说明:默认情况下,流程定义文件中的第一个状态也会是流程访问中的第一个状态。本例中,也就是identifyCustomer状态(一个子流程)。也可以通过元素的start-state属性显示的指定任意状态为开始状态:




......

说明:

  • 识别顾客、构造披萨订单以及支付这样的活动太复杂了,并不适合将其强行塞入一个状态。后面将其单独定义为流程。但是为了更好地整体了解披萨流程,这些活动都是以元素来进行展现的。

  • 流程变量order将在前三个状态中进行填充并在第四个状态中进行保存。identifyCustomer子流程状态使用元素来填充ordercustomer属性,将其设置为顾客子流程收到的输出。buildOrdertakePayment状态使用了不同的方式,使用order流程变量作为输入,这些子流程就能在其内部填充order对象。

  • 在订单得到顾客、一些披萨和支付细节后,saveOrder对其进行保存,是处理这个任务的行为状态。订单完成保存后,会转移到thankCustomer,这是一个简单的视图状态,后台使用"/WEB-INF/flows/flowspizza/thankCustomer.jsp",如下:


Spring Pizza

    

Thank you for your order!

Finish ]]>

说明:在此页面中,会感谢顾客的订购并为其提供一个完成流程的链接。这个链接展示了用户与流程交互的唯一办法。此处提供了一个flowExecutionUrl变量,它包含了流程的URL。结束链接将一个"_eventId"参数关联到URL上,以便回到Web流程时触发finished事件。这个事件将会让流程到达结束状态。流程将会在结束状态完成。鉴于在流程结束后没有下一步做什么的具体信息,流程将会重新从identifyCustomer状态开始,以准备接受另一个披萨订单。

3.2 收集顾客信息

顾客在订购披萨的时候,我们需要知道用户的详细信息,特别是地址信息。这里可以根据电话号码进行查询(已注册过的用户),如果查询不到,则需要像用户询问。整个流程如下图所示:


20、使用Spring Web Flow(2)(Spring笔记)_第2张图片
2

下面对整个流程进行定义:





    
    



    
    
    



    
      
    
    
    



  



    
    



    
    

        



    



    

说明:这里书中有些地方可能是有点问题的。此流程应该说是整个订购流程的第一个分支identifyCustomer,所以,对比来看,这里首先是定义了一个customer的变量,而最后将customer进行了输入,这与大流程是相符的。

3.2.1 询问电话号码

下面给出欢迎视图:"/WEB-INF/flows/pizza/customer/welcome.jsp"

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

    Spring Pizza
    
        

Welcome to Spring Pizza!!!


说明:表单中有一个隐藏的"_flowExecutionKey"输入域。当进入视图状态时,流程暂停并等待用户采取一些行为。赋予视图的流程执行key(flow execution key)就是一种返回流程的“回程票”(claim ticket)。当用户提交表单时,流程执行key会在“_flowExecutionKey”输入域中返回并在流程暂停的位置进行恢复。同时,按钮的名字“_eventId_”部分是提供给Spring Web Flow的一个线索,它标明了接下来要触发的事件。当点击这个按钮提交表单时,会触发phoneEntered事件进而转移到lookupCustomer

3.2.2 查找顾客

目前,lookupCustomer()方法的实现并不重要,这里只需要知道要么返回customer对象,要么抛出异常。返回的结果会通过result属性设置到输入变量customer中。

3.2.3 注册新顾客

注册表单如下:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

    Spring Pizza
    
        

Customer Registration

Phone number:
Name:
Address:
City:
State:
Zip Code:

3.2.4 检查配送区域

在配送表单中需要告知顾客不能将披萨送到它们的地址(就是警告表单deliveryWarning.jsp):

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

    Spring Pizza
    
        

Delivery Unavailable

The address is outside of our delivery area. The order may still be taken for carry-out.

Accept | Cancel

说明:这里提供了两个链接,允许用户继续订单或者取消。通过使用与welcome状态相同的flowExecutionUrl变量,这些链接分别触发流程中的acceptcancel事件。

3.2.5 存储顾客数据

这里使用addCustomer()方法对用户地址等数据进行保存,并将customer流程参数传递进去。

3.2.6 结束流程

这里给出了两个流程结束状态,而且使用进行输出,这和整个披萨订购流程是相符合的。

3.3 构建订单

在识别完顾客之后,主流程的下一个事件就是确定它们想要干什么类型的披萨。订单子流程就是用于提示用户创建披萨并将其放入订单中的,如图所示。


20、使用Spring Web Flow(2)(Spring笔记)_第3张图片
3

整个流程较为简单,下面看如何定义此流程:





    
    
    



    
      
      
    
    
      
    
    





说明:首先是输入一个order,这是主流程上创建的Order对象,这里使用将主流程的Order对象进行了输入。createPizza状态的视图是一个表单,这个表单可以添加新的Pizza对象到订单中。元素添加了一个新的Pizza对象到流程作用域内,当表单提交时,表单的内容会填充到该对象中。需要注意的是,这个视图状态引用的model是流程作用域内的同一个Pizza对象(都是flowScope.pizza

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

Create Pizza

Size:




Toppings:


说明:这里对于showOrder.jsp就不给出了。当通过Continue按钮提交时,相关数据会绑定到Pizza对象中且触发addPizza转移。

3.4 支付

支付流程较为简单,首先是输入相关的支付信息,然后提交。具体流程如图所示。


20、使用Spring Web Flow(2)(Spring笔记)_第4张图片
4

下面给出流程定义:




    
      

      
    
    
    



    
    

        



说明:对于选择支付信息的页面这里就不给出了。这里在进入视图时,元素构建了一个支付表单并创建了一个PaymentDetails实例。之后还创建了视图作用域的paymentTypeList变量,这个变量是一个列表包含了PaymentType枚举的值。这里需要调用一个adList()方法。

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 asList() {
    PaymentType[] all = PaymentType.values();
    return Arrays.asList(all);
  }
  
  @Override
  public String toString() {
    return WordUtils.capitalizeFully(name().replace('_', ' '));
  }
}

说明:至此,整个流程就执行完了。

你可能感兴趣的:(20、使用Spring Web Flow(2)(Spring笔记))