Spring Web Flow :流程,基于Spring MVC 的DispatchServlet
使用方法
- 配置命名空间,目前不支持java方式的配置
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/webflow"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow.xsd">
- 流程执行器,负责创建和执行流程执行器
webflowContext.xml
<webflow:flow-executor id="logoutFlowExecutor" flow-registry="logoutFlowRegistry">
<webflow:flow-execution-attributes>
<webflow:always-redirect-on-pause value="false"/>
<webflow:redirect-in-same-state value="false"/>
</webflow:flow-execution-attributes>
</webflow:flow-executor>
- 配置流程注册器,加载流程定义,并让执行器能够使用它们.
webflowContext.xml
<webflow:flow-registry id="logoutFlowRegistry" flow-builder-services="builder" base-path="/WEB-INF/webflow">
<webflow:flow-location-pattern value="/logout/*-webflow.xml"/>
</webflow:flow-registry>
也可以用 <webflow:flow-location path=""/>
指定一个绝对路径,而不用webflow:flow-location-pattern
和base-path
-
配置服务构造器
webflowContext.xml
<webflow:flow-builder-services id="builder"
development="true"
view-factory-creator="viewFactoryCreator"
expression-parser="expressionParser"/>
- 处理流程请求
cas-servlet.xml
FlowHandlerMapping
帮助DispatchServlet将请求发送给Spring Web Flow
<!-- logout webflow configuration -->
<bean id="logoutFlowHandlerMapping" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"
p:flowRegistry-ref="logoutFlowRegistry" p:order="3">
<property name="interceptors">
<array value-type="org.springframework.web.servlet.HandlerInterceptor">
<ref bean="localeChangeInterceptor"/>
</array>
</property>
</bean>
FlowHandlerMapping
的工作仅仅是将请求重定向给 Spring Web Flow
响应请求的是FlowHandlerAdapter
等同于Spring MVC的控制器,处理请求.配置如下:cas-servlet.xml
<bean id="logoutHandlerAdapter" class="org.jasig.cas.web.flow.SelectiveFlowHandlerAdapter"
p:supportedFlowId="logout" p:flowExecutor-ref="logoutFlowExecutor"
p:flowUrlHandler-ref="logoutFlowUrlHandler"/>
<bean id="logoutFlowUrlHandler" class="org.jasig.cas.web.flow.CasDefaultFlowUrlHandler"
p:flowExecutionKeyParameter="RelayState"/>
流程的组件
如果流程是旅行,那么状态就是路途上的城镇,风景点,转移就是公路,流程数据就像一路买的纪念品和记忆
-
状态
状态类型 | 它是用来做什么的 |
---|---|
视图(view) | 暂停流程并邀请用户参与流程 |
行为(Action) | 行为状态,流程逻辑发生的地方 |
决策(Decision) | 基于流程数据的评估结果确定流程方向 |
子流程(SubFlow) | 在当前的流程上下文中启动一个新的流程 |
结束(End) | 流程的最后一站 |
- 视图状态:
<view-state id="redirectToFrontApp" view="externalRedirect:#{currentEvent.attributes.logoutUrl}&RelayState=#{flowExecutionContext.key}">
<transition on="next" to="frontLogout" />
</view-state>
属性解释
id:在流程内标识这个状态,(逻辑视图名)
view:展现的逻辑视图名
model:表单所绑定的对象
<view-state id="viewLoginForm" view="casLoginView" model="credential" >
<binder>
<binding property="username" required="true" />
<binding property="password" required="true"/>
<binding property="captcha"/>
<!--
<binding property="rememberMe" />
-->
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'"/>
<!--
<evaluate expression="samlMetadataUIParserAction" />
-->
</on-entry>
<!-- <transition on="submit" bind="true" validate="true" to="realSubmit"/> -->
<transition on="submit" bind="true" validate="true" to="validate"/>
</view-state>
- 行为状态
例子:
<action-state id="frontLogout">
<evaluate expression="frontChannelLogoutAction" />
<transition on="finish" to="finishLogout" />
<transition on="redirectApp" to="redirectToFrontApp" />
</action-state>
或
<action-state id="validate">
<evaluate expression="captchaVaditeAuthenticationViaFormAction.validate(flowRequestContext, flowScope.credential, messageContext)"/>
<transition on="error" to="initializeLogin"/>
<transition on="valid" to="realSubmit"/>
</action-state>
属性解释:
evaluate:行为状态要做的事情
expression : 调用那个Action,并计算结果.用SpEL表达式
- 决策状态
决定分支
<decision-state id="serviceCheck">
<if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess"/>
</decision-state>
test
是SpEL表达式,返回结果必须是Boolean格式,可以调指定bean(一般是Action)中的一个方法.
- 子流程状态
<subflow-state id="order" subflow="pizza/order">
<input name="order" value="order"/>
<transition on="orderCreated" to=" payment" />
</subflow-state>
- 结束状态
<end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}"/>
或
<end-state id="viewRedirectToUnauthorizedUrlView" view="externalRedirect:#{flowScope.unauthorizedRedirectUrl}"/>
view:如果是externalRedirect:
前缀,将重定向到流程的外部页面;如果是flowRedirect:
前缀,将重定向到另一个流程中
-
转移
<transition on="finish" to="finishLogout" />
<transition on="front" to="frontLogout" />
Action中返回的写法
if (needFrontSlo) {
return new Event(this, FRONT_EVENT);
} else {
// otherwise, finish the logout process
return new Event(this, FINISH_EVENT);
}
如果只有to属性,则是默认的转移状态
异常转移
<transition to="viewServiceErrorView"
on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException"/>
全局转移 将重复写的共用的转移抽取出来
<global-transitions>
<transition to="viewLoginForm" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException"/>
<transition to="viewServiceErrorView"
on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException"/>
<transition to="serviceUnauthorizedCheck" on-exception="org.jasig.cas.services.UnauthorizedServiceException"/>
<transition to="serviceUnauthorizedCheck" on-exception="org.jasig.cas.services.UnauthorizedServiceForPrincipalException" />
</global-transitions>
-
流程数据
- 声明变量
<var name="credential" class="org.jasig.cas.authentication.RememberMeUsernamePasswordCredential" />
或
<evaluate result="viewScope.toppingsList" expression="T(com.springinaction.pizza.domain.Topping).asList()"/>
#viewScope 视图作用域
或
<set name="flowScope.pizza" value="new com.springinaction.pizza.domain.Pizza()"/>
#flowScope 流程作用域
var定义的可以在流程的任意状态访问.
作用域
范围 | 生命作用域和 可见性 |
---|---|
Conversation | 最高层级的流程开始创建,被最高层级及其所有子流程共享 |
flow | 只有在创建他的流程中是可见的,var是流程作用域的 |
Request | 请求进入流程时创建,流程返回时销毁 |
Flash | 流程开始时创建,结束时销毁,在视图状态渲染后也会被清除 |
View | 进入视图状态时创建,当这个状态退出时销毁 |
- flowScope
- requestParameters
- flowRequestContext
- requestScope
- requestScope.response.responseType.name() == 'POST'"
开始状态:默认是第一个流程定义文件中的第一个状态,也可以用 start-state
<on-start>
<evaluate expression="initialFlowSetupAction"/>
</on-start>
<input type="hidden" name="execution" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submit" />
-### 实例
-### 保护Web流程
<view-state id="restricted"> <secured attributes="ROLE_ADMIN" match="all"/>
</view-state>
网友评论