分析订单表-以超市小票为例
超市小票案例
会员ID:583381
流水号:jlf_ba_31_sy003_1002
交易时间:2018年3月10日08:41:53
商品名称 商品价格 商品数量 小计
好日子 15 2 30
芙蓉王 25 2 50
黄鹤楼 15 3 45
大前门 10 1 10
总金额:135元
设计表,存储小票上的数据
会员id 流水号 交易时间 商品名称 商品价格 商品数量 小计 总金额
1231231 XXX XXXX 好日子 15 2 30 135
1231231 XXX XXXX 芙蓉王 25 2 50 135
1231231 XXX XXXX 黄鹤楼 15 3 45 135
1231231 XXX XXXX 大前门 10 1 10 135
这种是我们最直接的想法,直接把订单项存到一个表中,但是这种设计有一个严重的弊端。
[v_error]弊端:数据冗余严重。[/v_error]
[v_notice]DB原则:存储最少的数据,办更多的事情。[/v_notice]
改进方案
一个表专注于交易描述,订单表 orders
订单id(流水号) 会员id 交易时间 总金额 收货人姓名 地址 电话 订单状态(1234)
1123 1231231 XXXX 135
1124 1234444 YYYY 200
orders表中的会员id列参照了用户表uid
订单状态:
买家:下单未付款,付款未发货,已发货,签收
卖家: 未付款,发货,未签收,已收货(结束)
一个表专注于每笔订单详细交易情况,订单项orderitem
订单项id 商品id 数量 小计 所在订单编号
001 p003 2 30 1123
002 p005 2 50 1123
003 p101 3 45 1123
004 p220 1 10 1123
005 p334 1 101 1124
006 p556 3 54 1124
007 p445 5 45 1124
orderitem表中的商品id参照了商品表的pid
orderitem表中的所在订单编号参照了订单表的订单id
我们本次项目所用的就是第二个方案,之前我们已经完成了表的设计
提交订单原理分析
用户点击提交订单,将购物车中的数据以订单/订单项形式保存下来。
保存订单:
为订单表中插入一行数据,描述本次交易,这行数据部分数据是通过程序赋予,部分数据来自购物车的,部分数据来自session中的用户。
oid:UUIDUtils orderTime:new Date(); total: 从购物车获取
state:1 address: null name:null telephone:null uid:从session中的用户获取
保存订单项:
向订单项表中插入数据,描述当前订单的详细的购买信息,部分数据来自于购物车,部分数据需要通过程序赋予。
itemid: UUIDUtils quantity:来自于购物车中的购物项
total:来自于购物车中的购物项 pid:来自于购物车上的购物项下商品对象pid oid:来自于当前订单id
[v_warn]提交订单时,订单以及订单项必须同时成功(事务)[/v_warn]
具体实现
实现订单模块相关程序
创建OrderServlet、OrderService、OrderServiceImp、OrderDao、OrderDaoImp。
在domain中创建Order和OrderItem。
Order.java
根据数据库Order表创建
package com.geekerstar.store.domain;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Order {
@Override
public String toString() {
return "Order [oid=" + oid + ", ordertime=" + ordertime + ", total=" + total + ", state=" + state + ", address="
+ address + ", name=" + name + ", telephone=" + telephone + ", user=" + user + ", list=" + list + "]";
}
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 Listlist = new ArrayList();
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 ListgetList() {
return list;
}
public void setList(Listlist) {
this.list = list;
}
}
OrderItem
根据数据库orderitem表创建
package com.geekerstar.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;
}
}
JSP页面准备工作
在Cart.jsp中修改提交订单链接到OrderServlet
OrderServlet中增加saveOrder方法
package com.geekerstar.store.web.servlet;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.geekerstar.store.domain.Cart;
import com.geekerstar.store.domain.CartItem;
import com.geekerstar.store.domain.Order;
import com.geekerstar.store.domain.OrderItem;
import com.geekerstar.store.domain.User;
import com.geekerstar.store.service.OrderService;
import com.geekerstar.store.service.serviceImp.OrderServiceImp;
import com.geekerstar.store.utils.UUIDUtils;
import com.geekerstar.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";
}
}
修改web.xml
web.xml中添加
OrderServlet
OrderServlet
com.geekerstar.store.web.servlet.OrderServlet
OrderServlet
/OrderServlet
在Cart.java中做如下修改
//返回MAP中所有的值
public CollectiongetCartItems(){
return map.values();
}
在OrderService中创建方法
void saveOrder(Order order)throws Exception;
在OrderServiceImp中实现方法,用事务实现
package com.geekerstar.store.service.serviceImp;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import com.geekerstar.store.dao.daoImp.OrderDaoImp;
import com.geekerstar.store.domain.Order;
import com.geekerstar.store.domain.OrderItem;
import com.geekerstar.store.domain.PageModel;
import com.geekerstar.store.domain.User;
import com.geekerstar.store.service.OrderService;
import com.geekerstar.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中添加方法
void saveOrder(Connection conn, Order order)throws Exception;
void saveOrderItem(Connection conn, OrderItem item)throws Exception;
OrderDaoImp中实现两个方法
@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_info.jsp中获取订单信息,由于页面较多就不一一展示了,详情请看源码,并且原理和之前的一样,可以参考下面的图片进行修改。
效果演示
运行程序,添加两件商品到购物车,然后点击提交订单按钮
此时跳到这个页面
然后我们查看数据库,发现订单信息已经添加到数据库了,提交订单成功
源码下载
导航目录