Spring Web Flow

类别:Java 点击:0 评论:0 推荐:



2005年3月
转自 .style1 { COLOR: #0000ff } :http://www.nirvanastudio.org/nicholas/SpringWebFlow.htm

介绍

你是否觉得当你的Web应用越来越复杂,理解和管理页面流程—驱动你应用程序用例的乐谱—也越来越困难了呢?而被迫使用特定的方式做事情并且无法重用是不是让你感觉很累?你是否觉得使用了太多时间开发你自己特定的方法去解决普遍问题就像会话状态管理?

进入Spring Web Flow。

什么是Spring Web Flow?

Spring Web Flow (SWF) 是Spring Framework的一个脱离模块。这个模块是Spring Web应用开发模块栈的一部分,Spring Web包含Spring MVC。

Spring Web Flow 的目标是成为管理Web应用页面流程的最佳方案。当你的应用需要复杂的导航控制,例如向导,在一个比较大的事务过程中去指导用户经过一连串的步骤的时候,SWF将会是一个功能强大的控制器。

以下是一个受控制的导航的例子,使用UML状态图描述:

图 1 - 一个航空订票服务流程

聪明的读者会认出这个是一个典型的航空订票流程,就是那种每次你通过在线方式参与订票的过程。

为什么出现Spring Web Flow?

在传统的Web应用中,页面流程就像上面所展示的,不是很明确 — 他们不是一等公民。就拿一个使用Struts的Web应用举个例子,为了在Struts里面实现页面流,大多数开发人员利用了框架提供的Action和视图。在这种情况下,一个单独的Action就和一个指定的请求URL产生了联系。只有当请求从那个URL过来的时候,Action才会被执行。在执行过程中,Action运行一些处理并且选择一个合适的视图显示结果。这非常简单。

所以要在Struts中实现多步控制的页面流,你需要通过不同的视图将独立的Action形成链。用来处理不同事件,例如“后退”或“提交”的Action URL都是硬编码在视图中的。一些ad-hoc形式的会话存储被用来管理流程状态。提交后重定向被用来阻止重复提交,等等。

虽然这是一个简单并且有效的方法,但是它具有一个很大的缺陷:从struts-config.xml文件的Action定义中不能清晰的看到页面流程。你无法从几棵树看到一片森林,就像你无法从Action和视图的定义看到页面流程一样。灵活性也因为Action和视图不能被重用而大打折扣。最后,你仍然需要做很多工作,这并不见得容易。

Spring MVC提供了一个轻便的高层次的功能:表单控制器实现了一个与定义的页面流程。它提供了两个这样的控制器:SimpleFormController和AbstractWizardController。尽管如此,这些仍然是大多数页面流程控制概念的例子。

Tapestry和JSP在页面的基础上而不是请求的基础上使用事件驱动的方法,使得每个页面和它的后退控制器逻辑保持一致。然而,仍然需要提供一个优秀的类根据一个定义良好的能跨越多个页面和不同路径的生存周期去支持一个逻辑页面流程。就如你所看到的,这个页面流程的生存周期要比单一的请求长,但是却比一个会话要短。

这就是Spring Web Flow的切入点,允许你使用一个简单清晰的方法体现你的页面流程,并且随时重用,包括像Struts、Spring MVC、Tapestry、JSP甚至Portlets这些环境下。

优点

正如你所看到的,Spring Web Flow提供以下优点:

Web应用中的页面流程可以通过Web流程的定义(XML文件或者Java类)清晰的展现出来。 Web流程被设计成自包含的。这就允许你把你的应用中的一部分看作是一个模块,这样就你可以在多种场合重用它。 Web流程捕获任何合理的页面流程总是使用同种技术。你不必被迫在特定的场合使用特定的控制器。 最后,Web流程是一等公民并且可以通过一个良好定义的契约使用。它具有一个清晰的,可观察的生存周期为你自动管理。通过简单配置,系统便会为你管理复杂的逻辑,总而言之,这非常容易使用。 Spring Web Flow是如何工作的?

现在已经有能力说Web流程是一组状态(states)的集合。一个状态是流程中发生某事的一个点。举个例子,譬如显示一个视图或者执行一个Action。每个状态都有一个或更多的转变(transitions)用来移动到下一个状态。

一个转变是由一个事件(event)触发的。

航空订票Web流程示例

为了展示一个Web流程的定义,下面的XML片段展示了上面UML状态图定义的航空订票处理:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN" "http://www.springframework.org/dtd/spring-webflow.dtd"> <webflow id="bookflight" start-state="obtainTripInfo"> <action-state id="obtainTripInfo"> <action bean="bookingActions" method="bindAndValidate"/> <transition on="success" to="suggestItineraries"/> <transition on="error" to="tryAgain"/> </action-state> <action-state id="suggestItineraries"> <action bean="bookingActions"/> <transition on="success" to="displaySuggestedItineraries"/> </action-state> <view-state id="displaySuggestedItineraries" view="suggestedItenaries"> <transition on="startOver" to="cancel"/> <transition on="select" to="selectItinerary"/> </view-state> <action-state id="selectItinerary"> <action bean="bookingActions"/> <transition on="success" to="isPassengerInfoRequired"/> </action-state> <decision-state id="isPassengerInfoRequired"> <if test="${requestScope.passenger == null}" then="enterPassengerInformation"/> <if test="${requestScope.passenger.preferences.alwaysConfirmPassengerInfo}" then="enterPassengerInformation" else="displayReservationVerification"/> </decision-state> <subflow-state id="enterPassengerInformation" flow="passenger"> <attribute-mapper> <input value="${requestScope.passenger.id}" as="passengerId"/> </attribute-mapper> <transition on="finish" to="displayReservationVerification"/> </subflow-state> <view-state id="displayReservationVerification" view="reservationVerification"> <transition on="startOver" to="cancel"/> <transition on="assignSeats" to="chooseSeatAssignments"/> <transition on="book" to="book"/> </view-state> <subflow-state id="chooseSeatAssignments" flow="seatAssignments"> <attribute-mapper> <input value="${requestScope.passenger.id}" as="passengerId"/> <input name="itinerary"/> </attribute-mapper> <transition on="finish" to="displayReservationVerification"/> </subflow-state> <action-state id="book"> <action bean="bookingActions"/> <transition on="success" to="displayConfirmation"/> </action-state> <end-state id="displayConfirmation" view="reservationConfirmation"/> <end-state id="tryAgain" view="tryAgain"/> <end-state id="cancel" view="home"/> </webflow>

图 2 - 基于XML的航空订票流程定义

就像你所看到的,仅仅是扫过XML定义,逻辑流程驱动的订票流程处理就已经可以清晰地辨认出来了,即使你都不了解Spring Web Flow实现细节。

如果你看得仔细点,你将会发现两个子流程产生了订票流程的子过程。第一个子流程指导用户输入乘客信息。第二个让用户分配他的座位。这个内嵌的流程扮演了“迷你应用程序模块”的角色,这是Spring Web Flow强大的功能之一。

你可以将这份定义上交给一位业务分析人员,并且她估计能看懂。更好的是你可以根据这个定义绘制一个可视化图表将其提交给业务分析人员。做这个的工具已经诞生了。

航空订票流程祥解

这篇文章的下一部分将逐块分解上面的航空订票流程定义,并且提供对话框演示Spring Web Flow是如何工作的。

流程定义

这是第一行的XML流程定义:

<webflow id="bookflight" start-state="obtainTripInfo"> ... </webflow>

webflow

本文地址:http://com.8s8s.com/it/it9602.htm