《Spring实战》学习笔记-第八章:使用Spring Web Flow

第四版的第八章内容与第三版基本一致。

本章内容:

  • 创建会话式web应用程序
  • 定义流程状态和行为
  • 保护web流程

互联网的一个奇特之处就在于它很容易让人迷失。有如此多的内容可以查看和阅读,而超链接是其强大魔力的核心所在。

有时候,web应用程序需要控制web冲浪者的导向,引导他们一步步地访问应用。比如电子商务网站的付款流程,从购物车开始,应用程序会引导你依次经过配送详情、账单信息以及最终的订单确认。

Spring Web Flow是一个web框架,它适用于元素规定流程运行的程序。本章中,我们将会探索它是如何用于Spring Web框架平台的。

其实我们可以使用任何的Web框架编写流程化的应用程序,比如使用Struts构建特定的流程。但是这样没有办法将流程与实现分开,你会发现流程的定义分散在组成流程的各个元素中,没有特定的地方能够完整地描述整个流程。

Spring Web Flow是Spring MVC的扩展,它支持开发基于流程的应用程序,可以将流程的定义和实现流程行为的类和视图分离开来。

在介绍Spring Web Flow的时候,我们会暂且放下Spittr样例,而使用生产披萨订单的web程序。

使用的第一步是在项目中进行安装,那么就从安装开始吧。

在Spring中配置Spring Web Flow

Spring Web Flow是基于Spring MVC构建的,这就意味着所有的流程请求都需要经过Spring MVC的DispatcherServlet。我们需要在Spring应用上下文中配置一些Bean来处理流程请求并执行流程。

现在还没有支持使用Java来配置Spring Web Flow,所以没得选,只能在XML中进行配置。有一些Bean会使用Spring Web Flow的Spring配置文件命名空间来进行声明,因此我们需要在上下文定义XML文件中添加相应的命名空间:

<?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"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow-config 
   http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

声明了命名空间后,就可以准备装配Web Flow的Bean了。

编写流程执行器

顾名思义,流程执行器(flow executor )就是用来驱动流程的执行。当用户进入到一个流程时,流程执行器会为该用户创建并启动一个流程执行器的实例。当流程暂停时(例如为用户展示视图时),流程执行器会在用户执行操作后恢复流程。

在Spring中,<flow:flow-executor>元素可以创建一个流程执行器:
<flow:flow-executor id="flowExecutor" />

尽管流程执行器负责创建和执行流程,但它并不负责加载流程定义。这个要由流程注册表(flow registry)负责,下面会创建它。

配置流程注册表

流程注册表的工作就是加载流程定义,并让流程执行器可以使用它们。可以在Spring中使用<flow:flow-registry>进行配置:

<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows">
    <flow:flow-location-pattern value="/**/*-flow.xml" />
</flow:flow-registry>

正如这里声明的,流程注册表会在/WEB-INF/flows目录下寻找流程定义,这个路径是由base-path属性指明的。根据<flow:flow-location-pattern>元素,任何以-flow.xml结尾的XML文件都会被视为流程定义。

所有的流程都是通过其ID来进行引用的。使用<flow:flow-location-pattern>元素,流程的ID就是相对于base-path的路径,或者是双星号所代表的路径,如下图展示了流程ID是如何计算的:
在使用流程定位模式时,流程定义文件相对于基本路径的路径将用作流程的id

另外,你也可以不使用base-path属性,直接显式地声明流程定义文件的位置:

<flow:flow-registry id="flowRegistry">
    <flow:flow-location path="/WEB-INF/flows/springpizza.xml" />
</flow:flow-registry>

这里使用了<flow:flow-location>而不是<flow:flow-location-pattern>path属性直接指定了/WEB-INF/flows/springpizza.xml为流程定义文件。当这样定义时,流程的ID是从流程定义文件的文件名中获取的,这就是springpizza

如果你希望更显示地指定流程ID,那么可以通过<flow:flow-location>元素的id属性来进行设置。例如,要设定pizza作为流程ID,可以这样进行配置:

<flow:flow-registry id="flowRegistry">
    <flow:flow-location id="pizza"
        path="/WEB-INF/flows/springpizza.xml" />
</flow:flow-registry>

处理流程请求

正如前面的章节中提到的,DispatcherServlet会将请求分发给控制器,但是对于流程而言,你需要FlowHandlerMapping来帮助DispatcherServlet将流程请求发送给Spring Web Flow。FlowHandlerMapping的配置如下:

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
    <property name="flowRegistry" ref="flowRegistry" />
</bean>

FlowHandlerMapping装配了注册表的引用,这样它就知道如何将请求的URL匹配到流程上。例如,如果有一个ID为pizza的流程,FlowHandlerMapping就会知道如果请求的URL是/pizza的话,就会将其匹配到这个流程上。

然而,FlowHandlerMapping的工作仅仅是将流程请求定向到Spring Web Flow,响应请求的是FlowHandlerAdapter,它等同于Spring MVC的控制器,会对流程请求进行响应并处理。FlowHandlerAdapter可以像下面这样装配成一个Spring Bean:

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
    <property name="flowExecutor" ref="flowExecutor" />
</bean>

这个处理适配器就是DispatcherServlet和Spring Web Flow之间的桥梁。它会处理流程请求并管理基于这些请求的流程。在这里,它装配了流程执行器的引用,而后者是为请求执行流程的。

现在已经配置了Spring Web Flow所需的Bean和组件,下面所需的就是真正的定义流程了。首先了解下流程的组成元素。

流程组件

在Spring Web Flow中,流程是由3个主要元素组成的:状态(state)、转移(transition)和流程数据(flow data)。状态是流程中事件发生的地点。如果将流程想象成公路旅行,那么状态就是路途上的城镇、路边饭店以及风景点等。流程中的状态是业务逻辑执行、做出决策或将页面展示给用户的地方,而不是在公路旅行中买薯片或者可乐这些行为。

如果说流程状态是公路上停下来的地点,那么转移就是连接这些点的公路。在流程上,需要通过转移从一个状态到达另一个状态。

在城镇间旅行的时候,可能需要购买一些纪念品、留下一下回忆。类似的,在流程处理过程中,它要收集一些数据:流程当前状况等。也许你很想将其称为流程的状态,但是我们定义的状态已经有了另外的含义。

状态

Spring Web Flow定义了5种不同的状态,如下表所示。通过选择Spring Web Flow的状态几乎可以把任意的安排功能构造成会话式的Web应用程序。尽管并不是所有的流程都需要下表中的状态,但最终你可能会经常使用其中几个。

状态类型 作用
行为(Action) 流程逻辑发生的地方
决策(Decision) 决策状态将流程分为两个方向,它会基于流程数据的评估结果确定流程方向
结束(End) 结束状态是流程的最后一站,进入End状态,流程就会终止
子流程(Subflow) 子流程状态会在当前正在运行的流程上下文中启动一个新的流程
视图(View) 视图状态会暂停流程并邀请用户参与流程

首先了解下这些流程元素在Spring Web Flow定义中是如何表现的。

视图状态

视图状态用来为用户展现信息并使用户在流程中发挥作用。实际的视图实现可以是Spring支持的任意视图类型,但通常是用JSP来实现的。

在流程定义文件中,<view-state>用来定义视图状态:

<view-state id="welcome" />

在这个简单的示例中,id属性有两个含义。其一,它定义了流程中的状态。其二,因为这里没有其他地方指定视图,那么它就指定了流程到达这个状态时要展现的逻辑视图名称为welcome。

如果要显示地指定另外一个视图名称,那么就可以使用view属性:

<view-state id="welcome" view="greeting" />

如果流程为用户展现了一个表单,你希望指定表单所绑定的对象,可以使用model属性:

<view-state id="takePayment" model="flowScope.paymentDetails"/>

这里指定了takePayment视图将绑定流程范围内的paymentDetails对象。

行为状态

视图状态包括流程应用的用户,而行为状态则是应用程序自身在执行任务。行为状态一般会触发Spring所管理Bean的一些方法,并跟你讲方法调用的执行结果转移到另一个状态。

在流程定义文件中,行为状态使用<action-state>元素来声明:

<action-state id="saveOrder">
    <evaluate expression="pizzaFlowActions.saveOrder(order)" />
    <transition to="thankYou" />
</action-state>

尽管没有严格要求,但是<action-state>元素一般都有一个<evaluate>子元素,该元素给出了行为状态要做的事情,expression属性指定了进入这个状态时要评估的表达式。本例中,给出的是SpEL表达式,这表明它将会找到ID为pizzaFlowActions的Bean,并调用其saveOrder()方法。

决策状态

流程有可能会按照线性执行下去,从一个状态到另一个状态,没有其他的替代路线。但是更常见的是流程在某一个点根据流程当前情况进入不同的分支。

决策状态能够使得在流程执行时产生两个分支,它会评估一个Boolean表达式,根据结果是true还是false在两个状态转移中选择一个。在流程定义文件中,使用<decision-state>元素来定义决策状态:

<decision-state id="checkDeliveryArea">
    <if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)"
        then="addCustomer"
        else="deliveryWarning" />
</decision-state>

<decision-state>并不是单独工作的,<if>元素是其核心,它是进行表达式评估的地方,如果表达式结果为true,流程会转向then属性指定的状态,为false会转向else指定的状态中。

子流程状态

也许你不会将应用程序的所有逻辑都写在一个方法里,而是将其分散到多个类、方法一起其他结构中。

同样的,将流程分成独立的部分也是个不错的主意。<subflow-state>元素允许在一个正在执行的流程中调用另一个流程:

<subflow-state id="order" subflow="pizza/order">
    <input name="order" value="order"/>
    <transition on="orderCreated" to=
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值