Spring Web Flow


本文是CAS的热身篇,在深入了解CAS之前必须先具备这块的基本知识。否则很难弄明白CAS的内部原理。

本文是Spring Web Flow的入门篇,适用于对Spring Web Flow的入门学习。

本文是Spring Web Flow的实战篇,适用于Spring Web Flow的项目实战参考。

 

CAS在登录时包括很多步骤,比如检查票据是否已经登录,校验用户名密码,分发授权票据,跳转登录页面,重定向子系统等。

我们一般会使用MVC框架实现,编写登录页面填写用户名密码、定义model传递数据,实现Action来做登录校验。如果使用MVC来处理,这个Action将会非常复杂(方法得有多长?代码得有多少if else?),特别是要修改登录流程的时候,更加麻烦,非常不容易维护。这个时候更需要一个流程引擎,来管理这个复杂的登录流程,CAS的架构师们也正是这么做的。

CAS的架构师们选用了spring web flow作为登录流程引擎,来管理登录流程。

我们知道,在传统的Web应用程序里,有request、session、application三个作用域。request用来保存单次请求的数据,请求完数据就销毁,我们通常用它来传递view和controller之间的数据。session用于保存用户会话的数据,会话结束后数据就销毁,我们通常用它来保存当前登录的用户信息、权限信息等。application用于保存应用级别的数据,应用停止后数据销毁,我们通常用它来保存应用全局的数据。

CAS登录是个流程,包含多个步骤,如果用request来传递model,则每个步骤都要查询和保存model,多次操作model,不仅代码量冗长,而且多次数据的交互,会严重影响登录的性能。如果用session来保存model,很明显太浪费服务器资源了(登录流程执行完数据就用不到了)。这时候迫切需要一种介于request和session之间的流程级别范围的容器来传递数据model。

Spring web flow正是这种介于request和session之间的流程级别数据传递的解决方案。

本文内容包括Spring web flow的基础知识,然后通过实例来了解Spring webflow如何应用到实际的项目中。

Spring Web Flow基础知识

Spring Web Flow 是构建在SpringMVC之上的web流程解决方案。这里web流程的意思是为了实现某个业务的一系列步骤组成的集合:它跨越多个HTTP请求,具有状态,可处理业务数据,可重用,并且可能是动态的,可长期运行的。

总结下来,Spring Web Flow主要目的是为以下场景提供解决方案:

需要连续的多个步骤组合、多次与后端交互来完成某个业务,为了更好的扩展性,最好能支撑业务流程编排。如购物流程可拆分为【结算】->【下单】->【支付】三个步骤来完成,且每个步骤可能包含多个子步骤完成。

本节将会介绍Spring Web Flow的基础知识,涉及它的工作原理和基础组件。

Spring Web Flow工作原理

Spring Web Flow是构建于SpringMVC之上的,他们的工作原理基本一致。

首先,DispatcherServlet接收用户的请求。跟其他MVC框架一样,SpringMVC实现了一个DispatcherServlet来处理用户的请求。

然后,通过处理器映射找到对应Handler,构建HandlerAdapter。

再然后,执行自定义Handler的业务逻辑,并返回模型和逻辑视图名(ModelAndView)

再然后,视图解析器进行视图的解析和渲染。

最后,将渲染好的视图响应给用户。

SpringMVC工作原理

Spring Web Flow工作原理

SpringMVC和Spring Web Flow原理对比

对比两张原理图可知,SpringMVC和Spring Web Flow执行流程完全相同,不同的只有第2步和第4步的子步骤。

2-1,获取HandlerMapping

HandlerMapping是映射具体实现关键组件。它决定了谁去执行URL对应的业务。

SpringMVC返回的是RequestMappingHandlerMapping,RequestMappingHandlerMapping负责映射用户自定义的method。

Spring Web Flow返回的是FlowHandlerMapping,它是Spring Web Flow自己实现的HandlerMapping,用于映射流程。

2-2,获取Handler

2-1已经说过,HandlerMapping的目的就是映射具体执行业务的Handler。

SpringMVC返回的是用户添加@RequestMapping注解的method。

Spring Web Flow返回的是Web Flow实现的FlowHandlerMapping.DefaultFlowHandler。

2-3,获取HandlerAdapter

HandlerAdapter是DispatcherServlet和Handler之间的桥梁,负责调起具体的Handler。

SpringMVC返回的是RequestMappingHandlerAdpater,用于调起用户自定义的Handler(添加@RequestMapping注解的method)。

Spring Web Flow返回的是FlowHandlerAdapter,用于通过FlowExecutor执行器,执行流程。

3-1,执行业务

SpringMVC通过RequestMappingHandlerAdpater调起自定义实现的Handler(添加@RequestMapping注解的method)执行业务。

Spring Web Flow通过FlowHandlerAdapter调起FlowExecutor执行器(自定义的流程模型)驱动流程业务的执行。

Spring Web Flow组件

Spring Web Flow实现了若干个组件来支撑web流程控制,其中比较核心的组件有连接SpringMVC并驱动流程执行的流程执行组件、定义流程模型的流程模型组件、以及传输数据的作用域组件。其中流程模型组件可分为流程状态组件和连接各流程步骤并决定流程走向的转移组件。

流程执行组件

流程执行组件负责连接SpringMVC,并驱动流程的执行,相当于流程执行引擎,没有它就无法执行流程。流程执行组件包括流程执行器、流程注册表、流程处理器映射以及流程执行适配器。

FlowExecutor:流程执行器,负责驱动流程的执行。当用户进入一个流程时,流程执行器会创建并启动一个流程执行器实例。

FlowRegistry:流程注册表,负责注册流程定义,并为FlowExecutor提供查找流程的方法。FlowExecutor的成员变量。

FlowHandlerMapping:流程处理器映射,负责在处理流程过程中根据流程ID映射FlowHandler。

FlowHandlerAdapter:DispatcherServlet和Spring Web Flow之间的桥梁,负责调起flowExecutor。

流程模型组件

流程模型组件是构建流程的基本组件,用户用它来定义流程模型。其核心有两个部分,状态组件和转移组件。

状态组件

流程模型的状态组件即流程的步骤,包含五种状态组件,涵盖了流程处理中的各个场景。

Action:行为状态,执行流程逻辑的地方,一般对应后端的一个Action或逻辑方法。

Decision:决策状态,相当于流程中的判断节点,返回true/false,决定流程下一步的走向。

End:结束状态,流程一旦走到End状态,就代表流程结束了。

Subflow:子流程状态,会在当前正在运行的流程上下文上创建一个新的子流程。

View:视图状态,流程中和用户交互的页面,可以是JSP,thymeleaf等其他模版引擎。

转移组件

转移组件连接了各流程状态,负责决定流程状态的执行走向。

transition:转移组件,执行流程时决定流程的走向。

流程数据作用域

Spring Web Flow为了实现流程不同场景的数据传输,实现了不同的流程数据作用域。

Conversation:最高层级的流程开始时创建,最高层级的流程结束时销毁。这里的最高层级流程是相对于包含子流程的流程而言的,即父子流程之间Conversation范围的数据是共享的,可以互相访问。如果没有子流程,则它和Flow的作用域是一样的。

Flow:流程开始时创建,流程结束时销毁。这里是相对于流程本身而言的,子流程和父流程之间是隔离的。

Request:进入流程时创建,流程返回时销毁。

Flash:流程开始时创建,流程结束或渲染视图状态后销毁。

View:进入视图状态时创建,退出这个状态时销毁。它只在视图状态内是可见的。

 

Spring Web Flow实例 - 自驾游

每次过节从北京回家都要经过北京-廊坊-德州-济南,途中会遇到很多各种各样的事情,比如出发之前会收拾要带回家的东西,走到廊坊可能会去尝尝那里的香河肉饼,走到德州可能会去弄个扒鸡吃,半道上没油了去找加油站加油。。。

这整个过程就是个flow,可以通过spring web flow来模拟这次回家流程。

实现过程

使用Sping Web Flow实现流程需要实现两个部分

1、配置流程执行环境

2、实现流程模型

其中实现流程模型又包括定义流程模型、定义流程后端Action和数据模型、编写前端页面。

注意:

1、实现过程可以通过xml和注解两种方式,本例中基于Spring Boot实现,所以选用了注解的方式。

2、过程中的示例代码只会给出核心部分,完整的实现可以从https://github.com/417511458/learn_webflow下载。

 

配置流程执行环境

配置流程执行环境即配置流程执行组件,流程执行组件是驱动流程执行的基础组件,所以这块是共用的,且必须配置的。流程执行环境的配置内容包括:

1、流程执行组件

2、SpringMvc和Web Flow的适配器

3、视图解析器。

配置流程执行组件FlowExecutor和FlowRegistry

注意在FlowExecutor中需要注入flowRegistry。flowRegsitry会从classpath下的flows目录中加载流程模型,并将目录名字作为flowId。

配置SpringMVC和Spring Web Flow的适配器FlowHandlerMapping和FlowHandlerAdapter

注意这里需要注入flowExecutor,因为映射后需要调用flowExecutor驱动流程的执行。

配置视图解析器ThymeleafViewResolver

注意这里要根据前端的模版引擎来配置,因为示例中模版引擎使用的Thymeleaf,所以这里要配置ThymeleafViewResolver。

实现自驾游流程模型

实现流程模型包括:

1、定义流程模型,并放在flowRegistry的加载目录下;

2、定义后端Action和数据模型,和前端页面交互;

3、编写前端页面,展示信息和接收用户数据。

通过分析可知此流程模型可拆分为一个主和两个子流程,主流程为北京-廊坊-德州-济南。子流程为吃饭子流程和加油子流程。

实现主流程

主流程逻辑是这样的:

1、出发前可以从家里带点东西

2、沿途经过北京-廊坊-德州-济南

3、在行进过程中如果没油,则需要找加油站加油。

每到一个城市,我们都可能在这里吃饭、加油,产生交互,所以我们把每个城市定义为可以交互的view-state。把在城市视图中的交互动作吃饭和加油转向到各自的子流程subflow-state,把继续前进动作定义为action-state,因为继续出发是动作,需要判断没油的话就不能出发,而是去加油。

然后实现后端Action

ToSomePlaceAction,所有出发Action的抽象类,每个城市耗油20L。

这里默认返回success,即下一个城市视图,如果油不够了,则返回error,即回到当前城市视图,并提示需要加油。

主流程效果图

实现加油子流程

加油子流程包括加油和结账两个步骤,且结束后回到当前的城市视图。它和主流程的实现步骤都是一样的,需要注意的是子流程的end-state一定要是主流程中的其中一个状态,我们这里的逻辑是这四个城市视图之一。

加油流程效果预览

实现吃饭子流程

吃饭子流程包括点菜和结账两个步骤,且结束后回到当前的城市视图。实现逻辑和加油子流程一样,需要注意结束视图定义为当前所在的城市视图。

吃饭流程效果预览

源码下载

完整代码下载地址:https://github.com/417511458/learn_webflow

结束语

自驾游的例子是生活中的流程抽象,购物可能是会经常遇到的电商业务场景实现。

我们可以把购物定义为一个简单流程:

加入购物车:action-state,将商品加入购物车,在Action里需要判断是否登录、将商品加入购物车等。

购物车结算:view-state,结算页,展示购物车商品。

提交订单:view-state,展示订单信息。并提供对应的Action,验证库存信息、计算折扣、生成订单等。

支付:view-state,收银台视图。并提供对应的Action,验证支付信息、支付等。

注意:这里是简单示例下,实际的场景中非常复杂,每个步骤都要定义成subflow来处理。

 

 

原创文章,转载请注明出处:转载自小马过河 - Spring Web Flow


Jbone

Spring Cloud实战项目jbone正在开发中, jbone功能包括服务管理、单点登录、系统管理平台、内容管理平台、电商平台、支付平台、工作流平台等子系统。欢迎关注!

GitHub 码云
马军伟
关于作者 马军伟
写的不错,支持一下

先给自己定个小目标,日更一新。