Spring学习之旅(十一) Spring Web Flow的配置及简单使用

辛苦堆砌,转载请注明出处,谢谢!

        本篇文章看看Spring Web Flow,我们将注册模块单独拿出来做一套流程。首先简单介绍一下Spring Web Flow。

        Spring Web Flow主要用来实现流程,其中配置包括主要的三个方面:流程执行器(flow executor),流程注册表(flow registry)和流程定义(flow definition)。流程定义就是我们定义的具体流程,流程注册表加载流程定义,流程执行器则使用流程注册表实现流程的创建和执行。

        流程有三个组要元素构成:状态,转移和流程数据。流程数据是流程执行过程中承载的数据,有不同的作用域和可见性:Conversation,Flow,Request,Flash,View。状态就是流程所处的状态,Spring Web flow有五种状态可以使用:view-state,action-state,decision-state,end-state,subflow-state。状态之间的切换就是转移,我们常常按照前一个状态的执行结果来切换到下一个状态,这时候就需要使用转移。

        了解了这些,我们开始实际操作,练习一下,先配置Spring Web Flow,从Spring Web Flow 2.4开始,我们可以使用Java类完成配置了,我还是比较喜欢Java类配置,灵活,还方便调试。

package com.yjp.springmvc.blog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.webflow.config.AbstractFlowConfiguration;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter;
import org.springframework.webflow.mvc.servlet.FlowHandlerMapping;

@Configuration
@ComponentScan(basePackages={"com.yjp.springmvc.blog.web.flowaction"})
public class WebFlowConfig extends AbstractFlowConfiguration {
	
	@Bean
	public FlowDefinitionRegistry flowRegistry() {
	    return getFlowDefinitionRegistryBuilder()
	    		.setBasePath("/WEB-INF/flows")
	    		.addFlowLocationPattern("/**/*-flow.xml")
	            .build();
	}
	
	@Bean
	public FlowExecutor flowExecutor(FlowDefinitionRegistry flowRegistry) {
	    return getFlowExecutorBuilder(flowRegistry()).build();
	}
	
	@Bean
	public FlowHandlerAdapter flowHandlerAdapter(FlowExecutor flowExecutor) {
		FlowHandlerAdapter flowHandlerAdapter = 
				new FlowHandlerAdapter();
		flowHandlerAdapter.setFlowExecutor(flowExecutor);
		return flowHandlerAdapter;
	}
	
	@Bean
	public FlowHandlerMapping flowHandlerMapping(FlowDefinitionRegistry flowRegistry) {
		FlowHandlerMapping flowHandlerMapping = 
				new FlowHandlerMapping();
		flowHandlerMapping.setFlowRegistry(flowRegistry);
		flowHandlerMapping.setOrder(0);
		return flowHandlerMapping;
	}
}
这就是我们的配置类,主要配置了 流程执行器(flow executor),流程注册表(flow registry),由于我们还要在Spring MVC中使用Spring Web Flow,所以还要额外配置FlowHandlerAdapter和FlowHandlerMapping,以使我们Spring MVC的DispatcherServlet将对应的请求交给Spring Web Flow处理。 很简单,这样我们就完成了配置。我们先删除之前的注册实现,然后修改我们的点击注册超链接的请求

<td align="center"><a href="regist">注册</a></td>

        完成配置后,实现我们的流程定义。看看我们要实现的流程,如图所示




比较清楚,然后我们按照状态图完成我们的流程定义,路径为/WEB-INF/flows/regist/regist-flow.xml,/WEB-INF/flows/是我们上面配置的base-path,/regist/regist-flow.xml是/流程id/流程定义文件,流程点以文件命名为"流程id-flow.xml",这样我们访问regist请求时,如果DispatcherServlet找不到对应的处理器,就会交给Web Flow,这样Web Flow就会按照流程定义开始流程。

<?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">

	<!-- flow作用域的变量,我们这个流程的模型对象 -->
	<var name="user" 
		class="com.yjp.springmvc.blog.beans.model.User"/>

	<!-- 欢迎界面,默认找welcome.jsp -->
	<view-state id="welcome">
		<transition on="register" to="register"/>
	</view-state>
	
	<!-- 注册界面,默认找register.jsp -->
	<view-state id="register" model="user">
		<transition on="doRegist" to="doRegist"/>
	</view-state>
	
	<!-- 使用registAction判断是否注册成功,执行跳转 -->
	<decision-state id="doRegist">
		<if test="registAction.regist(user)" 
			then="complete"
			else="register" />
	</decision-state>
	
	<!-- 完成界面,默认找complete.jsp -->
	<view-state id="complete" model="user">
		<transition on="login" to="end"/>
	</view-state>
	
	<!-- 结束状态-->
	<end-state id="end" view="externalRedirect:/"/>
	
	<!-- 全局转移 -->
	<global-transitions>
		<transition on="cancel" to="end" />
	</global-transitions>

</flow>
流程中我们使用了view-state,decision-state和end-state,通过转移将他们串联起来,我们还定义了一个全局转移,无论哪个状态以cancel终结,都会进入到end-state。下面看看我们的welcome.jsp有什么不同

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>欢迎</title>
</head>
<body>
	<h1>欢迎您选择简微</h1>
	如果您喜欢我们的简微,请点击下一步,开始您的旅程<br><br>
	<sf:form>
		<input type="hidden" name="_flowExecutionKey"
			value="${flowExecutionKey} }"/>
		<input type="submit" name="_eventId_register"
			value="下一步"/>
		<input type="submit" name="_eventId_cancel"
			value="取消"/>
	</sf:form>
</body>
</html>
有两点特殊的,使用Spring的标签库中的form标签,然后添加了一个hidden的input,其中保存我们的流程key,,最后,submit类型的input的name"以_eventId_事件"的格式命名,以表明点击该按钮触发的事件,这会用在流程中transition的on属性,用来判断下一步的流程走向。其他的没有特殊的。下面给出其他两个jsp文件,除了这里要注意一些,没有更多的东西了。

register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>注册</title>
</head>
<body>
    <h1>会员注册</h1>
    <sf:form commandName="user">
	    <input type="hidden" name="_flowExecutionKey"
				value="${flowExecutionKey} }"/>
        <table style="background-color:#cccccc">
            <tr>
                <td>邮件地址:</td>
                <td><sf:input type="emil" path="email" size="25" maxlength="100" cssErrorClass="error"/></td>
            </tr>
            <tr>
                <td>名称(最大16字符):</td>
                <td><sf:input type="text" path="username" size="25" maxlength="16" cssErrorClass="error"/></td>
            </tr>
            <tr>
                <td>密码(6到16字符):</td>
                <td><sf:input type="password" path="password" size="25" maxlength="16" cssErrorClass="error"/></td>
            </tr>
            <tr>
                <td>确认密码:</td>
                <td><input type="password" name="confirmedPasswd" size="25" maxlength="16"></td>
            </tr>
            <tr>
                <td align="center"><input type="submit" name="_eventId_doRegist" value="注册"></td>
                <td align="center"><input type="submit" name="_eventId_cancel" value="取消"></td>
            </tr>
        </table>
    </sf:form>
</body>
</html>
complete.jsp去登陆使用了一个a标签,那么事件ID就以url参数的形式传递了。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>注册完成</title>
</head>
<body>
	<h1>恭喜  ${user.username} 完成注册</h1>
	<a href="${flowExecutionUrl}&_eventId=login">去登陆</a>
</body>
</html>

最后,看一下我们在decision-state中使用的action类

package com.yjp.springmvc.blog.web.flowaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.yjp.springmvc.blog.beans.model.User;
import com.yjp.springmvc.blog.beans.service.UserService;

@Component
public class RegistAction {
	
	private UserService userService;
	
	@Autowired
	public RegistAction(UserService userService) {
		this.userService = userService;
	}
	
	public boolean regist(User user) {
		return userService.saveUser(user);
	}
}
注意一下包名,是我们Web Flow配置类中的@ComponentScan注解中的包名,该注解就是告诉流程,在哪里扫描Spring Web Flow使用的Bean,以实现自动装配。

        细心的可能会想到,这里我们没有校验User的字段,的确如此,为了简单,我暂时删除了这部分内容,不过Spring Web Flow使用另一套方法校验,感兴趣的可以看看Spring Web Flow的官方文档,里面有详细的介绍。我们可以看到,Spring Web Flow实际上除了做流程,也可以用来做一个完整的Web项目,可以说是另一套体系,也是另一套思路。有兴趣可以去探索一下。








  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值