一、Spring web Flow定义
Spring Web Flow(后面简称swf)是一个Web框架,它适用于元素按规定流程运行的程序。Spring Web Flow是Spring MVC的扩展,它支持开发基于流程的应用程序。它将流程的定义于实现流程行为的类和视图分离开来。
下面我们通过生成披萨订单的新Web应用程序。我们会使用Spring Web Flow来定义订单流程。
1.1 swf环境准备
尽管swf是Spring框架的子项目,但它并不是Spring框架的一部分。因此,在构建基于流程的应用程序之前,我们需要在项目的类路径下添加swf。
最新版本的jar包位置(ps:官方网址现在已经不提供直接的jar包下载了)
1.2 基于Spring MVC上构建swf
swf是构建于Spring MVC基础之上的。这意味着所有的流程请求都需要首先经过Spring MVC的DispatcherServlet。我们需要在Spring应用上下文中配置一些Bean来处理流程请求并执行流程。
先看看web.xml的配置信息,算是spring mvc的最小配置了,在这里完全体现不出来swf,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>order</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>order</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>order</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
接下来就是swf重点配置了,先直接看配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:flow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.4.xsd">
<!-- 控制器包路径,对于SWF而言,在这里面增加流程的action -->
<context:component-scan
base-package="com.paner.pizza.controller">
</context:component-scan>
<!-- 适配器和视图解析,指定了jsp查找的路径 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<!-- 流程执行器 -->
<flow:flow-executor id="flowExecutor"
flow-registry="flowRegistry"></flow:flow-executor>
<!-- 配置流程注册表 -->
<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows"
flow-builder-services="flowBuilderService">
<flow:flow-location-pattern value="/**/*-flow.xml"/>
</flow:flow-registry>
<!-- 这两个配置用于将刚才的视图解析器的方式,作用于swf中 -->
<flow:flow-builder-services id="flowBuilderService"
view-factory-creator="mvcViewFactoryCreator"
/>
<bean id="mvcViewFactoryCreator"
class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="viewResolver"/>
</bean>
<!-- 接下来两个配置项,是为了处理流程的请求 -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry"></property>
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"></property>
</bean>
</beans>
说明:
- 流程执行器
<flow:flow-executor>
元素会创建一个流程执行器。流程执行器(flow executor)驱动流程的执行。当用户进入一个流程时,流程执行器会为用户创建并启动一个流程执行实例。当流程暂停的时候,流程执行器会在用户执行操作后恢复流程。当流程暂停的时候,流程执行器会在用户执行操作后恢复流程。
尽管流程执行器负责创建和执行流程,但它并不负责加载流程定义。这个责任落在了流程注册表(flow registry)身上,接下来会创建它。在这里,通过ID来引用了流程注册表。
- 配置流程注册表
</flow:flow-registry>
元素会创建一个流程注册表。 流程注册表(flow registry)的工作是加载流程定义并让流程执行器能够使用它们。
在这里通过flow-builder-services="flowBuilderService
字段定义了jsp的解析方式;<flow:flow-location-pattern value="/**/*-flow.xml"/>
在这里的声明中,流程注册表会在/WEB-INF/flows目录下查找流程定义,这是通过base-path属性指明的。依据 < flow:flow-location-pattern>元素的值,任何文件名以-flow.xml结尾的XML文件都将视为流程定义。
比如我们现在的主流程定义在order-flow.xml文件中,如要在浏览器中加载该流程,只需要输入http://localhost:8080/WebFlow_orderSystem/order,后面的order就是流程默认的id。通过该id找到对应的流程配置文件。
- 处理流程请求
DispatcherServlet一般将请求分发给控制器。但是对于流程而言,我们需要FlowHandlerMapping来帮助DispatcherServlet将流程请求发送给Spring Web Flow。
你可以看到,FlowHandlerMapping装配了流程注册表的引用,这样他就能知道如何请求的URL匹配到流程上。例如,如果我们有一个ID为springpizza的流程,FlowHandlerMapping就会知道如果请求的URL模式是“/springpizza”的话,就要将其匹配到这个流程上。、
然而,FlowHandlerMapping的工作仅仅是将流程请求定向到Spring Web Flow上,响应请求的是FlowHandlerAdapter。FlowHandlerAdapter等同于Spring MVC的控制器,它会响应发送的流程请求并对其进行处理。
这个处理器适配器是DispatcherServlet和Spring Web Flow之间的桥梁。它会处理流程请求并管理基于这些请求的流程。在这里,它装配了流程制定器的引用,而后者是为请求执行的流程。
二、流程的组件
在Spring Web Flow中,流程是由3个主要元素定义的:状态、转移和流程数据。
状态(State)是流程中事件发生的地点。如果你将流程想象成公路旅行,那状态就是路途上的城镇、路边饭店以及风景点。流程中的状态是业务逻辑执行、作出决策或将页面展现给用户的地方,而不是在公路旅行中买薯片和可乐的所在。
如果流程状态就像公路旅行中停下来的地点,那转移(transition)就是连接这写点的公路。在流程中,你通过转移的方式从一个状态到另一个状态。
当你在城镇之间旅行的时候,你可能要买一些纪念品、留下一些记忆并在路上获取一些空的零食袋。类似地,在流程处理中,它要收集一些数据:流程的当前状况。
2.1 状态
Spring Web Flow定义了5中不同的类型的状态,如下表所示。
通过选择Spring Web Flow的状态几乎可以把任意的安排功能构造成会话式的Web应用程序。
- 视图状态用来为用户展现信息并使用用户在流程中发挥作用。实际的视图实现可以是Spring支持的任意视图类型,但通常使用JSP来实现的;
- 视图状态涉及流程应用程序的用户,而行为状态则是应用程序自身在执行任务。行为状态一般会触发Spring所管理Bean的一些方法并根据方法调用的执行结果转移到另一个状态。
- 有可能流程会完全按照线性执行,从一个状态进入另一个状态,没有其他的替代路线。但是更常见的情况是流程中某一个点根据流程的当前情况进入不同的分支。
- 决策状态能够使得在流程执行时产生两个分支。决策将评估一个Boolean类型的表达式,然后在两个状态转移中选择一个,这是要取决于表达式会计算出true还是false。在XML流程定义中,决策状态通过元素进行定义。
- 你可能不会将应用程序的所有逻辑写在一个方法中,而是将其分散到多个类、方法以及其他结构中。
- 当到达状态,流程会结束。接下来发生什么取决于几个因素。
- 如果结束的流程是一个子流程,那调用它的流程将会从处继续执行。的ID将会用作事件触发从开始的转移。
- 如果设置了view属性,指定的视图将会被渲染。视图可以是相对于流程的路径也可以是流程模板。加externalRedirect:前缀将重定向到流程外部的页面而添加flowRedirect:将重定向到另一个流程中。
- 如果结束的流程不是子流程也没有指定view属性,那这个流程只是会结束。浏览器最后会加载流程的基本URL地址,当前已没有活动的流程,所以会开始一个新的流程实例。
2.2 转移
转移连接流程中的状态。流程中除结束状态的每个状态,至少需要由一个转移,这样能够知道一旦这个状态完成时流程要去向哪里。状态可以由多个转移,分别对应于当前状态结束时可以执行的不同的路径。
转移使用元素来进行定义,它会作为各种状态元素的子元素。最简单的形式就是元素在流程中指定下一个状态:
属性to用于指定流程的下一个状态。如果只使用了to属性,那这个转移就会是当前状态的默认转移选项,如果没有其他可用转移的话,就会使用它。
2.2 流程数据
当流程从一个状态进行到另一个状态时,它会带走一些数据。有时候,这些数据只需要很短的时间。有时候,这些数据会在整个流程中传递并在流程结束的时候使用。
声明变量
流程数据保存在变量中,而变量可以在流程的任意地方进行引用。它能够以多种方式创建。在流程中创建变量的最简单形式是使用元素:
<var name="customer" class="com.spring.pizza.domain.Customer" />
作为行为状态的一部分或者作为视图状态的入口,你可能会使用元素来创建变量。
<evaluate result="viewScope.toppingsList"
expression="T(com.spring.pizza.domain.Tooping).asList()" />
元素也可以设置变量的值:<set name="flowScope.pizza"
value="new com.spring.pizza.domain.Pizza()" />
元素与元素很类似,都是将变量设置为表达式计算的结果。
定义流程数据的作用域
流程中携带的数据会拥有不同的生命作用域和可见性,这取决于保存数据的变量本身的作用域。Spring Web Flow定义了5种作用域,如表所示:
到此,swf相关的基本知识已经介绍完了。下面开始进入披萨流程了
版权声明:本文为博主原创文章,未经博主允许不得转载。