【Spring+Mybatis+SpringMVC整合项目六】天猫商城(前台-购物流程)

前台一共有以下这些场景

这里记录购买商品这里场景开发,首先看看购物流程

 1. 登录
2. 访问产品页
3. 立即购买
4. 进入结算页面
5. 加入购物车
6. 查看购物车
7. 选中购物车中的商品
8. 又到了第4步的结算页面
9. 在结算页面生成订单
10. 付款
11. 确认收货
12. 评价


围绕购物流程最重要的两个表是OrderItem 和 Order表

关于OrderItem的业务行为
1. 立即购买 —— 新增 OrderItem
2. 加入购物车 —— 新增 OrderItem
3. 查看购物车 —— 显示未和Order关联的OrderItem
4. 选中购物车中的商品 —— 选中OrderItem
5. 结算页面 —— 显示选中的OrderItem

6. 生成订单 —— 新增Order
7 .付款 —— 修改Order状态
8. 我的订单 —— 显示Order
9. 确认收货 —— 修改Order状态

OrderItem表

Order表

 


 

当我们按下立即购买时,如果未登陆,那么点击立即购买之后会弹出一个登陆窗口,需要登陆后才能购买

前端检查是否登录js代码

$(".buyLink").click(function(){var page = "forecheckLogin";$.get(page,function(result){if("success"==result){var num = $(".productNumberSetting").val();location.href= $(".buyLink").attr("href")+"&num="+num;}else{$("#loginModal").modal('show');}});return false;});

forecheckLogin

@RequestMapping("forecheckLogin")@ResponseBodypublic String checkLogin( HttpSession session) {User user =(User)  session.getAttribute("user");if(null!=user)return "success";return "fail";}

如果我们登陆了会做如下操作

通过上个步骤访问的地址 /forebuyone 导致ForeController.buyone()方法被调用
1. 获取参数pid
2. 获取参数num
3. 根据pid获取产品对象p
4. 从session中获取用户对象user

接下来就是新增订单项OrderItem,如

在OrderItem表里插入一条数据,这条数据会表示:
1. pid =844 购买的商品id
2. oid = null, 这个订单项还没有生成对应的订单,即还在购物车中
3. uid= 3,用户的id是3
4. number=3, 购买了3件产品 

 

新增订单项要考虑两个情况
a. 如果已经存在这个产品对应的OrderItem,并且还没有生成订单,即还在购物车中。 那么就应该在对应的OrderItem基础上,调整数量
a.1 基于用户对象user,查询没有生成订单的订单项集合
a.2 遍历这个集合
a.3 如果产品是一样的话,就进行数量追加
a.4 获取这个订单项的 id

b. 如果不存在对应的OrderItem,那么就新增一个订单项OrderItem
b.1 生成新的订单项
b.2 设置数量,用户和产品
b.3 插入到数据库
b.4 获取这个订单项的 id

最后, 基于这个订单项id客户端跳转到结算页面/forebuy

@RequestMapping("forebuyone")public String buyone(int pid, int num, HttpSession session) {Product p = productService.get(pid);int oiid = 0;User user =(User)  session.getAttribute("user");boolean found = false;List ois = orderItemService.listByUser(user.getId());for (OrderItem oi : ois) {if(oi.getProduct().getId().intValue()==p.getId().intValue()){oi.setNumber(oi.getNumber()+num);orderItemService.update(oi);found = true;oiid = oi.getId();break;}}if(!found){OrderItem oi = new OrderItem();oi.setUid(user.getId());oi.setNumber(num);oi.setPid(pid);orderItemService.add(oi);oiid = oi.getId();}return "redirect:forebuy?oiid="+oiid;}}

结算页面是这样的

可以发现跳转到/forebuy其实就是进行了服务器端的跳转,使得ForeServlet.buy()被调用了

1. 通过字符串数组获取参数oiid
为什么这里要用字符串数组试图获取多个oiid,而不是int类型仅仅获取一个oiid?因为结算页面还需要显示在购物车中选中的多条OrderItem数据,所以为了兼容从购物车页面跳转过来的需求,要用字符串数组获取多个oiid
2. 准备一个泛型是OrderItem的集合ois
3. 根据前面步骤获取的oiids,从数据库中取出OrderItem对象,并放入ois集合中
4. 累计这些ois的价格总数,赋值在total上
5. 把订单项集合放在session的属性 "ois" 上
6. 把总价格放在 model的属性 "total" 上
7. 服务端跳转到buy.jsp 

@RequestMapping("forebuy")public String buy( Model model,String[] oiid,HttpSession session){List ois = new ArrayList<>();float total = 0;for (String strid : oiid) {int id = Integer.parseInt(strid);OrderItem oi= orderItemService.get(id);total +=oi.getProduct().getPromotePrice()*oi.getNumber();ois.add(oi);}session.setAttribute("ois", ois);model.addAttribute("total", total);return "fore/buy";}}

在buy.jsp中,点击提交按钮后,就把表单里面的信息提交到/forecreateOrder

到了订单生成的开发,对于每个订单,都有自己的一个状态

1. 首先是创建订单,刚创建好之后,订单处于waitPay 待付款状态
2. 接着是付款,付款后,订单处于waitDelivery 待发货状态
3. 前两步都是前台用户操作导致的,接下来需要到后台做发货操作,发货后,订单处于waitConfirm 待确认收货状态
4. 接着又是前台用户进行确认收货操作,操作之后,订单处于waitReview 待评价状态
5. 最后进行评价,评价之后,订单处于finish 完成状态

以上状态都是一个接一个的,不能跳状态进行。
比较特殊的是,无论当前订单处于哪个状态,都可以进行删除操作。 像订单这样极其重要的业务数据,实际上是不允许真正从数据库中删除掉的,而是把状态标记为删除,以表示其被删掉了,所以在删除之后,订单处于 delete 已删除状态 

 

这里,在写createOrder代码之前,我们还需在OrderService中新增方法add(Order c,List ois);

看看它的实现方法

1.增加了事务管理,因为增加订单需要同时修改两个表,orderItem表和order表,如果在修改了orderItem表之后发生突发意外,没能修改到order表,会导致数据不一致,所以这里增加事务管理,当有异常时就回滚

2.传入ois是为了算出总价格,最后返回所有商品价格之和

@Override@Transactional(propagation= Propagation.REQUIRED,rollbackForClassName="Exception")public float add(Order o, List ois) {float total = 0;add(o);if(false)throw new RuntimeException();for (OrderItem oi: ois) {oi.setOid(o.getId());orderItemService.update(oi);total+=oi.getProduct().getPromotePrice()*oi.getNumber();}return total;}

现在开始写createOrder代码

提交订单访问路径 /forecreateOrder, 导致ForeController.createOrder 方法被调用
1. 从session中获取user对象
2. 通过参数Order接受地址,邮编,收货人,用户留言等信息
3. 根据当前时间加上一个4位随机数生成订单号
4. 根据上述参数,创建订单对象
5. 把订单状态设置为等待支付
6. 从session中获取订单项集合 ( 在forebuy中,订单项集合被放到了session中 )
7. 把订单加入到数据库,并且遍历订单项集合,设置每个订单项的order,更新到数据库
8. 统计本次订单的总金额
9. 客户端跳转到确认支付页forealipay,并带上订单id和总金额

@RequestMapping("forecreateOrder")
public String createOrder( Model model,Order order,HttpSession session){User user =(User)  session.getAttribute("user");String orderCode = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + RandomUtils.nextInt(10000);order.setOrderCode(orderCode);order.setCreateDate(new Date());order.setUid(user.getId());order.setStatus(OrderService.waitPay);List ois= (List)  session.getAttribute("ois");float total =orderService.add(order,ois);return "redirect:forealipay?oid="+order.getId() +"&total="+total;
}

支付页forealipay没有做什么事情,因为这里并没有真正使用到支付的功能~只是做了一个跳转。。。

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" isELIgnored="false"%>扫一扫付款(元)

1. 在上一步确认访问按钮提交数据到/forepayed,导致ForeController.payed方法被调用
1.1 获取参数oid
1.2 根据oid获取到订单对象order
1.3 修改订单对象的状态和支付时间
1.4 更新这个订单对象到数据库
1.5 把这个订单对象放在model的属性"o"上
1.6 服务端跳转到payed.jsp

@RequestMapping("forepayed")
public String payed(int oid, float total, Model model) {Order order = orderService.get(oid);order.setStatus(OrderService.waitDelivery);order.setPayDate(new Date());orderService.update(order);model.addAttribute("o", order);return "fore/payed";
}

payed.jsp图

其中这里可以点击 查看交易详情,跳转到个人订单页面

 

/forebought导致ForeController.bought()方法被调用
1. 通过session获取用户user
2. 查询user所有的状态不是"delete" 的订单集合os
3. 为这些订单填充订单项
4. 把os放在model的属性"os"上
5. 服务端跳转到bought.jsp

@RequestMapping("forebought")public String bought( Model model,HttpSession session) {User user =(User)  session.getAttribute("user");List os= orderService.list(user.getId(),OrderService.delete);orderItemService.fill(os);model.addAttribute("os", os);return "fore/bought";}}

 bought.jsp


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部