您的位置:首页 > 编程语言 > Java开发

Spring Web Flow 入门demo(三)嵌套流程与业务结合 附源码

2016-09-21 10:35 435 查看


Spring Web Flow 入门demo(三)嵌套流程与业务结合 附源码

2015-07-03 14:42 2320人阅读 评论(3) 举报


分类:

JAVA(105)

Spring
Web Flow(2)


版权声明:本文为博主原创文章,未经博主允许不得转载。

上篇博客我们说Spring web Flow与业务结合的方式主要有三种,下面我们主要介绍一下第三种的应用方式

3,执行到<action-state> 元素

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

action-state 示例:

[html] view
plain copy

print?

<action-state id="addToCart">

<evaluate expression="cart.addItem(productService.getProduct(productId))"/>

<transition to="productAdded"/>

</action-state>

添加subflow 结点

商品列表已经实现了,接下来操作步骤为:

实现 Cart 和 CartItem 两个业务类
在 shopping.xml 中添加配置
在 /WEB-INF/flows 目录下添加 addToCart.xml
在 webflow-config.xml 中添加 addToCart.xml 的位置
修改 viewCart.jsp 页面

具体demo实现:

Cart:

[java] view
plain copy

print?

package samples.webflow;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

//购物车的实现类

public class Cart implements Serializable {

private static final long serialVersionUID = 7901330827203016310L;

private Map<Integer, CartItem> map = new HashMap<Integer, CartItem>();

//getItems 用于获取当前购物车里的物品

public List<CartItem> getItems() {

return new ArrayList<CartItem>(map.values());

}

//addItem 用于向购物车添加商品

public void addItem(Product product) {

int id = product.getId();

CartItem item = map.get(id);

if (item != null)

item.increaseQuantity();

else

map.put(id, new CartItem(product, 1));

}

//getTotalPrice 用于获取购物车里所有商品的总价格

public int getTotalPrice() {

int total = 0;

for (CartItem item : map.values())

total += item.getProduct().getPrice() * item.getQuantity();

return total;

}

}

Cart 是购物车的实现类,其同样要实现java.io.Serializable 接口,但它没有像 ProductService 一样成为由 Spring IoC 容器管理的 Bean,每个客户的购物车是不同的,因此不能使用 Spring IoC 容器默认的 Singleton 模式。

CartItem:

[java] view
plain copy

print?

package samples.webflow;

import java.io.Serializable;

//购物车中的条目

public class CartItem implements Serializable {

private static final long serialVersionUID = 8388627124326126637L;

private Product product;//商品

private int quantity;//数量

public CartItem(Product product, int quantity) {

this.product = product;

this.quantity = quantity;

}

//计算该条目的总价格

public int getTotalPrice() {

return this.quantity * this.product.getPrice();

}

//增加商品的数量

public void increaseQuantity() {

this.quantity++;

}

/**

* Return property product

*/

public Product getProduct() {

return product;

}

/**

* Sets property product

*/

public void setProduct(Product product) {

this.product = product;

}

/**

* Return property quantity

*/

public int getQuantity() {

return quantity;

}

/**

* Sets property quantity

*/

public void setQuantity(int quantity) {

this.quantity = quantity;

}

/* getter setter */

}

shopping.xml:

[html] view
plain copy

print?

<?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">
<!-- 在 shopping flow 开始时必须分配一个 Cart 对象,由于要调用 subflow ,

这个 Cart 对象应存放于 conversationScope 中。

同时要添加一个 subflow-state 用于执行添加商品到购物车的任务。 -->

<!-- mycart为一个服务类 -->

<var name="mycart" class="samples.webflow.Cart" />

<on-start>

<set name="conversationScope.cart" value="mycart"></set>

</on-start>

<!-- view-state中的view对应jsp文件夹中的jsp页面,on是触发事件,to对应state id -->

<view-state id="viewCart" view="viewCart">

<!-- 在进入 view 的 render 流程之后,在 view 真正 render出来之前 -->

<on-render>

<!-- 要在 viewCart 页面中显示商品,只需在 view-state 元素的 on-render 切入点调用 productService

的 getProducts 方法,并将所得结果保存到 viewScope 中即可 -->

<evaluate expression="productService.getProducts()" result="viewScope.products" />

</on-render>

<transition on="submit" to="viewOrder" />

<transition on="addToCart" to="addProductToCart" />

</view-state>

<subflow-state id="addProductToCart" subflow="addToCart">

<transition on="productAdded" to="viewCart" />

</subflow-state>

<view-state id="viewOrder" view="viewOrder">

<transition on="confirm" to="orderConfirmed">

</transition>

</view-state>

<view-state id="orderConfirmed" view="orderConfirmed">

<transition on="returnToIndex" to="returnToIndex">

</transition>

</view-state>

<end-state id="returnToIndex" view="externalRedirect:servletRelative:/index.jsp">

</end-state>

</flow>

在/WEB-INF/flows 目录下添加 addToCart.xml

subflow-state元素的 subflow 属性即指明了这个被调用的 flow 的 id 为“ addToCart ”,现在就要添加addToCart flow的定义。

addToCart.xml:

[html] view
plain copy

print?

<?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 执行之前 ,productId这个字段内容从viewCart页面中获取-->

<on-start>

<set name="requestScope.productId" value="requestParameters.productId" />

</on-start>

<!-- addToCart flow 主要由一个 action-state 构成,完成添加商品到购物车的功能,

addToCart flow 的实现需要有输入参数,即 productId 。

本示例中是通过请求参数来传递,通过 requestParameters 来获取该数值。

这里还要注意到 end-state 的 id 为“ productAdded ”,

与 subflow-state 中的 transition元素的on属性的名称是对应的。 -->

<action-state id="addToCart">

<evaluate expression="cart.addItem(productService.getProduct(productId))" />

<transition to="productAdded" />

</action-state>

<end-state id="productAdded" />

</flow>

webflow-config.xml 中添加addToCart.xml 的位置

[html] view
plain copy

print?

<?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:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- 搜索 samples.webflow 包里的 @Component 注解,并将其部署到容器中 -->

<context:component-scan base-package="samples.webflow" />

<!-- 启用基于注解的配置 -->

<context:annotation-config />

<import resource="webmvc-config.xml" />

<import resource="webflow-config.xml" />

</beans>

viewCart.jsp:

[html] view
plain copy

print?

<?xml version="1.0" encoding="utf-8" ?>

<%@ 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>

<c:choose>

<c:when test="${empty cart.items}">

<p>Your cart is empty.</p>

</c:when>

<c:otherwise>

<table border="1" cellspacing="0">

<tr>

<th>Item</th>

<th>Quantity</th>

<th>Unit Price</th>

<th>Total</th>

</tr>

<c:forEach var="item" items="${cart.items}">

<tr>

<td>${item.product.description}</td>

<td>${item.quantity}</td>

<td>${item.product.price}</td>

<td>${item.totalPrice}</td>

</tr>

</c:forEach>

<tr>

<td>TOTAL:</td>

<td></td>

<td></td>

<td>${cart.totalPrice}</td>

</tr>

</table>

</c:otherwise>

</c:choose>

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

<td><a

href="${flowExecutionUrl}&_eventId=addToCart&productId=${product.id}">[add

to cart]</a></td>

</tr>

</c:forEach>

</table>

</body>

</html>

viewOrder.jsp:

[html] view
plain copy

print?

<?xml version="1.0" encoding="utf-8" ?>

<%@ 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 order</title>

</head>

<body>

<h1>Order</h1>

<c:choose>

<c:when test="${empty cart.items}">

<p>Your cart is empty.</p>

</c:when>

<c:otherwise>

<table border="1" cellspacing="0">

<tr>

<th>Item</th>

<th>Quantity</th>

<th>Unit Price</th>

<th>Total</th>

</tr>

<c:forEach var="item" items="${cart.items}">

<tr>

<td>${item.product.description}</td>

<td>${item.quantity}</td>

<td>${item.product.price}</td>

<td>${item.totalPrice}</td>

</tr>

</c:forEach>

<tr>

<td>TOTAL:</td>

<td></td>

<td></td>

<td>${cart.totalPrice}</td>

</tr>

</table>

</c:otherwise>

</c:choose>

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

</body>

</html>

访问地址:

http://localhost:8080/CartApp5/spring/index

显示效果:





再扩展一下:

如果我们将shopping.xml中的配置文件修改一下,改为flowScope时,我们在viewOrder页面也可以获取products数据。

[html] view
plain copy

print?

<view-state id="viewCart" view="viewCart">

<!-- 在进入 view 的 render 流程之后,在 view 真正 render出来之前 -->

<on-render>

<!-- 要在 viewCart 页面中显示商品,只需在 view-state 元素的 on-render 切入点调用 productService

的 getProducts 方法,并将所得结果保存到 viewScope 中即可 -->

<evaluate expression="productService.getProducts()" result="flowScope.products" />

</on-render>

<transition on="submit" to="viewOrder" />

<transition on="addToCart" to="addProductToCart" />

</view-state>

viewOrder.jsp:

[html] view
plain copy

print?

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

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

效果图:



总结:

Spring Web Flow 应用流程的方式解决了数据存取范围的问题,并在解决数据存取范围问题的同时,通过使用xml的方式来控制页面间的流转顺序以及页面间数据的传输,使得我们页面间的跳转变得更加灵活可控。

附源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: