商品已经有列表了,接下来就要增加把商品放入购物车的功能,在本示例中用 subflow 来实现这一功能,操作步骤如下:
实现 Cart 和 CartItem 两个业务类 在 shopping.xml 中添加配置 在 /WEB-INF/flows 目录下添加 addToCart.xml 在 webflow-config.xml 中添加 addToCart.xml 的位置 修改 viewCart.jsp 页面
实现 Cart 和 CartItem 两个业务类
CartItem 表示存放于购物车中的条目,主要记录相应商品及商品数量,同时不要忘记实现 java.io.Serializable 接口,见清单 29:
清单 29 CartItem 类
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:
清单 30 Cart 类
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.xml 中添加配置
在 shopping flow 开始时必须分配一个 Cart 对象,由于要调用 subflow ,这个 Cart 对象应存放于 conversationScope 中。同时要添加一个 subflow-state 用于执行添加商品到购物车的任务。
清单 31 shopping.xml 中添加的配置
<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的定义。
清单 32 addToCart.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">
<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>
修改 viewCart.jsp 页面
最后就可以来看在视图中如何显示相关的信息,并触发相应的 webflow 事件,见清单 34:
清单 34 完整的 viewCart.jsp 的代码
<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>
运行效果
图 6 添加购物车后的效果