商品已经有列表了,接下来就要增加把商品放入购物车的功能,在本示例中用 subflow 来实现这一功能,操作步骤如下:
- 实现 Cart 和 CartItem 两个业务类
- 在 shopping.xml 中添加配置
- 在 /WEB-INF/flows 目录下添加 addToCart.xml
- 在 webflow-config.xml 中添加 addToCart.xml 的位置
- 修改 viewCart.jsp 页面
CartItem 表示存放于购物车中的条目,主要记录相应商品及商品数量,同时不要忘记实现 java.io.Serializable 接口,见清单 29:
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++; } /*省略getter和setter*/ } |
除去相应的属性外, CartItem 可根据商品的数量算出该商品的总价格( getTotalPrice ),也可通过 increaseQuantity 增加商品数量。
Cart 是购物车的实现类,其同样要实现 java.io.Serializable 接口,但它没有像 ProductService 一样成为由 Spring IoC 容器管理的 Bean ,每个客户的购物车是不同的,因此不能使用 Spring IoC 容器默认的 Singleton 模式。见清单 30:
package samples.webflow; /* 省略 import 语句 */ public class Cart implements Serializable { private static final long serialVersionUID = 7901330827203016310L; private Map<Integer, CartItem> map = new HashMap<Integer, CartItem>(); public List<CartItem> getItems() { return new ArrayList<CartItem>(map.values()); } 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)); } public int getTotalPrice() { int total = 0; for (CartItem item : map.values()) total += item.getProduct().getPrice() * item.getQuantity(); return total; } } |
Cart 主要实现三个业务函数, getItems 用于获取当前购物车里的物品, addItem 用于向购物车添加商品, getTotalPrice 用于获取购物车里所有商品的总价格。
|
在 shopping flow 开始时必须分配一个 Cart 对象,由于要调用 subflow ,这个 Cart 对象应存放于 conversationScope 中。同时要添加一个 subflow-state 用于执行添加商品到购物车的任务。
<var name="mycart" class="samples.webflow.Cart"/> <on-start> <set name="conversationScope.cart" value="mycart"></set> </on-start> <view-state id="viewCart" view="viewCart" > <on-render> <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> |
|
在 /WEB-INF/flows 目录下添加 addToCart.xml
清单 31 中 subflow-state 元素的 subflow 属性即指明了这个被调用的 flow 的 id 为“ addToCart ”,现在就要添加addToCart 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"> <on-start> <set name="requestScope.productId" value="requestParameters.productId"/> </on-start> <action-state id="addToCart"> <evaluate expression="cart.addItem(productService.getProduct(productId))"/> <transition to="productAdded"/> </action-state> <end-state id="productAdded"/> </flow> |
addToCart flow 主要由一个 action-state 构成,完成添加商品到购物车的功能, addToCart flow 的实现需要有输入参数,即 productId 。在本示例中是通过请求参数来传递,通过 requestParameters 来获取该数值。这里还要注意到清单 32 中的 end-state 的 id 为“ productAdded ”,与清单 31 中 subflow-state 中的 transition元素的on属性的名称是对应的。
|
在 webflow-config.xml 中添加 addToCart.xml 的位置
新增加的 flow 不要忘记在 flow-registry 中注册。
清单 33 flow-registry 中注册 addToCart
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/shopping.xml" id="shopping"/>
<webflow:flow-location path="/WEB-INF/flows/addToCart.xml" id="addToCart"/>
</webflow:flow-registry>
|
|
最后就可以来看在视图中如何显示相关的信息,并触发相应的 webflow 事件,见清单 34:
<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>
|
|