做一个在线的披萨订购应用
实际上,订购披萨的过程可以很好地定义在一个流程中。我们首先从 构建一个高层次的流程开始,它定义了订购披萨的整体过程。接下 来,我们会将这个流程拆分成子流程,这些子流程在较低的层次定义 了细节。
一、定义基本流程
当顾客访问Spizza站点时,他们需要进行用户识别,选择一个 或更多披萨添加到订单中,提供支付信息然后提交订单。
订购披萨的整个流程很简单且是线性的。
1.使用Spring Web Flow的XML流程定义来实现披萨订单的整体流程。
pizza-flow.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <flow xmlns="http://www.springframework.org/schema/webflow" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/webflow 5 http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> 6 7 <var name="order" class="com.springinaction.pizza.domain.Order"/> 8 9 <!-- Customer --> 10 <subflow-state id="customer" subflow="pizza/customer"> 11 <input name="order" value="order"/> 12 <transition on="customerReady" to="order" /> 13 </subflow-state> 14 15 <!-- Order --> 16 <subflow-state id="order" subflow="pizza/order"> 17 <input name="order" value="order"/> 18 <transition on="orderCreated" to="payment" /> 19 </subflow-state> 20 21 <!-- Payment --> 22 <subflow-state id="payment" subflow="pizza/payment"> 23 <input name="order" value="order"/> 24 <transition on="paymentTaken" to="saveOrder"/> 25 </subflow-state> 26 27 <action-state id="saveOrder"> 28 <evaluate expression="pizzaFlowActions.saveOrder(order)" /> 29 <transition to="thankYou" /> 30 </action-state> 31 32 <view-state id="thankYou"> 33 <transition to="endState" /> 34 </view-state> 35 36 <!-- End state --> 37 <end-state id="endState" /> 38 39 <global-transitions> 40 <transition on="cancel" to="endState" /> 41 </global-transitions> 42 </flow>
在流程定义中,第一件事就是order变量的声明。每次流程开始的时候,都会创建一个order实例。order类会带有关于订单的所有信息,包含顾客信息、订购的披萨列表以及支付详情。
2. order带有披萨订单的所有细节信息
1 package com.springinaction.pizza.domain; 2 3 import java.io.Serializable; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 public class Order implements Serializable { 8 private static final long serialVersionUID = 1L; 9 private Customer customer; 10 private List<Pizza> pizzas; 11 private Payment payment; 12 13 public Order() { 14 pizzas = new ArrayList<Pizza>(); 15 customer = new Customer(); 16 } 17 18 public Customer getCustomer() { 19 return customer; 20 } 21 22 public void setCustomer(Customer customer) { 23 this.customer = customer; 24 } 25 26 public List<Pizza> getPizzas() { 27 return pizzas; 28 } 29 30 public void setPizzas(List<Pizza> pizzas) { 31 this.pizzas = pizzas; 32 } 33 34 public Payment getPayment() { 35 return payment; 36 } 37 38 public void setPayment(Payment payment) { 39 this.payment = payment; 40 } 41 }
流程定义的主要组成部分是流程的状态。默认情况下,流程定义文件 中的第一个状态也会是流程访问中的第一个状态。在本例中,也就 是identifyCustomer状态(一个子流程)。但是如果你愿意的 话,你可以通过<flow>元素的start-state属性将任意状态指定 为开始状态。
识别顾客、构造披萨订单以及支付这样的活动太复杂了,并不适合将 其强行塞入一个状态,应该单独定义为流程。但是为了更好地整体了解披萨流程,这些活动都是以 <subflow-state>元素来进行展现的。
流程变量order将在前三个状态中进行填充并在第四个状态中进行保 存。identifyCustomer子流程状态使用了<output>元素来填 充order的customer属性,将其设置为顾客子流程收到的输 出。buildOrder和takePayment状态使用了不同的方式,它们使 用<input>将order流程变量作为输入,这些子流程就能在其内部 填充order对象。
在订单得到顾客、一些披萨以及支付细节后,就可以对其进行保存 了。saveOrder是处理这个任务的行为状态。它使用<evaluate> 来调用ID为pizzaFlowActions的bean的saveOrder()方法,并将 保存的订单对象传递进来。订单完成保存后,它会转移 到thankCustomer。
3.感谢页面(thankCustomer.jsp)
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'thankCustomer.jsp' starting page</title> 13 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 23 </head> 24 25 <body> 26 <h2>Thank you for your order!</h2> 27 <a href="${flowExecutionUrl}&_eventId=finished">Finish</a> 28 </body> 29 </html>
在感谢页面中,会感谢顾客的订购并为其提供一个完成流程的连接。Spring Web Flow为视图的用户提供了一个flowExecutionUrl变 量,它包含了流程的URL。结束链接将一个“_eventId”参数关联到 URL上,以便回到Web流程时触发finished事件。这个事件将会让 流程到达结束状态。流程将会在结束状态完成。鉴于在流程结束后没有下一步做什么的具 体信息,流程将会重新从identifyCustomer状态开始,以准备接 受另一个披萨订单。
目前还缺少的子流程:identifyCustomer、buildOrder、takePayment。