Spring Web Flow 2简化页面流的开发,结合Spring MVC更俊,Spirng Security 3添加安全机制

闲来无事,看看Spring这个生态系统中的各个模块挺不错,简化了很多事情,本文参考Spring Web Flow项目中的booking-mvc这个sample进行了仔细学习,很有收获,该sample主要讲解了Spirng Web Flow的一些核心概念,以及与spring mvc,spring security的组合使用,功力大大增强。

    还是典型的3层模型,dao,service,controller,涉及到Java EE 6的规范主要是JPA2.0,JSR303和JSR250。废话不多说先上例子吧。

    由于dao和service都比较简单,重点讲web层,稍后你会看到dao层我们只声明了接口,并没有写实现代码,这是由于我们借助了spring-data-jpa这个子项目的功能,由spring动态代理实现。大大简化了dao层。spring-data旨在提供一个统一的数据访问层接口。不管你是关系型数据库,还是no database,还是key-value,访问数据接口统一,是门面模式的体现。关于spring-data项目的详细信息,请查看官方信息:http://www.springsource.org/spring-data

    首先,我们来谈谈spring web flow 的一些核心概念:什么是flow呢,引用官方文档的一句话:A flow encapsulates a reusable sequence of steps that can execute in different contexts.大致意思就是说,流就是封装了一个可复用的序列步骤,这些序列步骤可以在不同的上下文环境中执行。哎呀,翻译的好别扭啊。那什么是”state“呢,在spring web flow中,把组成流的一系列的步骤称之为state(姑且叫状态吧),通常,进入一个状态就意味着一个页面视图将要呈现给用户,在这个页面视图中用户可以输入一些数据,而且还可以触发一些事件,比如点击了某个button之类的,而这些事件通常又会把当前的state转移到另外一个state,这就是state的transition(姑且叫转移,过渡也行)。在这些state中还可以执行一些动作,比如将收集到的用户数据,持久化到db中等等。

   介绍完一些基本概念后,我们来具体说一下操作。首先先讲spring web flow 和 spring mvc 的集成,在web.xml中配置spring mvc的前端控制器。配置很简单,如下:

Java代码   收藏代码
  1.  <!-- Loads the Spring web application context -->  
  2.     <listener>  
  3.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  4.     </listener>  
  5.   
  6. <servlet>  
  7.         <servlet-name>mvc</servlet-name>  
  8.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  9.         <load-on-startup>1</load-on-startup>  
  10. </servlet>  
  11.   
  12. <servlet-mapping>  
  13.        <servlet-name>mvc</servlet-name>  
  14.        <url-pattern>/</url-pattern>  
  15. </servlet-mapping>  

 由于我们是基于约定的编程,当mvc这个servlet加载时,会在/WEB-INF/目录下查找文件名为mvc-servlet.xml这个配置文件。下面我们就具体看看spring mvc的配置,首先,我们让spring 扫描web层的controller,代码如下:

Java代码   收藏代码
  1. <context:component-scan base-package="org.leochen.samples.web" />  

 第2步,充分利用mvc这个命名空间的作用,

Java代码   收藏代码
  1. <mvc:annotation-driven />  

 这个打包了一些列功能配置,比如支持JSR 303的验证,以及sprng 3的类型转换和字段的格式化等。

第3步,添加spring mvc对静态资源的处理,结合在web.xml中配置的url-pattern为”/“,

Java代码   收藏代码
  1. <mvc:resources mapping="/resources/**"   
  2.                           location="/resources/,classpath:/META-INF/web-resources/" />  
  3. <mvc:default-servlet-handler />  

 静态资源都放在web根目录下的resources文件下,对所有以/resources开头的请求,都会被映射到web根目录下的resources目录下和类路径下面的META-INF/web-resources(这个是spring-webflow 中一些jar包中的资源文件)目录下查找。

第4步,添加对国际化资源文件的处理,代码如下:

Java代码   收藏代码
  1. <mvc:interceptors>  
  2.        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />  
  3.  </mvc:interceptors>  
  4.   
  5. <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>  
  6.   
  7.   
  8. <bean id="messageSource"   
  9.            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  
  10.        <property name="basenames">  
  11.            <array>  
  12.                <value>/WEB-INF/messages/globalMessage</value>  
  13.                <value>/WEB-INF/messages/validationMessage</value>  
  14.            </array>  
  15.        </property>  
  16.        <property name="defaultEncoding" value="UTF-8" />  
  17.        <property name="cacheSeconds" value="0" />  
  18.  </bean>  

  第5步,配置tiles

Java代码   收藏代码
  1. <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">  
  2.         <property name="definitions">  
  3.             <list>  
  4.                 <value>/WEB-INF/**/views.xml</value>  
  5.             </list>  
  6.         </property>  
  7.     </bean>  
  8.   
  9. <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">  
  10.  <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView" />  
  11. </bean>  

 这里tilesViewResolver 使用的spring web flow中提供的实现类。

   下面来讲讲spring web flow 需要配置的一些东西,我们把这些配置单独放到一个文件中,叫做mvc-webflows.xml,方便管理,最后会在mvc-servlet.xml中include这个spring web flow 的配置文件。

第1步,配置flow-registry,顾名思义,这是spring-webflow流的注册入口,代码如下:

Java代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:webflow="http://www.springframework.org/schema/webflow-config"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.            http://www.springframework.org/schema/webflow-config  
  8.            http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd">  
  9.   
  10.  <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices"  
  11.                   base-path="/WEB-INF/views">  
  12.         <webflow:flow-location-pattern value="/**/*-flow.xml" />  
  13.   </webflow:flow-registry>  

 在这里要着重讲几点:首先这个base-path,表示所有的flow都是在/WEB-INF/views目录下,flow-location-pattern 这个主要是用来查找各个流定义文件,关于流(flow)的id的确定,有以下两种分配算法,如果base-path存在,那么流的id就是从base-path到流的定义文件之间的目录路径,比如说流的定义文件为/WEB-INF/views/hotels/booking/booking-flow.xml,而base-path是/WEB-INF/views,所以flow的id就为hotels/booking.如果base-path不存在或者流的定义文件就在base-path目录下,那么这时flow的id就为流的定义文件名减去后缀(这里我们定义的后缀为-flow.xml),比如说我们的流定义文件叫booking-flow.xml,那么这时flow的id就为booking。

第2步,配置flow executor,流执行器

Java代码   收藏代码
  1. <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">  
  2.        <webflow:flow-execution-listeners>  
  3.            <webflow:listener ref="securityFlowExecutionListener" />  
  4.        </webflow:flow-execution-listeners>  
  5.    </webflow:flow-executor>  

 这里flow-execution-listeners子元素是用来跟spring security 进行集成的,稍后会谈到。

第3步,补齐flow-registry的flow-builder-services属性的相关依赖配置。代码如下:

Java代码   收藏代码
  1. <webflow:flow-builder-services id="flowBuilderServices"  
  2.                                    view-factory-creator="mvcViewFactoryCreator"  
  3.                                    development="true"  
  4.                                    validator="validator" />  
  5.   
  6.     <!-- Installs a listener to apply Spring Security authorities -->  
  7.     <bean id="securityFlowExecutionListener"   
  8.                 class="org.springframework.webflow.security.SecurityFlowExecutionListener" />  
  9.   
  10.     <!-- Configures Web Flow to use Tiles to create views for rendering -->  
  11.     <bean id="mvcViewFactoryCreator"   
  12.                class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">  
  13.         <property name="viewResolvers">  
  14.             <list>  
  15.                 <ref bean="tilesViewResolver" />  
  16.             </list>  
  17.         </property>  
  18.         <property name="useSpringBeanBinding" value="true" />  
  19.     </bean>  
  20. <bean id="validator"   
  21.            class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />  

 简单说一下webflow:flow-builder-services 几个属性的含义,view-factory-creator表示使用的是哪个视图工厂,validator是用来在处理页面流的过程使用的是JSR303的验证,bean id为validator就是spring对jsr303的支持类。development可以扫描flow定义文件的变化,开发时这么用比较好。

    好了,spring web flow 的定义文件就这么多了,下面来将spring mvc与spring web flow 集成。代码如下:

Java代码   收藏代码
  1. <!-- Spring MVC Integration With Spring Web Flow -->  
  2.     <!-- 1.Registering the FlowHandlerAdapter, Enables FlowHandler URL mapping -->  
  3.     <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">  
  4.         <property name="flowExecutor" ref="flowExecutor" />  
  5.     </bean>  
  6.   
  7.     <!-- 2.Defining flow mappings, Maps request paths to flows in the flowRegistry -->  
  8.     <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">  
  9.         <property name="flowRegistry" ref="flowRegistry" />  
  10.         <property name="order" value="-1" />  
  11.     </bean>  

 ok,spring mvc 和spring web flow 集成完毕,下面加入spring security 3.

第1步,当然是配置web.xml文件了,代码如下:

Java代码   收藏代码
  1. <!-- Enables Spring Security -->  
  2.    <filter>  
  3.        <filter-name>springSecurityFilterChain</filter-name>  
  4.        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  5.    </filter>  
  6.   
  7.   
  8.   
  9.   <filter-mapping>  
  10.        <filter-name>springSecurityFilterChain</filter-name>  
  11.        <url-pattern>/*</url-pattern>  
  12.    </filter-mapping>  

 注意这里的filter-name可不是随便起的,这个name为成为spring security filter chain中的一个filter相匹配上,从而完成spring security的功能。注意到filter-class只是spring-web中的一个类而已,并不是spring-security中的类。

第2步,配置spring-security,applicationContext-security.xml,全部配置如下:

Java代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"  
  3.              xmlns:beans="http://www.springframework.org/schema/beans"  
  4.              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.              xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  7.                 http://www.springframework.org/schema/security  
  8.                 http://www.springframework.org/schema/security/spring-security-3.1.xsd">  
  9.   
  10.       
  11.   
  12.  <http security="none" pattern="/resources/**" />  
  13.   
  14.  <http auto-config="true" use-expressions="true">  
  15.   
  16.         <intercept-url pattern="/sec/**" access="hasRole('ROLE_USER')" />  
  17.   
  18.         <form-login login-page="/login"  
  19.                     login-processing-url="/loginProcess"  
  20.                     authentication-failure-url="/login?error=1"  
  21.                     default-target-url="/" />  
  22.   
  23.  <remember-me key="SpringWebFlowTutorial-rmkey-BUUttZnBJCa#U=4Dwg@%5_ptCC8wHtlY"  
  24.                           services-ref="ipTokenBasedRememberMeService" />  
  25.   
  26.         <logout logout-url="/logout" logout-success-url="/" invalidate-session="true" />  
  27.     </http>  
  28.   
  29.     <authentication-manager alias="authenticationManager">  
  30.         <authentication-provider user-service-ref="customJdbcDao">  
  31.             <password-encoder ref="passwordEncoder">  
  32.                 <salt-source ref="saltSource" />  
  33.             </password-encoder>  
  34.         </authentication-provider>  
  35.     </authentication-manager>  
  36.   
  37.   
  38.     <beans:bean id="customJdbcDao" class="org.leochen.samples.dao.impl.CustomJdbcDaoImpl">  
  39.         <beans:property name="dataSource" ref="dataSource" />  
  40.         <beans:property name="enableGroups" value="true" />  
  41.         <beans:property name="enableAuthorities" value="false" />  
  42.     </beans:bean>  
  43.   
  44.     <!-- the property of 'key' must be have -->  
  45.  <beans:bean id="ipTokenBasedRememberMeService"   
  46.                           class="org.leochen.samples.web.security.IPTokenBasedRememberMeService">  
  47.     <beans:property name="userDetailsService" ref="customJdbcDao" />  
  48.     <beans:property name="key"   
  49.                        value="SpringWebFlowTutorial-rmkey-BUUttZnBJCa#U=4Dwg@%5_ptCC8wHtlY" />  
  50.     <beans:property name="tokenValiditySeconds" value="1209600" />  
  51.         <beans:property name="parameter" value="_remember_me" />  
  52.         <beans:property name="cookieName" value="LOGIN_REMEMBER_ME" />  
  53.     </beans:bean>  
  54. </beans:beans>  

 spring security 可以参考spring security的文档和 Spring Security 3这本书来参考学习,很有帮助。

这样基本配置就这么着了,对于那些datasource,jpa 以及spring-jpa的配置会在附件中的代码中给出,附件中的代码可以完整运行。当然了,要熟悉maven。

    下面说一下一个流的基本定义图,如下图:

 

     还是看图一目了然吧,下面是flow定义文件,/WEB-INF/views/hotels/booking/booking-flow.xml,如下:

Java代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <flow xmlns="http://www.springframework.org/schema/webflow"  
  3.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.       xsi:schemaLocation="http://www.springframework.org/schema/webflow  
  5.       http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">  
  6.   
  7.     <!--notice: 'attributes' property cann't use the form like hasRole('ROLE_USER'),  
  8.                          it's just the role name -->  
  9.  <secured attributes="ROLE_USER"/>  
  10.   
  11.  <var name="searchCriteria" class="org.leochen.samples.web.controllers.hotels.SearchCriteria"/>  
  12.   
  13.     <input name="hotelId" required="true"/>  
  14.     <on-start>  
  15.         <evaluate expression="bookingService.createBooking(hotelId,currentUser.name)"   
  16.                          result="flowScope.booking"/>  
  17.     </on-start>  
  18.   
  19.     <view-state id="enterBookingDetails" model="booking">  
  20.         <binder>  
  21.             <binding property="checkinDate" />  
  22.             <binding property="checkoutDate" />  
  23.             <binding property="beds" />  
  24.             <binding property="smoking" />  
  25.             <binding property="creditCard" />  
  26.             <binding property="creditCardName" />  
  27.             <binding property="creditCardExpiryMonth" />  
  28.             <binding property="creditCardExpiryYear" />  
  29.             <binding property="amenities" />  
  30.         </binder>  
  31.           
  32.         <on-render>  
  33.             <render fragments="main"/>  
  34.         </on-render>  
  35.   
  36.         <transition on="submit" to="reviewBooking"/>  
  37.         <transition on="cancel" to="bookingCancelled" bind="false" />  
  38.     </view-state>  
  39.   
  40.     <view-state id="reviewBooking">  
  41.         <on-render>  
  42.             <render fragments="main"/>  
  43.         </on-render>  
  44.   
  45.         <transition on="confirm" to="bookingConfirmed">  
  46.             <evaluate expression="bookingService.save(booking)" />  
  47.         </transition>  
  48.         <transition on="revise" to="enterBookingDetails"/>  
  49.         <transition on="cancel" to="bookingCancelled"/>  
  50.     </view-state>  
  51.   
  52.   
  53.     <end-state id="bookingConfirmed" />  
  54.     <end-state id="bookingCancelled" />  
  55. </flow>  
 

    下面贴上E-R图,看得直观,如下:

 



   最后,想说几点关于jsr303验证的几个注意点,使用hibernate validator(jsr 303的实现)为spring mvc提供验证

的时候,需要把org.hibernate.validator包下面的ValidationMessages.properties文件拷贝到类路径下,这样就可以

 自定义验证消息了,对于spring web flow 的验证,只需在flow定义文件的相同目录下定义messages.properties文件

就可以添加验证消息了,spring web flow 对于验证消息key的生成遵循这么一个约定,key值有3部分组成,第一部分是model的名称,比如booking,第二部分是model的property,比如booking的checkinDate属性,第三部分是error

code,举个全的例子,booking.checkinDate.NotNull=,booking.creditCardExpiryMonth.typeMismatch=

 

Spring3.1新特性,配置JPA无需persistence.xml描述文件,SpringWebFlowTutorial-without-persistence.xml.7z这个是修改后的打包文件,里面还将SpringWebFlowTutorial.sql文件中的booking_amenities表的amenity 字段长度增大些,一个小bug修正了一下。原先的版本在应用服务器glassfish中还不能部署成功,是因为spring提供

  LocalContainerEntityManagerFactoryBean与Java EE应用服务器有些冲突,在没有Spring3.1新特性之前,

可以有其他的解决方案,具体请参考Spring官方文档。现在spring不用persistence.xml文件了,就可以避免掉冲突了。

 


http://clongjava.iteye.com/blog/1314108

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
英文版:The Definitive Guide to Spring Web Flow 内容简介 《Spring Web Flow权威指南》介绍了Spring Web Flow的构建系统Spring Jumpstart、Spring Web Flow架构和基础知识,并结合示例讲述了Spring Web Flow的高级概念、执行管理和驱动,同时说明了如何测试。 《Spring Web Flow权威指南》适合各层次Java Web开发人员阅读和参考。 编辑推荐 《Spring Web Flow权威指南》:Spring Web Flow创始人著作、体验全新的Web用户界面开发方式、深入剖析开源框架的设计与实现。 Spring Web Flow是著名的Spring框架的子项目。它解决了困扰Web应用程序开发人员的3个主要问题.即用户界面导航的控制、状态管理和模块化,极大地提高了生产效率,尤其适合需要复杂用户交互界面的Web应用程序。此外,它还借鉴了UML状态图思想的定义方式,使得Web开发更加自然。 书中重点讲解Web定义语言、执行、的测试以及自定义扩展等精髓内容,并结合使用Spring WebFlow 1开发的实例来向读者说明如何将其实际应用到项目中。尤其弥足珍贵的是,作者从框架设计者角度深入阐述了Spring Web Flow的设计思想和实现方式。更能让读者掌握其核心本质。此外,书中还清楚地讲述了SpringWeb Flow 1和Spring Web Flow 2在设计和使用上的差异。 《Spring Web Flow权威指南》适合各层次Java Web开发人员阅读和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值