版权声明:转载请联系作者本人!!! https://blog.csdn.net/qq_41307491/article/details/82810097
购物车模块
购物车存储方式:
1)保存在session中;此次项目保存在session中
2)保存在cookie中;
3)保存在数据库中:
不同方式的优缺点:
1.Session(Memcached)方式
优点:购物车信息保存在服务端,可以保存1M 信息。
缺点:1)对于大型网站会占有过多的服务器内存资源,造成服务器压力过大。
2)Session保存的信息会在用户退出登录后丢失。用户下次登录,购物车中商品信息丢失,用户只能从新选择。
2.Cookie方式
优点:购物车信息存储在客户端,不占用服务器资源,基本可以到达持久化存储。
缺点:Cookie有大小的限制,不能超过4K,而且不够安全、不能对用户购买行为分析统计
如果是个人PC机,Cookie能很好的保存购物车信息.
但如果是公共办公环境,Cookie保存的信息基本就失效了(会被其他人购物车信息覆盖)。
对于大型的电子商务网站,需要对用户的购买行为进行分析,如果把购物车信息保存在Cookie中,则不能对用户购买行为分析统计。
3.数据库存储
优点:持久化存储,可以分析用户购买行为。
缺点: 网站速度变慢,成本和维护增加。
1创建相关类
购物车的结构:
CartItem:包含图书和数量
Cart:包含一个Map<String,CartItem>
dao:没有
service:没有
web.servlet:提供!CartServlet
修改登录方法,在用户登录成功后,马上在session中添加一辆车!!!
页面:/jsps/cart/list.jsp
它只有一个任务,就是遍历车!
车在session中,通过车可以得到所有的CartItem
${sessionScope.cart.cartItems}
2 添加购物车条目
3 清空条目
4 删除购物车条目
5 我的购物车
top.jsp中存在一个链接:我的购物车
我的购物车直接访问/jsps/cart/list.jsp,它会显示session中车的所有条目
domian:
/**
* 购物车类
* @author 一万年行不行
*
*/
public class Cart {
/*
* map创建:
* 1.创建Map存放条目,以书id做键<书id,条目>
* 2.创建LinkedHashMap,为了保证顺序
*/
private Map<String,CartItem> map = new LinkedHashMap<String, CartItem>();
/**
* 合计 (所有条目价钱小计之和)
* 使用BigDecimal类型:解决二进制运算误差问题
* @return
*/
public double getTotal() {
//使用BigDecimal类型
BigDecimal total = BigDecimal.valueOf(0);
//遍历每个条目
for (CartItem cartItem : map.values()) {
//得到每个条目价钱(得到BigDecimal类型)
BigDecimal subTatal = BigDecimal.valueOf(cartItem.getSubtotal());
//对每个条目进行加法求和
total = total.add(subTatal);
}
return total.doubleValue(); //转为double类型
}
/**
* 添加条目
* @param cartItem
*/
public void add(CartItem cartItem){
/*
* 1.判断map中是否含有被添加条目
* 2.有,进行条目合并(合并数量)
* 条目合并:
* 1.拿到原条目
* 2.条目数量合并 (原数量 + 新数量)
* 3.将合并后的条目放进map
* 3.没有,直接添加
*/
if(map.containsKey(cartItem.getBook().getBid())){
//1.拿到原条目
CartItem _cartItem = map.get(cartItem.getBook().getBid());
//2.条目数量合并 (原数量 + 新数量)
_cartItem.setCount(_cartItem.getCount() + cartItem.getCount());
//3.将合并后的条目放进map
map.put(cartItem.getBook().getBid(), _cartItem);
}else{
//直接存放
map.put(cartItem.getBook().getBid(),cartItem);
}
}
/**
* 删除指定条目
* @param bid
*/
public void delete(String bid){
map.remove(bid);
}
/**
* 清空条目
*/
public void clear(){
map.clear();
}
/**
* 我的购物车(获取所有条目)
* @return
*/
public Collection<CartItem> getCartItems(){
return map.values();
}
}
/**
* 购物条目
* @author 一万年行不行
*
*/
public class CartItem {
private Book book; //商品
private int count; //商品数量
/**
* 小计方法:处理二进制运算误差问题
* @return
*/
public double getSubtotal(){ //计算方法,没有对应成员
//将double转化为BigDecimal类型:解决二进制运算误差问题
BigDecimal _price = BigDecimal.valueOf(book.getPrice());
BigDecimal _count = BigDecimal.valueOf(count);
//计算价格(价钱*数量),并转回double类型
return _price.multiply(_count).doubleValue();
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
servlet:
public class CartServlet extends BaseServlet {
private static final long serialVersionUID = 1L;
/**
* 添加购物 条目
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.得到session中的车(只有登陆的用户才有车)
* 2.得到购买的图书和数量
* 3.创建条目(条目包含图书和数量属性),并对条目设置图书和购买数
* 4.添加条目到车中
*/
Cart cart = (Cart) request.getSession().getAttribute("cart");
//得到条目,先得到图书的id,通过id查询数据库,得到book
String bid = request.getParameter("bid");
Book book = new BookService().load(bid);
//得到用户购买数量
int count = Integer.parseInt(request.getParameter("count"));
//创建条目,并对条目设置图书和购买数
CartItem cartItem = new CartItem();
cartItem.setBook(book);
cartItem.setCount(count);
cart.add(cartItem);
return "f:/jsps/cart/list.jsp";
}
/**
* 删除购物条目
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.得到车
* 2.得到要清空的条目ID
* 3.根据ID删除条目
*/
Cart cart = (Cart) request.getSession().getAttribute("cart");
String bid = request.getParameter("bid");
cart.delete(bid);
return "f:/jsps/cart/list.jsp";
}
/**
* 清空购物条目
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String clear(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.得到车
* 2.清空车
*/
Cart cart = (Cart) request.getSession().getAttribute("cart");
cart.clear();
return "f:/jsps/cart/list.jsp";
}
}
jsp
list.jsp 显示购物车中信息
<style type="text/css">
* {
font-size: 11pt;
}
div {
margin:20px;
border: solid 2px gray;
width: 150px;
height: 150px;
text-align: center;
}
li {
margin: 10px;
}
#buy {
background: url(<c:url value='/images/all.png'/>) no-repeat;
display: inline-block;
background-position: 0 -902px;
margin-left: 30px;
height: 36px;
width: 146px;
}
#buy:HOVER {
background: url(<c:url value='/images/all.png'/>) no-repeat;
display: inline-block;
background-position: 0 -938px;
margin-left: 30px;
height: 36px;
width: 146px;
}
</style>
</head>
<body>
<h1>购物车</h1>
<c:choose>
<%-- 如果没有车 或 车中没有条目 则显示图片--%>
<c:when test="${empty sessionScope.cart or fn:length(sessionScope.cart.cartItems) eq 0 }">
<img src="<c:url value='/images/cart.png'/>" width="100"/>
<h1>您的购物车为空,快去商城挑选吧!</h1>
</c:when>
<c:otherwise>
<table border="1" width="100%" cellspacing="0" background="black">
<tr>
<td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
<a href="<c:url value='CartServlet?method=clear'/>">清空购物车</a>
</td>
</tr>
<tr>
<th>图片</th>
<th>书名</th>
<th>作者</th>
<th>单价</th>
<th>数量</th>
<th>小计</th>
<th>操作</th>
</tr>
<c:forEach items="${sessionScope.cart.cartItems }" var="cartItem">
<tr>
<td><div><img src="<c:url value='/${cartItem.book.image }'/>"/></div></td>
<td>${cartItem.book.bname }</td>
<td>${cartItem.book.author }</td>
<td>${cartItem.book.price }元</td>
<td>${cartItem.count }</td>
<td>${cartItem.subtotal }元</td>
<td><a href="<c:url value='/CartServlet?method=delete&bid=${cartItem.book.bid }'/>">删除</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
合计:${sessionScope.cart.total }元
</td>
</tr>
<tr>
<td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
<a id="buy" href="<c:url value='/OrderServlet?method=add'/>"></a>
</td>
</tr>
</table>
</c:otherwise>
</c:choose>
</body>
订单模块
1 创建相关类
domain:
Order
OrderItem
dao:OrderDao
service:OrderService
web.servlete:OrderServlet
2 生成订单
3 我的订单(按用户查)
4 加载订单(按id查)
5 确认收货
domain:
/**
* 订单类
* @author 一万年行不行
*
*/
public class Order {
private String oid;
private Date ordertime; //下单时间
private double total; //合计
//订单状态(四种)
private int state; //1.未付款、2.付款未发货、3.发货未收货、4.交易成功
private User owner; //订单所有者
private String address; //收获地址
private List<OrderItem> orderItemList; //当前订单下所有商品条目
}
/**
* 订单条目类
* @author 一万年行不行
*
*/
public class OrderItem {
private String iid;
private int count; //数量
private double subtotal; //小计
private Book book; //所购买的图书
private Order order; //所属订单
}
dao
public class OrderDao {
private QueryRunner qr = new TxQueryRunner();
/**
* 添加订单
* @param order
*/
public void addOrder(Order order){
try {
String sql = "insert into orders values(?,?,?,?,?,?)";
//处理util的Date转换成sqlTimestamp(sql中的时间类型与java中时间类型不同)
Timestamp timestamp = new Timestamp(order.getOrdertime().getTime());
Object[] params = {
order.getOid(),timestamp,
order.getTotal(),order.getState(),
order.getOwner().getUid(),
order.getAddress()};
qr.update(sql,params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 添加订单中商品条目
* @param orderItemList
*/
public void addOrderItemList(List<OrderItem> orderItemList){
/*
* QueryRunner类的batch(String sql, Object[][] params)
* 其中params是多个一维数组!
* 每个一维数组都与sql在一起执行一次,则多个一维数组就执行多次
*/
try {
String sql = "insert into orderitem value(?,?,?,?,?)";
//对参数赋值 : 使用二维数组(目的是使用批处理)。
/*
* 把orderItemList转换为二维数组,则可完成批处理
* 做法:
* 把每个OrderItem对象都转换为一个一维数组
*/
//第一个[]:指定二维数组中一维数组的个数
//第二个[]:指定每个一维数组中元素的个数
Object[][] params = new Object[orderItemList.size()][];
/*
* 遍历二维数组orderItemList,得到一维数组
* 使用条目对每组参数(一维数组)赋值:
* 内部:使用每个orderItem的对象为params中每个参数赋值
*/
for (int i = 0; i < orderItemList.size(); i++) {
//得到每个条目(一维数组)
OrderItem item = orderItemList.get(i);
//使用条目对每组参数(一维数组)赋值
params[i] = new Object[]{
item.getIid(),item.getCount(),
item.getSubtotal(),item.getOrder().getOid(),
item.getBook().getBid()};
}
//执行批处理操作
qr.batch(sql,params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 使用uid查询订单
* @param uid
* @return
*/
public List<Order> findByUid(String uid) {
/*
* 1.通过uid查询出当前用户的所有List<Order>
* 2.循环遍历每个Order,加载每个Order下所有OrderItem
*/
try{
//1.得到当前用户所有订单
String sql = "select * from orders where uid= ? ";
List<Order> orderList = qr.query(sql, new BeanListHandler<Order>(Order.class),uid);
//2.循环遍历每个Order,加载每个订单下每个条目
for (Order order : orderList) {
loadOrderItems(order);
}
return orderList;
}catch(SQLException e){
throw new RuntimeException(e);
}
}
/**
* 加载指定Order的所有订单条目
* 查询结果为mapList,需要将mapListz转为OrderItem
* @param order
* @throws SQLException
*/
private void loadOrderItems(Order order) throws SQLException {
//查询两张表:orderitem book
String sql = "select * from orderitem i, book b where i.bid=b.bid AND oid = ?";
/*
* 使用MapListHandler()结果集
* 因为一行结果集不再对应一个JavaBean,所以不能使用BeanListHandler。
*
* mapList是多个map,每个map对应多个结果集。
* map中的每个键值对为表的列名
*/
List<Map<String,Object>> mapList = qr.query(sql, new MapListHandler(),order.getOid());
/*
* 需求:
* 1)需要使用每一个map生成两个对象:OrderItem和Book
* 2)然后建立两者间关系(把Book设置给OrderItem)
* 3)最终得到一个OrderItem
* 做法:创建toOrderItemList()方法来完成。
*/
List<OrderItem> orderItemList = toOrderItemList(mapList);
order.setOrderItemList(orderItemList);
}
/**
* 把一大堆map生成一大堆OrderItem
* 使mapList中每个map生成两个对象,并建立关系.
*
* @param mapList
* @return 一个完整的OrderItem
*/
private List<OrderItem> toOrderItemList(List<Map<String, Object>> mapList) {
/*
* 做法:
* 1.循环遍历 每个map
* 2.建立方法完成2.3.(toOrderItem)
* 2.使map生成两个对象
* 3.建立关系(把Book设置给OrderItem),最终结果为一个OrderItem
* 4.保存OrderItem
*/
//创建集合:用来存放所有的 OrderItem
List<OrderItem> orderItemList = new ArrayList<OrderItem>();
for (Map<String, Object> map : mapList) {
OrderItem item = toOrderItem(map);
orderItemList.add(item);
}
return orderItemList;
}
/**
* 把一个Map转换成一个OrderItem对象
* @param map
* @return
*/
private OrderItem toOrderItem(Map<String, Object> map) {
/*
* 做法:
* 1.使用toBean方法,使map分别转换出两个对象:OrderItem对象、Book对象
* 2.对OrderItem设置book属性
* 3.返回OrderItem
*/
//1.使用toBean方法,使map转换出OrderItem对象、Book对象
OrderItem orderItem = CommonUtils.toBean(map, OrderItem.class);
Book book = CommonUtils.toBean(map, Book.class);
//2.对OrderItem设置book属性,完成返回
orderItem.setBook(book);
return orderItem;
}
/**
* 加载订单
* @param oid
* @return
*/
public Order load(String oid){
try{
//1.得到订单
String sql = "select * from orders where oid= ? ";
Order order = qr.query(sql, new BeanHandler<Order>(Order.class),oid);
//加载订单下每个条目
loadOrderItems(order);
return order;
}catch(SQLException e){
throw new RuntimeException(e);
}
}
/**
* 查询订单状态
* @param oid
* @return
*/
public int getStateByOid(String oid){
String sql = "select state from orders where oid = ?";
try {
Number num = (Number) qr.query(sql,new ScalarHandler(),oid);
return num.intValue();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 修改订单状态
* @param oid
* @param state
*/
public void updateState(String oid,int state){
String sql = "update orders set state=? where oid = ?";
try {
qr.update(sql,state,oid);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
service
public class OrderService {
private OrderDao orderDao = new OrderDao();
/**
* 添加订单
* 处理事务
* @param order
*/
public void add(Order order){
try{
//开启事务
JdbcUtils.beginTransaction();
orderDao.addOrder(order); //插入订单
orderDao.addOrderItemList(order.getOrderItemList()); //插入订单中商品条目
//提交事务
JdbcUtils.commitTransaction();
}catch(Exception e){
//事务回滚
try {
JdbcUtils.rollbackTransaction();
} catch (SQLException e1) {
}
throw new RuntimeException(e); //发生回滚,则抛出异常
}
}
/**
* 我的订单
* @param uid
* @return
*/
public List<Order> myOrders(String uid) {
// TODO Auto-generated method stub
return orderDao.findByUid(uid);
}
/**
* 加载订单
* @param oid
* @return
*/
public Order load(String oid) {
// TODO Auto-generated method stub
return orderDao.load(oid);
}
/**
* 确认收货
* @param oid
* @throws OrderException
*/
public void confirm(String oid) throws OrderException{
/*
* 校验订单状态
* 不是3,抛出异常
* 修改订单状态为4,表示交易成功
*/
int state = orderDao.getStateByOid(oid);
if(state != 3) throw new OrderException("订单确认失败。请按流程确认");
//修改状态为4
orderDao.updateState(oid, 4);
}
/**
* 支付方法
* @param oid
*/
public void pay(String oid) {
/*
* 1. 获取订单的状态
* * 如果状态为1,那么执行下面代码
* * 如果状态不为1,那么本方法什么都不做
*/
int state = orderDao.getStateByOid(oid);
if(state == 1) {
// 修改订单状态为2
orderDao.updateState(oid, 2);
}
}
}
servlet
public class OrderServlet extends BaseServlet {
private static final long serialVersionUID = 1L;
private OrderService orderService = new OrderService();
/**
* 添加订单
* 用session中的公务车生成订单
*
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.从session中得到cart
* 2.使用cart生成Order对象
* 3.调用service方法完成添加订单
* 4.保存order到request中,转发到/jsps/order/desc.jsp
*/
Cart cart = (Cart) request.getSession().getAttribute("cart");
/* 2.
* 使用cart生成Order对象
* 并手动生成cart中没有的(order中需要的)相关属性
*
* Cart --> Order
*
*/
Order order = new Order();
order.setOid(CommonUtils.uuid()); //设置订单编号
order.setOrdertime(new Date()); //设置下单时间(使用当前系统时间)
order.setState(1); //设置状态为1,表示未付款
//得到当前用户,设置订单所有者
User user = (User) request.getSession().getAttribute("session_user");
order.setOwner(user); //设置订单所有者
order.setTotal(cart.getTotal()); //设置订单合计,从cart中获取
//创建订单条目(集合)
//cartItemList --> orderItemList
List<OrderItem> orderItemList = new ArrayList<OrderItem>();
//需要通过遍历cart条目,对每个订单条目属性赋值)
for (CartItem cartItem : cart.getCartItems()) {
OrderItem oi = new OrderItem(); //创建订单条目
oi.setIid(CommonUtils.uuid()); //设置条目ID
oi.setCount(cartItem.getCount()); //设置条目数量
oi.setBook(cartItem.getBook()); //设置条目的图书
oi.setSubtotal(cartItem.getSubtotal()); //设置小计
oi.setOrder(order); //设置所属订单
orderItemList.add(oi); //把订单条目添加到订单条目集合中
}
//把所有订单条目添加到订单中
order.setOrderItemList(orderItemList);
//清空购物车
cart.clear();
/*
* 3.调用orderService完成添加订单
*/
orderService.add(order);
//4.保存order到request域,转发
request.setAttribute("order", order);
return "f:/jsps/order/desc.jsp";
}
/**
* 我的订单
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String myOrders(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.从session中得到当前用户.
* 2.使用当前用户uid调用orderService#myOrders(uid),
* --得到该用户的所有订单List<Order>
* 3.把订单列表保存到request域中
* 4.转发到/jsps/order/list.jsp
*/
//得到当前用户
User user = (User) request.getSession().getAttribute("session_user");
//得到该用户的所有订单List<Order>
List<Order> orderList = orderService.myOrders(user.getUid());
//把订单列表保存到request域中,并转发
request.setAttribute("orderList", orderList);
return "f:/jsps/order/list.jsp";
}
/**
* 加载订单
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.得到oid参数
* 2.使用oid调用service方法得到Order
* 3.保存Order到request,转发
*/
String oid = request.getParameter("oid");
request.setAttribute("order", orderService.load(oid));
return "f:/jsps/order/desc.jsp";
}
/**
* 确认收货
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String confirm(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 1.获取oid参数
* 2.调用service方法
* 异常:保存异常信息,转发到msg.jsp
* 3.保存成功信息,转发到msg.jsp
*/
String oid = request.getParameter("oid");
try {
orderService.confirm(oid);
request.setAttribute("msg", "恭喜!确认完成,交易成功");
} catch (OrderException e) {
request.setAttribute("msg", e.getMessage());
}
return "f:/jsps/msg.jsp";
}
jsp
1) desc.jsp显示单个订单详细信息
<body>
<h1>当前订单</h1>
<table border="1" width="100%" cellspacing="0" background="black">
<tr bgcolor="gray" bordercolor="gray">
<td colspan="6">
订单编号:${order.oid } 成交时间:<fmt:formatDate pattern="yyyy-MM-dd HH:mm:ss" value="${order.ordertime }"/> 金额:<font color="red"><b>${order.total }元</b></font>
</td>
</tr>
<c:forEach items="${order.orderItemList }" var="orderItem">
<tr bordercolor="gray" align="center">
<td width="15%">
<div><img src="<c:url value='/${orderItem.book.image }'/>" height="75"/></div>
</td>
<td>书名:${orderItem.book.bname }</td>
<td>单价:${orderItem.book.price }元</td>
<td>作者:${orderItem.book.author }</td>
<td>数量:${orderItem.count }</td>
<td>小计:${orderItem.subtotal }</td>
</tr>
</c:forEach>
<c:url value=''/>
</table>
<br/>
<form method="post" action="<c:url value='/OrderServlet'/>" id="form" target="_parent">
<input type="hidden" name="method" value="pay"/>
<input type="hidden" name="oid" value="${order.oid} "/>
收货地址:<input type="text" name="address" size="50" value="北京市海淀区金燕龙大厦2楼216室无敌收"/><br/>
选择银行:<br/>
<input type="radio" name="pd_FrpId" value="ICBC-NET-B2C" checked="checked"/>工商银行
<img src="<c:url value='/bank_img/icbc.bmp'/>" align="middle"/>
<input type="radio" name="pd_FrpId" value="BOC-NET-B2C"/>中国银行
<img src="<c:url value='/bank_img/bc.bmp'/>" align="middle"/><br/><br/>
<input type="radio" name="pd_FrpId" value="ABC-NET-B2C"/>农业银行
<img src="<c:url value='/bank_img/abc.bmp'/>" align="middle"/>
<input type="radio" name="pd_FrpId" value="CCB-NET-B2C"/>建设银行
<img src="<c:url value='/bank_img/ccb.bmp'/>" align="middle"/><br/><br/>
<input type="radio" name="pd_FrpId" value="BOCO-NET-B2C"/>交通银行
<img src="<c:url value='/bank_img/bcc.bmp'/>" align="middle"/><br/>
</form>
<a id="pay" href="javascript:document.getElementById('form').submit();"></a>
</body>
2)list.jsp 遍历显示所有订单
<body>
<h1>我的订单</h1>
<table border="1" width="100%" cellspacing="0" background="black">
<c:forEach items="${orderList }" var="order">
<tr bgcolor="gray" bordercolor="gray">
<td colspan="6">
订单编号:${order.oid } 成交时间:${order.ordertime } 金额:<font color="red"><b>${order.total }</b></font>
<!-- 根据状态显示不同提示信息 -->
<c:choose>
<c:when test="${order.state eq 1 }">
<a href="<c:url value='/OrderServlet?method=load&oid=${order.oid }'/>">付款</a>
</c:when>
<c:when test="${order.state eq 2 }">等待发货</c:when>
<c:when test="${order.state eq 3 }">
<a href="<c:url value='/OrderServlet?method=confirm&oid=${order.oid }'/>">确认收货</a>
</c:when>
<c:when test="${order.state eq 4 }">交易成功</c:when>
</c:choose>
</td>
</tr>
<c:forEach items="${order.orderItemList }" var="orderItem">
<tr bordercolor="gray" align="center">
<td width="15%">
<div><img src="<c:url value='/${orderItem.book.image }'/>" height="75"/></div>
</td>
<td>书名:${orderItem.book.bname }</td>
<td>单价:${orderItem.book.price }</td>
<td>作者:${orderItem.book.author }</td>
<td>数量:${orderItem.count }</td>
<td>小计:${orderItem.subtotal }元</td>
</tr>
</c:forEach>
</c:forEach>
</table>
</body>