Spring Web Flow 2.0 入门 用 Unified EL 实现业务逻辑

本文介绍了SpringWebFlow中业务逻辑的整合方式,包括业务逻辑代码的触发时机及数据保存方法,并通过示例展示了如何在应用中添加商品。

到现在为止,这个购物车应用只是实现了页面之间的跳转,接下来我们要实现与业务逻辑相关的功能。由于本教程的重点在于介绍如何应用 Spring Web Flow ,所实现的业务比较简单,与实际应用有较大的距离,请读者谅解。

业务的逻辑涉及到数据的获取、传递、保存,相关的业务功能函数的调用等内容,这些功能的实现都可用 Java 代码来完成,但定义 Spring Web Flow 的语法与 Java 是无关的,这就要求 Spring Web Flow 提供与 Java 代码的整合机制。要了解这种机制,关键在于搞清楚两个问题:

  • 业务逻辑代码在什么时候被调用?
  • 业务逻辑代码在调用后得到的数据如何保存、传递?

业务逻辑代码在什么时候被调用?

在 Spring Web Flow 中,业务逻辑代码的执行可由以下三种情形来触发:

  • 客户端请求中包含了 _eventId 参数
  • 执行到框架自定义的切入点
  • 执行到 <action-state> 元素




回页首


客户端请求中包含了 _eventId 参数

这种方式一般用在 state 之间的 transition ,通过指定 _eventId 参数的值,表明了客户的行为,从而导致相应事件的发生,在 Spring Web Flow 的定义文件中可以通过 evaluate 元素来指定要处理的业务逻辑。参看清单21:


清单 21 transition 示例
<transition on="submit"> 
<evaluate expression="validator.validate()" /> 
</transition>

清单 21 的代码表示,当客户端的请求中包含“ _eventId=submit ”,则 evaluate 元素中 expression 属性所指明的表达式会被执行,即 validator 对象的validate 方法会得到调用。





回页首


执行到框架自定义的切入点

Spring Web Flow 定义了 5 个切入点,通过 flow 定义文件的配置,可在这 5 个切入点插入相关业务逻辑代码。


表 2 Spring Web Flow 自定义的切入点
切入点名称 XML 元素名称 触发时刻
flow start on-start flow 执行之前
state entry on-entry 进入某个 state 之后,做其他事情之前
view render on-render 在进入 view 的 render 流程之后,在 view 真正 render出来之前
state exit on-exit 在退出 state 之前
flow end on-end flow 执行结束之后

清单 22 给出了在 view render 切入点插入业务逻辑代码的例子:


清单 22 on-render 元素
<view-state id="viewCart" view="viewCart" >
  <on-render>
    <evaluate expression="productService.getProducts()"
      result="viewScope.products"/>
  </on-render>
</view-state>
	





回页首


执行到 <action-state> 元素

Spring Web Flow 中的这个 <action-state> 是专为执行业务逻辑而设的 state 。如果某个应用的业务逻辑代码即不适合放在 transition 中由客户端来触发,也不适合放在 Spring Web Flow 自定义的切入点,那么就可以考虑添加 <action-state> 元素专用于该业务逻辑的执行。示例代码参看清单23:


清单 23 action-state 示例
<action-state id="addToCart">
  <evaluate expression="cart.addItem(productService.getProduct(productId))"/>
  <transition to="productAdded"/>
</action-state>





回页首


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

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范围中。


清单 24 flowScope 示例
<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自带的文档。





回页首


为示例应用添加商品

接下来,我们要在示例应用的 viewCart.jsp 页面中添加商品,可按以下步骤操作:

  • 添加 Product 类
  • 添加 ProductService 类
  • 修改 shopping.xml 文件
  • 修改 viewCart.jsp 页面




回页首


添加 Product 类

Product 类是个普通的 JavaBean ,用于定义商品( Product )的一般属性,同时也提供了构造方法。由于会把 Product 存放于 conversationScope 中, Product 实现了 Serializable 接口。具体见清单25:


清单 25 Product 类
package samples.webflow;

import java.io.Serializable;

public class Product implements Serializable { 

    private static final long serialVersionUID = 1951520003958305899L; 
	private int id; 
	private String description; 
	private int price; 
	
	public Product(int id, String description, int price) { 
	    this.id = id; 
		this.description = description; 
		this.price = price; 
	} 

    /*省略getter和setter*/ 

} 





回页首


添加 ProductService 类

ProductService 主要提供商品列表,并能根据商品的 id 查找出该商品,由于示例较简单,这里只添加了三条纪录。见清单 26:


清单 26 ProductService 类
package samples.webflow;

/*省略import语句*/ 

@Service("productService")
public class ProductService {
    /*products 用于存放多个商品 */
    private Map<Integer, Product> products = new HashMap<Integer, Product>(); 
	
	public ProductService() { 
	    products.put(1, new Product(1, "Bulldog", 1000)); 
		products.put(2, new Product(2, "Chihuahua", 1500)); 
		products.put(3, new Product(3, "Labrador", 2000));
	} 
	
	public List<Product> getProducts() { 
	    return new ArrayList<Product>(products.values()); 
	} 
	
	public Product getProduct(int productId) {
	    return products.get(productId); 
	}
}

Service 注解表示 Spring IoC 容器会初始化一个名为 productService 的 Bean ,这个 Bean 可在 Spring Web Flow 的定义中直接访问。





回页首


修改 shopping.xml 文件

要在 viewCart 页面中显示商品,只需在 view-state 元素的 on-render 切入点调用 productService 的 getProducts 方法,并将所得结果保存到 viewScope 中即可。见清单27:


清单 27 shopping.xml 需修改的部分
<view-state id="viewCart" view="viewCart" >
  <on-render> 
    <evaluate expression="productService.getProducts()" result="viewScope.products"/>
  </on-render> 
  <transition on="submit" to="viewOrder"> </transition>
</view-state>





回页首


修改 viewCart.jsp 页面

清单 27 表明 productService 的 getProducts 方法所得的结果会存放在 viewScope 中名为 products 的变量中, jsp 页面的代码可直接访问该变量。见清单 28:


清单 28 修改后的 viewCart.jsp 页面
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>View Cart</title> 
</head> 
<body> 
<h1>View Cart</h1> 
<h2>Items in Your Cart</h2> 
<a href="${flowExecutionUrl}&_eventId=submit">Submit</a> 
<h2>Products for Your Choice</h2> 
<table> 
<c:forEach var="product" items="${products}"> 
<tr> 
<td>${product.description}</td> 
<td>${product.price}</td> 
</tr> 
</c:forEach> 
</table> 
</body> 
</html>





回页首


运行应用程序


图 5 viewCart.jsp 页面效果
viewCart.jsp 页面效果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值