Spring Web Flow是Spring MVC的扩展,它支持开发基于流程的应用程序.它将流程的定义与实现流程行为的类和视图分离开来.
在
Spring中配置Web Flow
Spring Web Flow是构建于Spring MVC的基础上的,这意味着所有的流程请求都需要首先经过DispatcherServlet.我们需要在Spring应用上下文中配置一些Bean来处理流程并执行请求.
首先,我们在Spring的基础上会多使用到4个jar包,并且会使用到flow命名空间
配置
做好了准备工作,让我们一起来看一下配置
装配流程执行器
在Spring配置文件中使用<flow:flow-executor>元素创建一个流程执行器.
正如其名,流程执行器驱动流程的执行,用户进入一个流程时,流程执行器会为用户创建并启动一个流程执行实例,当流程暂停的时候(如为用户展示视图时),流程执行器会在用户执行操作后恢复流程.流程执行器只负责创建和执行流程,但它并不负责加载流程定义.这个任务由流程注册表完成
|
|
配置流程注册表
在Spring配置文件中使用<flow:flow-register>配置流程注册表,流程注册表的工作是加载定义并让流程执行器能够使用它们.
|
|
如果不使用通配符,这里也可以使用<flow:flow-location id="pizza" path="/WEN-INF/flows/springpizza.xml"/>来指定流程配置文件的详细位置,当不显示指定id时,以文件名作为id的值
处理流程请求
在Spring MVC的基础上,还需要一个FlowHandlerMapping来帮助DispatcherServlet发送流程请求给spring web flow,在Spring的上下文中添加如下配置
|
|
可以看到,它装配了流程注册表的引用,这样它就能知道如何将请求的URL匹配到流程上
FlowHandlerMapping仅是对流程请求的处理,响应请求由FlowHandlerAdapter处理,它会把响应发送的流程请求进行处理,在Spring的上下文中添加如下配置:
|
|
这样,所有的准备工作都已经做完了!但这还不够,在定义流程前,我们先来看一下流程组件
流程组件
在Spring Web Flow中,流程是由三个主要元素定义的:状态、转移和流程数据.
状态(state)
即流程中事件的发生地点,如果将流程比喻成公路旅行,那么状态就是路途上的城镇或风景点,一共有五种不同的状态
| 状态类型 | 作用 |
|---|---|
| 行为(action) | 行为状态是流程逻辑发生的地方 |
| 决策(decision) | 决策状态将流程分成两个方向,它会基于流程数据的评估结果确定流程方向 |
| 结果(end) | 结束状态是流程的最后一站,一旦进入End状态,流程就会终止 |
| 子流程(subflow) | 子流程状态会在当前正在运行的流程上下文中启动一个心的流程 |
| 视图(view) | 视图状态会暂停流程并邀请用户参与流程 |
视图状态
视图状态用于为用户展现信息并使用户在流程中发挥作用,可以是任意Spring支持的视图类型.在下面的示例中,id在流程内标识这个状态,当不使用view显示指定另一个视图名称时,它也代表视图的名称,model指明表单所绑定的对象
行为状态
行为状态是应用程序自身在执行任务,行为状态一般会触发Spring所管理的Bean的一些方法并根据方法调用的执行结果转移到另一个状态.如下例,其中的evaluate子节点代表行为状态要做的事,在此处它会找到id为pizzaFlowActions的bean并执行saveOrder()方法
决策状态
决策状态能够在流程执行时产生两个分支.决策状态将评估一个Boolean类型的表达式,然后在两个状态中选择转移一个.可以看到,if子节点是这个状体的核心,test中的表达式值为true则转移到then指定状态,否则转移到else指定状态
子流程状态
就像把代码逻辑分写到多个类/方法中一样,流程也将其分成一些子流程.如下例中子流程结束的<endstate>的id为orderCreated,则流程将会进入到名为payment的状态
结束状态
所有的流程均会结束,这就是结束状态要做的事情.
在流程结束后,接下来会发生什么取决于以下因素:
- 如果结束流程是一个子流程,那么调用它的流程将会从
<subflow-state>处继续执行,<end-state>的id将会用作事件触发从<subflow-state>开始的转移 - 如果
<end-state>设置了view属性,指定的视图将会被渲染.视图可以是相对于流程路径的视图模版,如果添加externalRedirect:前缀话,将会重定向到流程外部的页面,如果添加flowRedirect:将会重定向到另一个流程中 - 如果结束的流程不是子流程,也没有指定
view属性,那这个流程只是会结束而已,浏览器最后将会加载流程的基本URl地址,当前已没有活动的流程,所以会开始一个新的流程实例
==流程可能会有不止一个结束状态,子流程的结束状态id确定了激活的事件,所以可以通过多钟结束状态来结束子流程,从而能够在流程中触发不同的事件,即使不是在子流程中,在结束流程后也可以根据流程的执行情况进行多个页面的选择==
转移
流程中除结束状态之外的每个状态都至少需要一个转移,使用<transition>子节点来定义,在前面可能你已经看到了他的身影.它是action-state/view-state/subflow-state的子节点,其中id可以是用户触发的事件,在子流程中,事件取决于子流程结束的id,任何事件都可以使用no来触发转移事件,当抛出异常时,可以使用on-exception来指定异常的转移状态.
全局转移:在多个状态中都需要用到的转移,可以定义成全局转移
流程数据
定义变量
流程数据保存在变量中,而变量可以在流程的各个地方进行引用,它能够以多钟方式创建,在流程中创建变量的最简单形式就是使用<var>元素
当然,也可以使用<evaluate>元素计算并创建一个变量
也可以使用<set>元素设置变量的值
后面两个特别类似,都是通过计算生成结果
流程数据的作用域
| 范围 | 作用域与可见性 |
|---|---|
| Conversation | 最高层级的流程开始创建,在最高层级的流程结束时销毁,被最高层级的流程与子流程共享 |
| Flow | 当流程开始时创建,在流程结束时被销毁,只有在创建它的流程中是可见的 |
| Request | 当一个请求进入流程的时候创建,在流程返回时被销毁 |
| Flash | 当流程开始的时候创建,在流程结束的时候销毁,在视图状态渲染后,它也会被清除 |
| View | 当进入视图状态时创建,当这个状态退出的时候销毁,只在视图状态内可见 |
当使用<var>元素声明时,变量始终是流程作用域的,当使用<set>或<evaluate>的时候,作用域通过name或result属性的前缀指定
以上就是Spring Web Flow 的基础知识,至于Demo可以在《Spring 实战》的指定网站上下载源码,当然啦,也可以百度一下,为了方便起见,可以直接去我建的仓库克隆一下,传送门,这是Spring Web Flow的Demo ,不是全部的源码.