用户在购物车中提交订单,将购物车中的数据以订单/订单项的形式保存下来,之后清空购物车。
整体技术路线:客户端点击提交订单至OrderServlet中saveOrder方法中,将购物车中的购物信息以订单形式保存,清空购物车,之后将订单放入request,转发到订单详情页面。
将购物车中信息抽取成两个数据库表,分别是:
(1)order表:表示此次交易的所有商品项,类似于超市小票;
为订单表中插入一行数据,描述本次交易,这行数据部分数据是通过程序赋予,部分数据来自于购物车的,部分数据来自于session中的用户,其中字段包含:
oid:UUIDUtils orderTime:new Date(); total: 从购物车获取 state:1 address: null name:null telephone:null uid:从session中的用户获取
(2)orderitem表:表示此次订单中的每个订单项,类似于小票中的各个商品项;
向订单项表中插入数据,描述当前订单的详细的购买信息,部分数据来自于购物车,部分数据需要通过程序赋予
itemid: UUIDUtils quantity:来自于购物车中的购物项 total:来自于购物车中的购物项 pid:来自于购物车上的购物项下商品对象pid oid:来自于当前订单id
注:商品提交时需要加入事务,一旦订单或订单项提交失败,则全部回滚
思路:点击cart.jsp页面中的【提交订单】,调用服务器端的OrderServlet中的saveOrder方法,之后调用OrderService OrderServiceImp OrderDao OrderDaoImp中的saveOrder方法,最终将数据存入数据库。
代码如下:
购物车界面:cart.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>购物车</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css" type="text/css" />
<script src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type="text/javascript"></script>
<!-- 引入自定义css文件 style.css -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css" type="text/css"/>
<style>
body {
margin-top: 20px;
margin: 0 auto;
}
.carousel-inner .item img {
width: 100%;
height: 300px;
}
.container .row div {
/* position:relative;
float:left; */
}
font {
color: #3164af;
font-size: 18px;
font-weight: normal;
padding: 0 10px;
}
</style>
</head>
<body>
<%@ include file="/jsp/header.jsp" %>
<div class="container">
<c:if test="${empty cart.cartItems }">
<div class="row">
<div class="col-md-12">
<h1>开启剁手模式</h1>
</div>
</div>
</c:if>
<c:if test="${not empty cart.cartItems }">
<div class="row">
<div style="margin:0 auto; margin-top:10px;width:950px;">
<strong style="font-size:16px;margin:5px 0;">订单详情</strong>
<table class="table table-bordered">
<tbody>
<tr class="warning">
<th>图片</th>
<th>商品</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
<th>操作</th>
</tr>
<c:forEach items="${cart.cartItems}" var="item">
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="id" value="22">
<img src="${pageContext.request.contextPath}/${item.product.pimage}" width="70" height="60">
</td>
<td width="30%">
<a target="_blank">${item.product.pname}</a>
</td>
<td width="20%">
¥${item.product.shop_price}
</td>
<td width="10%">
<input type="text" name="quantity" value="${item.num}" maxlength="4" size="10">
</td>
<td width="15%">
<span class="subtotal">¥${item.subTotal}</span>
</td>
<td>
<a href="javascript:;" id="${item.product.pid}" class="delete">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<div style="margin-right:130px;">
<div style="text-align:right;">
<em style="color:#ff6600;">
登录后确认是否享有优惠
</em> 赠送积分: <em style="color:#ff6600;">${cart.total}</em> 商品金额: <strong style="color:#ff6600;">¥${cart.total}元</strong>
</div>
<div style="text-align:right;margin-top:10px;margin-bottom:10px;">
<a href="${pageContext.request.contextPath}/CartServlet?method=clearCart" id="clear" class="clear">清空购物车</a>
<a href="${pageContext.request.contextPath}/OrderServlet?method=saveOrder">
<%--提交表单 --%>
<input type="submit" width="100" value="提交订单" name="submit" border="0" style="background: url('${pageContext.request.contextPath}/img/register.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0);
height:35px;width:100px;color:white;">
</a>
</div>
</div>
</c:if>
</div>
<%@ include file="/jsp/footer.jsp" %>
</body>
<script>
$(function(){
//页面加载完毕之后获取到class的值为delete元素,为其绑定点击事件
$(".delete").click(function(){
if(confirm("确认删除?")){
//获取到被删除商品pid
var pid=this.id;
window.location.href="/store_v5/CartServlet?method=removeCartItem&id="+pid;
}
});
});
</script>
</html>
OrderServlet.java
ackage cn.itcast.store.web.servlet;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.store.domain.Cart;
import cn.itcast.store.domain.CartItem;
import cn.itcast.store.domain.Order;
import cn.itcast.store.domain.OrderItem;
import cn.itcast.store.domain.PageModel;
import cn.itcast.store.domain.User;
import cn.itcast.store.service.OrderService;
import cn.itcast.store.service.serviceImp.OrderServiceImp;
import cn.itcast.store.utils.PaymentUtil;
import cn.itcast.store.utils.UUIDUtils;
import cn.itcast.store.web.base.BaseServlet;
public class OrderServlet extends BaseServlet {
// saveOrder 将购物车中的信息以订单的形式保存
public String saveOrder(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//确认用户登录状态
User user=(User)req.getSession().getAttribute("loginUser");
if(null==user){
req.setAttribute("msg", "请登录之后在下单");
return "/jsp/info.jsp";
}
//获取购物车
Cart cart=(Cart)req.getSession().getAttribute("cart");
//创建订单对象,为订单对象赋值
Order order=new Order();
order.setOid(UUIDUtils.getCode());
order.setOrdertime(new Date());
order.setTotal(cart.getTotal());
order.setState(1);
order.setUser(user);
//遍历购物项的同时,创建订单项,为订单项赋值
for (CartItem item : cart.getCartItems()) {
OrderItem orderItem=new OrderItem();
orderItem.setItemid(UUIDUtils.getCode());
orderItem.setQuantity(item.getNum());
orderItem.setTotal(item.getSubTotal());
orderItem.setProduct(item.getProduct());
//设置当前的订单项属于哪个订单:程序的角度体检订单项和订单对应关系
orderItem.setOrder(order);
order.getList().add(orderItem);
}
//调用业务层功能:保存订单
OrderService OrderService=new OrderServiceImp();
//将订单数据,用户的数据,订单下所有的订单项都传递到了service层
OrderService.saveOrder(order);
//清空购物车
cart.clearCart();
//将订单放入request
req.setAttribute("order", order);
//转发/jsp/order_info.jsp
return "/jsp/order_info.jsp";
}
}
OrderService.java
package cn.itcast.store.service;
import java.util.List;
import cn.itcast.store.domain.Order;
import cn.itcast.store.domain.PageModel;
import cn.itcast.store.domain.User;
public interface OrderService {
void saveOrder(Order order)throws Exception;
}
OrderServiceImp.java
package cn.itcast.store.service.serviceImp;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import cn.itcast.store.dao.OrderDao;
import cn.itcast.store.dao.daoImp.OrderDaoImp;
import cn.itcast.store.domain.Order;
import cn.itcast.store.domain.OrderItem;
import cn.itcast.store.domain.PageModel;
import cn.itcast.store.domain.User;
import cn.itcast.store.service.OrderService;
import cn.itcast.store.utils.JDBCUtils;
public class OrderServiceImp implements OrderService {
OrderDao orderDao=new OrderDaoImp();
@Override
public void saveOrder(Order order) throws SQLException {
//保存订单和订单下所有的订单项(同时成功,失败)
/*try {
JDBCUtils.startTransaction();
OrderDao orderDao=new OrderDaoImp();
orderDao.saveOrder(order);
for(OrderItem item:order.getList()){
orderDao.saveOrderItem(item);
}
JDBCUtils.commitAndClose();
} catch (Exception e) {
JDBCUtils.rollbackAndClose();
}
*/
Connection conn=null;
try {
//获取连接
conn=JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//保存订单
orderDao.saveOrder(conn,order);
//保存订单项
for (OrderItem item : order.getList()) {
orderDao.saveOrderItem(conn,item);
}
//提交
conn.commit();
} catch (Exception e) {
//回滚
conn.rollback();
}
}
}
OrderDao.java
package cn.itcast.store.dao;
import java.sql.Connection;
import java.util.List;
import cn.itcast.store.domain.Order;
import cn.itcast.store.domain.OrderItem;
import cn.itcast.store.domain.User;
public interface OrderDao {
void saveOrder(Connection conn, Order order)throws Exception;
void saveOrderItem(Connection conn, OrderItem item)throws Exception;
}
OrderDaoImp.java
package cn.itcast.store.dao.daoImp;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.itcast.store.dao.OrderDao;
import cn.itcast.store.domain.Order;
import cn.itcast.store.domain.OrderItem;
import cn.itcast.store.domain.Product;
import cn.itcast.store.domain.User;
import cn.itcast.store.utils.JDBCUtils;
public class OrderDaoImp implements OrderDao {
@Override
public void saveOrder(Connection conn, Order order) throws Exception {
String sql="INSERT INTO orders VALUES(?,?,?,?,?,?,?,?)";
QueryRunner qr=new QueryRunner();
Object[] params={order.getOid(),order.getOrdertime(),order.getTotal(),order.getState(),order.getAddress(),order.getName(),order.getTelephone(),order.getUser().getUid()};
qr.update(conn,sql,params);
}
@Override
public void saveOrderItem(Connection conn, OrderItem item) throws Exception {
String sql="INSERT INTO orderitem VALUES(?,?,?,?,?)";
QueryRunner qr=new QueryRunner();
Object[] params={item.getItemid(),item.getQuantity(),item.getTotal(),item.getProduct().getPid(),item.getOrder().getOid()};
qr.update(conn,sql,params);
}
}
Order.java
package cn.itcast.store.domain;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Order {
private String oid; //订单编号
private Date ordertime; //下单时间
private double total; //总计
private int state; //状态
private String address; //收货人地址
private String name; //收货人姓名
private String telephone; //收货人电话
// private String uid;
// 1_程序对象和对象发生关系,而不是对象和对象的属性发生关系
// 2_设计Order目的:让order携带订单上的数据向service,dao传递,user对象是可以携带更多的数据
private User user;
// 程序中体现订单对象和订单项之间关系,我们再项目中的部分功能中有类似的需求:查询订单的同时还需要获取订单下所有的订单项
private List<OrderItem> list = new ArrayList<OrderItem>();
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public Date getOrdertime() {
return ordertime;
}
public void setOrdertime(Date ordertime) {
this.ordertime = ordertime;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<OrderItem> getList() {
return list;
}
public void setList(List<OrderItem> list) {
this.list = list;
}
}
OrderItem.java
package cn.itcast.store.domain;
public class OrderItem {
private String itemid; //id
private int quantity; //数量
private double total; //小计
//1_对象对应对象
//2_product,order携带更多的数据
private Product product;
private Order order;
public String getItemid() {
return itemid;
}
public void setItemid(String itemid) {
this.itemid = itemid;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
order_info.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>下订单</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css" type="text/css" />
<script src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type="text/javascript"></script>
<!-- 引入自定义css文件 style.css -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css" type="text/css"/>
<style>
body {
margin-top: 20px;
margin: 0 auto;
}
.carousel-inner .item img {
width: 100%;
height: 300px;
}
</style>
</head>
<body>
<%@ include file="/jsp/header.jsp" %>
<div class="container">
<form id="orderForm" method="post" action="${pageContext.request.contextPath}/OrderServlet?method=payOrder">
<div class="row">
<div style="margin:0 auto;margin-top:10px;width:950px;">
<strong>订单详情</strong>
<table class="table table-bordered">
<tbody>
<tr class="warning">
<th colspan="5">订单编号:${order.oid}</th>
</tr>
<tr class="warning">
<th>图片</th>
<th>商品</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
</tr>
<c:forEach items="${order.list}" var="item">
<tr class="active">
<td width="60" width="40%">
<input type="hidden" name="id" value="22">
<img src="${pageContext.request.contextPath}/${item.product.pimage}" width="70" height="60">
</td>
<td width="30%">
<a target="_blank">${item.product.pname}</a>
</td>
<td width="20%">
¥${item.product.shop_price}
</td>
<td width="10%">
${item.quantity}
</td>
<td width="15%">
<span class="subtotal">¥${item.total}</span>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<div style="text-align:right;margin-right:120px;">
商品金额: <strong style="color:#ff6600;">¥${order.total }元</strong>
</div>
</div>
<div>
<hr/>
<div class="form-group">
<label for="username" class="col-sm-1 control-label">地址</label>
<div class="col-sm-5">
<input type="text" name="address" class="form-control" id="username" placeholder="请输入收货地址">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-1 control-label">收货人</label>
<div class="col-sm-5">
<input type="text" name="name" class="form-control" id="inputPassword3" placeholder="请输收货人">
</div>
</div>
<div class="form-group">
<label for="confirmpwd" class="col-sm-1 control-label">电话</label>
<div class="col-sm-5">
<input type="text" name="telephone" class="form-control" id="confirmpwd" placeholder="请输入联系方式">
<input type="hidden" name="oid" value="${order.oid}"/>
</div>
</div>
<hr/>
<div style="margin-top:5px;margin-left:150px;">
<strong>选择银行:</strong>
<p>
<br/>
<input type="radio" name="pd_FrpId" value="ICBC-NET-B2C" checked="checked" />工商银行
<img src="${pageContext.request.contextPath}/img/bank_img/icbc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="BOC-NET-B2C" />中国银行
<img src="${pageContext.request.contextPath}/img/bank_img/bc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="ABC-NET-B2C" />农业银行
<img src="${pageContext.request.contextPath}/img/bank_img/abc.bmp" align="middle" />
<br/>
<br/>
<input type="radio" name="pd_FrpId" value="BOCO-NET-B2C" />交通银行
<img src="${pageContext.request.contextPath}/img/bank_img/bcc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="PINGANBANK-NET" />平安银行
<img src="${pageContext.request.contextPath}/img/bank_img/pingan.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="CCB-NET-B2C" />建设银行
<img src="${pageContext.request.contextPath}/img/bank_img/ccb.bmp" align="middle" />
<br/>
<br/>
<input type="radio" name="pd_FrpId" value="CEB-NET-B2C" />光大银行
<img src="${pageContext.request.contextPath}/img/bank_img/guangda.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="CMBCHINA-NET-B2C" />招商银行
<img src="${pageContext.request.contextPath}/img/bank_img/cmb.bmp" align="middle" />
</p>
<hr/>
<p style="text-align:right;margin-right:100px;">
<a href="javascript:document.getElementById('orderForm').submit();">
<img src="${pageContext.request.contextPath}/img/finalbutton.gif" width="204" height="51" border="0" />
</a>
</p>
<hr/>
</div>
</div>
</form>
</div>
<%@ include file="/jsp/footer.jsp" %>
</body>
</html>