Spring Web Flow

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-patternbase-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}&amp;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 进入视图状态时创建,当这个状态退出时销毁
  1. flowScope
  2. requestParameters
  3. flowRequestContext
  4. requestScope
  5. 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>

找到的类似文章链接

推荐阅读更多精彩内容