Spring webflow

项目中用到了webflow的相关知识,就上网学习了一下,借鉴他人的经验,做了一个简单的example。


1、首先解释一下 为什么使用webflow?

web应用程序的三种范围:request,session,appcation。

1)request适合存放大量的临时数据。

2)session适合存放本次会话需要保留的数据。

3)application适合存放那些与应用程序全局相关的数据。

session中存放大量的数据会严重影响效率,request的存放有效范围有限,那么就需要一种,介于session和request之间的范围,spring提过了flow解决这个问题。(还有一种conversion, 与flow基本相同,唯一不同在于 conversation 范围内的对象所在的 flow 如果调用了其他 subflow ,那么在 subflow 中也可访问该对象)。


flow使用于比较复杂的,有状态的,需要在多个页面之间跳转的业务流程问题。


2、案例:模拟简单的购物车流程

购物车-〉显示订单-〉确认订单


1)Spring web flow关注的是业务的流程。是Spring Web MVC的一个扩展,所以需要对它进行配置。

2)配置web.xml文件

  <servlet>
      <servlet-name>CartServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/config/web-application-config.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
  </servlet>
 
  <servlet-mapping>
      <servlet-name>CartServlet</servlet-name>
      <url-pattern>/jsp/*</url-pattern>
  </servlet-mapping>
 

    配置 web-application-config.xml

<!-- 搜索 samples.webflow 包里的 @Component 注解,并将其部署到容器中 -->
    <context:component-scan base-package="samples.webflow" />
    <!-- 启用基于注解的配置 -->
    <context:annotation-config />
    <import resource="webmvc-config.xml"/>


    配置webmvc-config.xml

    webmvc-config.xml主要配置mvc,添加一个viewResolver(视图解析器),用于将视图名解析成真实的视图资源。再配置URL请求的handler(处理器),用于将url请求定向到某个控制器。viewMappings 中的/shopping.do=flowController指明不管设成 /shopping.do 还是设成 /shopping ,或者 /shopping.htm ,效果都是一样的, flowController 都会去找 id 为 shopping的flow来执行。

<bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <bean id="viewMappings"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
         <!-- /shopping.do 请求由 flowController 来处理 -->
        <property name="defaultHandler">
            <!-- UrlFilenameViewController 会将 "/index" 这样的请求映射成名为 "index" 的视图 -->
            <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
        </property>
         <property name="mappings">
            <value> /shopping.do=flowController </value>
        </property>
    </bean>
    <bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>


    配置webflow-config.xml和shopping.xml(业务流程的具体流动过程)

    webflow-config.xml中配置仓库们的总的配置
     <webflow:flow-executor id="flowExecutor"/>

    <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
        <webflow:flow-location path="/WEB-INF/flows/shopping.xml" id="shopping"/>
        <webflow:flow-location path="/WEB-INF/flows/addToCart.xml" id="addToCart" />
    </webflow:flow-registry>
   
    <!--Web Flow 中的视图通过 MVC 框架的视图技术来呈现 -->
    <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>
    <!-- 指明 MVC 框架的 view resolver ,用于通过 view 名查找资源 -->
    <bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
        <property name="viewResolvers" ref="viewResolver" />
    </bean>

    flowExecutor是web flow的一个核心接口,启动某个flow,要通过这个接口进行,会被flowController作为参数。

    flowRegistry是存放flow的仓库,每个定义flow的xml文件都会被分配一个唯一的id, 以FlowDefinition对象的形式存放在FlowRegistry中。每个flow都要有id标识,如果省略,那么flow默认的id就是文件名称,删除后缀的字符串,例如shopping.xml的默认id是shopping。

    flow-builder-services是flow-registry的一个重要属性,它指明了flow-registry仓库中flow的一些基本特性,在本案例中,它用来指明flow中所用到的view,由viewResolver来查找,有view class来解析,最后呈现给用户。

   shopping.xml中是具体的业务流程

    <view-state id="viewCart" view="viewCart">
        <transition on="submit" to="viewOrder"></transition>
    </view-state>
    <view-state id="viewOrder" view="viewOrder">
        <transition on="submit" to="viewConfirmed"></transition>
    </view-state>
    <view-state id="viewConfirmed" view="viewConfirmed">
        <transition on="returnToIndex" to="returnToIndex"></transition>
    </view-state>
    <end-state id="returnToIndex" view="externalRedirect:servletRelative:/index.jsp"></end-state>

    web flow中的元素:五种state,分别是Action State、View State、Subflow State、Decision State、End State,transition来实现到其他state的转换,转换的发生一般由事件来触发。

    view是视图资源的名字, 是viewResolver查找的名字。最后的end-state中externalRedirect用在view名字中,表示所指向的资源是在flow的外部,servletRelative则表明所指向资源的路径起始部分与flow所在servlet相同。


3)添加jsp文件

 

viewCart.jsp

<body>
    <h1>View Cart</h1>
    <a href="${flowExecutionUrl}&_eventId=submit">Submit</a>
</body>


viewOrder.jsp

<h1>Order</h1>
<a href="${flowExecutionUrl}&_eventId=confirm">Confirm</a>


orderConfirmed.jsp

<h1>Order Confirmed</h1>
<a href="${flowExecutionUrl}&_eventId=returnToIndex">Return to index</a>


flowExecutionUrl表示flow执行到当前状态时的url,它的值由spring web flow 框架的代码赋值,并放入相应的model中供view访问。它的值包含flow在执行过程中会为每一个状态生成唯一的key,因此不可以用其他手段获得。_eventId与shopping.xml中的transition的on属性的值对应。在接收到_eventId的值是,相应的transition就会执行。


3、Spring Web Flow 如何与 Spring Web MVC 整合在一起?

接收servlet 容器会找到相应的应用程序(本教程中即为 CartApp ),客户端发送的请求,先会由 servlet 容器再根据 web.xml 的配置找到出符合映射条件的 servlet 来处理。

Spring Web MVC 中处理请求的 servlet 是 DispatcherServlet ,如果请求的路径满足 DispatcherServlet 的映射条件,则 DispatcherServlet 会找出 Spring IoC 容器中所有的 HandlerMapping ,根据这些 HandlerMapping 中匹配最好的 handler (一般情况下都是 controller ,即控制器)来处理请求

当 Controller 处理完毕,一般都会返回一个 view (视图)的名字,DispatcherServlet再根据这个view的名字找到相应的视图资源返回给客户端。

1)这里的flow是flowController,在webmvc-config.xml中配置的。用于接收指定flow的请求,然后根据请求启动相应的flow。FlowController是webflow中自带的现成的控制器,可以根据客户端请求的结尾部分,找出相应的flow来执行,需要指定flowExecutor。

另外还有一个FlowHandler可以实现该功能,内部需要研发人员实现,灵活性比较大,可以参见Spring Web Flow文档。


4、业务逻辑代码在调用后得到的数据如何保存、传递?

Spring Web Flow 的定义中可直接使用表达式语言( Expression Language ),前面的代码都是用的 Unified EL ,对于习惯用 OGNL 的开发人员,可通过 flow-builder-services 的配置改成使用 OGNL 。不管是哪一种表达式语言, Spring Web Flow 都提供了一些固定名称的变量,用于数据的保存、传递。在 Spring Web Flow 的解决方案 一节中,已经提到 Spring Web Flow 所着力解决的问题即是数据存取范围的问题,为此, Spring Web Flow 提供了两种比较重要的范围,一是 flow 范围,另一个是 conversation 范围。通过 flowScope 和 conversationScope 这两个变量, Spring Web Flow 提供了在这两种范围里存取数据的方法。清单 24演示了如何将业务逻辑代码执行的结果存放到flow范围中。

<evaluate expression="productService.getProducts()" result="flowScope.products" /> 
注意:Spring Web Flow 2.0 在默认配置下,flowScope 和 conversationScope 的实现依赖于 Java 序列化和反序列化技术,因此存放于 flowScope 或 conversationScope 中的对象需要实现 java.io.Serializable 接口。


Spring Web Flow 还提供了大量其他的变量,以方便数据的存取。如 viewScope 范围即是从进入 view-state 至退出 view-state 结束, requestScope 即和一般的 request 范围没什么区别,等等。另外还有一些用于获取 flow 以外数据的变量,如 requestParameters 、 messageContext 等等。具体变量的列表可参看 Spring Web Flow自带的文档。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值