`
clongjava
  • 浏览: 63879 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类

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的前端控制器。配置很简单,如下:

 <!-- Loads the Spring web application context -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

<servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
       <servlet-name>mvc</servlet-name>
       <url-pattern>/</url-pattern>
</servlet-mapping>

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

 <context:component-scan base-package="org.leochen.samples.web" />

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

<mvc:annotation-driven />

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

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

<mvc:resources mapping="/resources/**" 
                          location="/resources/,classpath:/META-INF/web-resources/" />
<mvc:default-servlet-handler />

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

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

 <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
  </mvc:interceptors>

 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>


 <bean id="messageSource" 
            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <array>
                <value>/WEB-INF/messages/globalMessage</value>
                <value>/WEB-INF/messages/validationMessage</value>
            </array>
        </property>
        <property name="defaultEncoding" value="UTF-8" />
        <property name="cacheSeconds" value="0" />
  </bean>

  第5步,配置tiles

<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/**/views.xml</value>
            </list>
        </property>
    </bean>

<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
 <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView" />
</bean>

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

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd">

 <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices"
                  base-path="/WEB-INF/views">
        <webflow:flow-location-pattern value="/**/*-flow.xml" />
  </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,流执行器

 <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
        <webflow:flow-execution-listeners>
            <webflow:listener ref="securityFlowExecutionListener" />
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>

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

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

<webflow:flow-builder-services id="flowBuilderServices"
                                   view-factory-creator="mvcViewFactoryCreator"
                                   development="true"
                                   validator="validator" />

    <!-- Installs a listener to apply Spring Security authorities -->
    <bean id="securityFlowExecutionListener" 
                class="org.springframework.webflow.security.SecurityFlowExecutionListener" />

    <!-- Configures Web Flow to use Tiles to create views for rendering -->
    <bean id="mvcViewFactoryCreator" 
               class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
        <property name="viewResolvers">
            <list>
                <ref bean="tilesViewResolver" />
            </list>
        </property>
        <property name="useSpringBeanBinding" value="true" />
    </bean>
<bean id="validator" 
           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 集成。代码如下:

<!-- Spring MVC Integration With Spring Web Flow -->
    <!-- 1.Registering the FlowHandlerAdapter, Enables FlowHandler URL mapping -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
        <property name="flowExecutor" ref="flowExecutor" />
    </bean>

    <!-- 2.Defining flow mappings, Maps request paths to flows in the flowRegistry -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
        <property name="flowRegistry" ref="flowRegistry" />
        <property name="order" value="-1" />
    </bean>

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

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

 <!-- Enables Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>



   <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

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

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

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/security
                http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    

 <http security="none" pattern="/resources/**" />

 <http auto-config="true" use-expressions="true">

        <intercept-url pattern="/sec/**" access="hasRole('ROLE_USER')" />

        <form-login login-page="/login"
                    login-processing-url="/loginProcess"
                    authentication-failure-url="/login?error=1"
                    default-target-url="/" />

 <remember-me key="SpringWebFlowTutorial-rmkey-BUUttZnBJCa#U=4Dwg@%5_ptCC8wHtlY"
                          services-ref="ipTokenBasedRememberMeService" />

        <logout logout-url="/logout" logout-success-url="/" invalidate-session="true" />
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="customJdbcDao">
            <password-encoder ref="passwordEncoder">
                <salt-source ref="saltSource" />
            </password-encoder>
        </authentication-provider>
    </authentication-manager>


    <beans:bean id="customJdbcDao" class="org.leochen.samples.dao.impl.CustomJdbcDaoImpl">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="enableGroups" value="true" />
        <beans:property name="enableAuthorities" value="false" />
    </beans:bean>

    <!-- the property of 'key' must be have -->
 <beans:bean id="ipTokenBasedRememberMeService" 
                          class="org.leochen.samples.web.security.IPTokenBasedRememberMeService">
    <beans:property name="userDetailsService" ref="customJdbcDao" />
    <beans:property name="key" 
                       value="SpringWebFlowTutorial-rmkey-BUUttZnBJCa#U=4Dwg@%5_ptCC8wHtlY" />
    <beans:property name="tokenValiditySeconds" value="1209600" />
        <beans:property name="parameter" value="_remember_me" />
        <beans:property name="cookieName" value="LOGIN_REMEMBER_ME" />
    </beans:bean>
</beans:beans>

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

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

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

 

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

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
      http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

    <!--notice: 'attributes' property cann't use the form like hasRole('ROLE_USER'),
                         it's just the role name -->
 <secured attributes="ROLE_USER"/>

 <var name="searchCriteria" class="org.leochen.samples.web.controllers.hotels.SearchCriteria"/>

    <input name="hotelId" required="true"/>
    <on-start>
        <evaluate expression="bookingService.createBooking(hotelId,currentUser.name)" 
                         result="flowScope.booking"/>
    </on-start>

    <view-state id="enterBookingDetails" model="booking">
        <binder>
            <binding property="checkinDate" />
            <binding property="checkoutDate" />
			<binding property="beds" />
			<binding property="smoking" />
			<binding property="creditCard" />
			<binding property="creditCardName" />
			<binding property="creditCardExpiryMonth" />
			<binding property="creditCardExpiryYear" />
			<binding property="amenities" />
        </binder>
        
        <on-render>
            <render fragments="main"/>
        </on-render>

        <transition on="submit" to="reviewBooking"/>
        <transition on="cancel" to="bookingCancelled" bind="false" />
    </view-state>

    <view-state id="reviewBooking">
        <on-render>
            <render fragments="main"/>
        </on-render>

        <transition on="confirm" to="bookingConfirmed">
            <evaluate expression="bookingService.save(booking)" />
        </transition>
        <transition on="revise" to="enterBookingDetails"/>
        <transition on="cancel" to="bookingCancelled"/>
    </view-state>


    <end-state id="bookingConfirmed" />
    <end-state id="bookingCancelled" />
</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文件了,就可以避免掉冲突了。

 

  • 大小: 5.6 KB
  • 大小: 30.9 KB
  • pic.7z (2.6 MB)
  • 下载次数: 642
7
3
分享到:
评论
9 楼 sodagreen.simplicity 2015-09-23  
说的很赞,也挺清楚,就是文章一开始的配置文件讲述稍嫌太多了。
8 楼 澹若水 2015-09-06  
感谢分享,学习了
7 楼 clongjava 2012-07-27  
610622106 写道
楼主,你的 E-R图用什么软件画的呢?

是MySQL Workbench
6 楼 610622106 2012-07-27  
楼主,你的 E-R图用什么软件画的呢?
5 楼 fxl545826 2012-06-27  
osacar 写道
web flow和work flow有啥区别?

workflw是工作流,webflow是页面流转,workflow的话可能针对于一个新闻经过录入以后要经过主编等的审核,能够审批通过了,返工等类似处理,而webflw可能针对于一些例如购物车了,注册了需要多个页面分几个步骤来完成最后的完成。这样能理解吗?
4 楼 liumayulingyan 2011-12-19  
牛B
3 楼 osacar 2011-12-18  
web flow和work flow有啥区别?
2 楼 clongjava 2011-12-18  
KimHo 写道
挺好的,感谢分享!

谢谢支持
1 楼 KimHo 2011-12-17  
挺好的,感谢分享!

相关推荐

    Pro Spring MVC With Web Flow

    plus the first published coverage of Spring Web Flow 2.x, this book includes numerous tips and tricks to help you get the most out of Spring MVC, Spring Web Flow, and web development in general. ...

    spring web flow demo

    要了解 Spring Web Flow 是什么东西,最好的办法莫过于查看示例,图 2 展示了一个简化的购物车的流 程。 图 1 购物车示例 图 2 所示流程用 Spring Web Flow 2.0 的配置文件表示如下: 清单 1 用 Spring Web Flow ...

    精通Spring.MVC

    plus the first published coverage of Spring Web Flow 2.x, this book includes numerous tips and tricks to help you get the most out of Spring MVC, Spring Web Flow, and web development in general. ...

    Spring Recipes: A Problem-Solution Approach, Second Edition

    * Spring web: Spring MVC, Spring Web Flow 2, Spring Roo, other dynamic scripting, integration with popular Grails Framework (and Groovy), REST/web services, and more. This book guides you step by ...

    Spring攻略PDF版

    因为上传大小的限制,... 第15章 Spring Web Flow   第16章 Spring远程服务和Web服务   第17章 Spring对EJB和JMS的支持   第18章 Spring对JMX、电子邮件和调度的支持   第19章 Spring中的脚本编程 

    Spring攻略中文版PDF

    因为上传大小的限制,... 第15章 Spring Web Flow   第16章 Spring远程服务和Web服务   第17章 Spring对EJB和JMS的支持   第18章 Spring对JMX、电子邮件和调度的支持   第19章 Spring中的脚本编程 

    Spring攻略英文版(附带源码)

    Spring专家力作 理论与实践完美结合 问题描述→解决方案→实现方法 第一部分 核心概念  第1章 控制反转和容器   1.1 使用容器管理组件   1.1.1 问题描述   1.1.2 解决方案   1.1.3 实现方法   1.2...

    Spring in Action(第二版 中文高清版).part2

    A.2 把Spring添加为一个Maven 2依赖项 A.3 Spring与Ant A.4 Spring与Log4j 附录B 用(和不用)Spring进行测试 B.1 测试简介 B.1.1 理解不同类型的测试 B.1.2 使用JUnit B.1.3 Spring在测试中的角色 B.2 单元...

    Spring攻略(第二版 中文高清版).part2

    8.1 用Spring MVC开发简单的Web应用 280 8.1.1 问题 280 8.1.2 解决方案 281 8.1.3 工作原理 283 8.2 用@RequestMapping映射请求 293 8.2.1 问题 293 8.2.2 解决方案 294 8.2.3 工作原理 294 8.3 ...

    Spring攻略(第二版 中文高清版).part1

    8.1 用Spring MVC开发简单的Web应用 280 8.1.1 问题 280 8.1.2 解决方案 281 8.1.3 工作原理 283 8.2 用@RequestMapping映射请求 293 8.2.1 问题 293 8.2.2 解决方案 294 8.2.3 工作原理 294 8.3 ...

    Spring in Action(第二版 中文高清版).part1

    A.2 把Spring添加为一个Maven 2依赖项 A.3 Spring与Ant A.4 Spring与Log4j 附录B 用(和不用)Spring进行测试 B.1 测试简介 B.1.1 理解不同类型的测试 B.1.2 使用JUnit B.1.3 Spring在测试中的角色 B.2 单元...

    Manning.Spring.in.Action.4th.Edition.2014.11.epub

    8.1. Configuring Web Flow in Spring 8.1.1. Wiring a flow executor 8.1.2. Configuring a flow registry 8.1.3. Handling flow requests 8.2. The components of a flow 8.2.1. States 8.2.2. Transitions 8.2.3....

    spring MVC 最新教程

    spring MVC 最新的教程 2012年6月出品 Foreword.............................................................................................................. xvi  About the Authors.......................

    spring roo in action

    spring roo是快速开发java的框架,支持spring mvc/security/tiles/webflow/test,也可以自己修改。

    springboot学习思维笔记.xmind

    Spring Web Flow Spring Web Services Spring LDAP Spring Session Spring项目快速搭建 Maven简介 Maven安装 Maven的pom.xml dependencies dependency 变量定义 ...

    Spring in Action(Manning,Craig, 4ed,2014)

    It covers Spring core, along with the latest updates to Spring MVC, Security, Web Flow, and more. You'll move between short snippets and an ongoing example as you learn to build simple and efficient ...

    ShoppingCart:使用Java的电子商务网站-Maven中的Spring MVC-未维护项目

    我们使用带有多个模块的Spring MVC开发了端到端电子商务Web应用程序 不再维护项目 功能: 用户注册单元。 CRUD操作如 用户可以将产品添加到他们的购物车并购买摘要。 管理员可以将产品添加到产品列表中。 管理...

    Spring in Action

    It covers the latest features, tools, and practices including Spring MVC, REST, Security, Web Flow, and more. You'll move between short snippets and an ongoing example as you learn to build simple ...

    Spring in Action.4th.Edition(英文版)

    It covers the latest features, tools, and practices including Spring MVC, REST, Security, Web Flow, and more. You'll move between short snippets and an ongoing example as you learn to build simple ...

Global site tag (gtag.js) - Google Analytics