功能介绍:
前台功能:
1.创建订单
controller层实现:
传入userId和收货地址shippingId,由后台自动创建订单。
1 @RequestMapping("create.do")
2 @ResponseBody
3 public ServerResponse create(HttpServletRequest request, Integer shippingId) {
4 // User user = (User)session.getAttribute(Const.CURRENT_USER);
5
6 String loginToken = CookieUtil.readLoginToken(request);
7 if(StringUtils.isEmpty(loginToken)) {
8 return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
9 }
10 String userJsonStr = RedisShardedPoolUtil.get(loginToken);
11 User user = JsonUtil.string2Obj(userJsonStr, User.class);
12
13 if(user ==null){
14 return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
15 }
16 //将userId和shippingId传入,创建订单
17 return iOrderService.createOrder(user.getId(), shippingId);
18 }
View Code
service层实现:
1)根据userId从购物车表CART中将已勾选的商品取出来,由cartList保存,然后根据这个cartList,由getCartOrderItem()生成订单详情orderItemList。
2)由订单详情orderItemList可以计算出整个订单的总价,由getOrderTotalPrice()实现。
3)根据以上计算出来的订单总价、收货地址shipingId、userId生成最后的订单order,由assembleOrder()实现,并持久化到数据库中。
4)由assembleOrder()生成的订单,是带有最后的订单号的orderNo,所以将这个订单号更新到之前的订单详情orderItemList中,由mybatis的批量插入实现。
5)根据订单详情orderItemList,去对应的商品表中减库存,由reduceProductStock()实现。
6)清空当前购物车,由cleanCart()实现。
7)将生成的最后的订单order和订单详情orderItemList,组合成vo后返回给前台。
1 public ServerResponse createOrder(Integer userId, Integer shippingId) {
2 //从购物车中获取数据
3 //将购物车中已勾选的物品获取出来,这些物品会用来生成订单
4 List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
5
6 //根据这些物品,即cartList,生成订单详情List
7 ServerResponse serverResponse = this.getCartOrderItem(userId, cartList);
8 if(!serverResponse.isSuccess()) {
9 return serverResponse;
10 }
11 List<OrderItem> orderItemList = (List<OrderItem>)serverResponse.getData();
12 //根据订单详情list,计算订单总价
13 BigDecimal payment = this.getOrderTotalPrice(orderItemList);
14
15 //生成订单
16 Order order = this.assembleOrder(userId, shippingId, payment);
17 if(order == null) {
18 return ServerResponse.createByErrorMessage("生成订单错误");
19 }
20 if(CollectionUtils.isEmpty(orderItemList)) {
21 return ServerResponse.createByErrorMessage("购物车为空");
22 }
23 //将订单号逐一的更新到当前订单详情中,也就是一条订单数据可以对应多条订单详情
24 for(OrderItem orderItem : orderItemList) {
25 orderItem.setOrderNo(order.getOrderNo());
26 }
27 //mybatis批量插入
28 //由于订单详情,一次性可能有多个商品,多个订单详情,也就是多条数据,所以这里就要使用一次性批量插入
29 orderItemMapper.batchInsert(orderItemList);
30 //生成成功,减少产品的库存
31 this.reduceProductStock(orderItemList);
32
33 //清空购物车
34 this.cleanCart(cartList);
35
36 //将订单明细返回给前端,返回给前端
37 //pojo->vo
38 //组装vo,传给前端的数据
39 OrderVo orderVo = assembleOrderVo(order, orderItemList);
40 return ServerResponse.createBySuccess(orderVo);
41 }
View Code
getCartOrderItem()由购物车勾选状态生成订单详情实现:
从购物车表中获取productId,然后从product表中获取当前商品的详细信息,校验商品的在售和库存状态,然后组装订单详情,一种商品对应一个订单详情,一个订单详情由orderNo唯一标识,多个订单详情对应一个订单,最后将组装完成的订单详情cartItemList返回。
1 private ServerResponse getCartOrderItem(Integer userId,List<Cart> cartList){
2 List<OrderItem> orderItemList = Lists.newArrayList();
3 if(CollectionUtils.isEmpty(cartList)){
4 return ServerResponse.createByErrorMessage("购物车为空");
5 }
6
7 //校验购物车的数据,包括产品的状态和数量
8 for(Cart cartItem : cartList){
9 OrderItem orderItem = new OrderItem();
10 //从购物车中获取productId,然后从product表中获取当前产品的详细信息
11 Product product = productMapper.selectByPrimaryKey(cartItem.getProductId());
12 //查看当前产品是否在售
13 if(Const.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()){
14 return ServerResponse.createByErrorMessage("产品"+product.getName()+"不是在线售卖状态");
15 }
16
17 //校验库存,校验当前产品选购的数量是否超过产品本身库存
18 if(cartItem.getQuantity() > product.getStock()){
19 return ServerResponse.createByErrorMessage("产品"+product.getName()+"库存不足");
20 }
21
22 //组装订单详情,一种商品,一个订单详情,而订单详情又由orderNo唯一标识,所以可能多种商品有同样的orderNo,而orderNo又对应订单order中的一个订单,也由orderNo唯一标识
23
24 orderItem.setUserId(userId);
25 orderItem.setProductId(product.getId());
26 orderItem.setProductName(product.getName());
27 orderItem.setProductImage(product.getMainImage());
28 orderItem.setCurrentUnitPrice(product.getPrice());
29 orderItem.setQuantity(cartItem.getQuantity());
30 // 这里将当前商品的总价:单价*数量,存进数据表
31 orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(),cartItem.getQuantity()));
32 //将当前订单详情加入订单详情List中
33 orderItemList.add(orderItem);
34 }
35 //将订单详情list返回
36 return ServerResponse.createBySuccess(orderItemList);
37 }
View Code
getOrderTotalPrice()由订单详情计算出整个订单的总价:
由于在生成订单详情的时候,已经对每种商品单独计算过对应的总价,存储在订单详情中了,所以这里只需要将订单中的所有商品价值相加即可。
1 private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
2 BigDecimal payment = new BigDecimal("0");
3 //计算当前订单总计,逐一相加
4 for(OrderItem orderItem : orderItemList) {
5 payment = BigDecimalUtil.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
6 }
7 return payment;
8 }
View Code
assembleOrder()由userId、订单详情、总价组装最后的订单:
由generateOrderNo()生成订单号,然后添加订单所需要的字段,比如订单号、订单状态、运费、支付类型、订单总价等,然后将订单持久化到数据库中。
1 private Order assembleOrder(Integer userId, Integer shippingId, BigDecimal payment) {
2 Order order = new Order();
3 //生成订单号orderNo,很重要
4 long orderNo = this.generateOrderNo();
5 //设置订单号
6 order.setOrderNo(orderNo);
7 //设置订单状态
8 order.setStatus(Const.OrderStatusEnum.NO_PAY.getCode());
9 //设置运费
10 order.setPostage(0);
11 //设置支付类型
12 order.setPaymentType(Const.PaymentTypeEnum.ONLINE_PAY.getCode());
13 //设置订单总价
14 order.setPayment(payment);
15 order.setUserId(userId);
16 order.setShippingId(shippingId);
17
18 //将这个订单持久化到数据库中
19 int rowCount = orderMapper.insert(order);
20 if(rowCount > 0) {
21 return order;
22 }
23 return null;
24 }
View Code
reduceProductStock()由订单详情去对应的商品表中减库存:
1 private void reduceProductStock(List<OrderItem> orderItemList) {
2 //根据订单详情list,逐一针对商品,去product表中减库存
3 for(OrderItem orderItem : orderItemList) {
4 //根据productId,从product表中拿到当前商品
5 Product product = productMapper.selectByPrimaryKey(orderItem.getProductId());
6 //减库存
7 product.setStock(product.getStock() - orderItem.getQuantity());
8 //将库存信息更新到product表中
9 productMapper.updateByPrimaryKeySelective(product);
10 }
11 }
View Code
cleanCart()清空购物车:
1 private void cleanCart(List<Cart> cartList) {
2 for(Cart cart : cartList) {
3 //更新cart购物车表
4 cartMapper.deleteByPrimaryKey(cart.getId());
5 }
6 }
View Code
2.获取购物车中已经选中的商品信息
service层实现:
根据userId从购物车表中,将当前用户选中的商品拿出来,由cartList记录。根据cartList,由getCartOrderItem()得到订单详情orderItemList,从订单详情orderItemList中计算订单总价。最后将订单详情、订单总价等组装成对应的vo对象返回给前端。
1 public ServerResponse getOrderCartProduct(Integer userId) {
2 OrderProductVo orderProductVo = new OrderProductVo();
3 //从购物车中获取数据
4 //根据userId,从购物车表中,将当前用户选中的商品拿出来
5 List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
6 //根据选中的商品list,得到订单详情
7 ServerResponse serverResponse = this.getCartOrderItem(userId,cartList);
8 if(!serverResponse.isSuccess()){
9 return serverResponse;
10 }
11 List<OrderItem> orderItemList =( List<OrderItem> ) serverResponse.getData();
12
13 List<OrderItemVo> orderItemVoList = Lists.newArrayList();
14 //从订单详情list中,计算订单总价
15 BigDecimal payment = new BigDecimal("0");
16 for(OrderItem orderItem : orderItemList){
17 //计算订单总价
18 payment = BigDecimalUtil.add(payment.doubleValue(),orderItem.getTotalPrice().doubleValue());
19 //将订单详情,组装成订单详情vo对象,放在voList中
20 orderItemVoList.add(assembleOrderItemVo(orderItem));
21 }
22 //将订单总价放在orderProductVo中
23 orderProductVo.setProductTotalPrice(payment);
24 //将订单详情voList放在orderProductVo中
25 orderProductVo.setOrderItemVoList(orderItemVoList);
26 //将图片服务器地址放在orderProductVo中
27 orderProductVo.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));
28 //将orderProductVo返回
29 return ServerResponse.createBySuccess(orderProductVo);
30 }
View Code
3.订单列表
4.订单详情
5.取消订单
controller层实现:
传入userId,orderNo参数,通过service层实现:
1 @RequestMapping("cancel.do")
2 @ResponseBody
3 public ServerResponse cancel(HttpServletRequest request , Long orderNo) {
4 // User user = (User)session.getAttribute(Const.CURRENT_USER);
5
6 String loginToken = CookieUtil.readLoginToken(request);
7 if(StringUtils.isEmpty(loginToken)) {
8 return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
9 }
10 String userJsonStr = RedisShardedPoolUtil.get(loginToken);
11 User user = JsonUtil.string2Obj(userJsonStr, User.class);
12
13 if(user ==null){
14 return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),ResponseCode.NEED_LOGIN.getDesc());
15 }
16 return iOrderService.cancel(user.getId(), orderNo);
17 }
View Code
service层实现:
通过userId,orderNo查到对应的订单,如果订单状态是未付款,则置订单状态为CANCELED,更行到数据库即可。
1 public ServerResponse<String> cancel(Integer userId, Long orderNo) {
2 //根据userId和orderNo拿到订单
3 Order order = orderMapper.selectByUserIdAndOrderNo(userId, orderNo);
4 if(order == null) {
5 return ServerResponse.createByErrorMessage("该用户此订单不存在");
6 }
7 //判断订单状态
8 if(order.getStatus() != Const.OrderStatusEnum.NO_PAY.getCode()) {
9 return ServerResponse.createByErrorMessage("已付款,无法取消订单");
10 }
11 Order updateOrder = new Order();
12 updateOrder.setId(order.getId());
13 //更新订单状态
14 updateOrder.setStatus(Const.OrderStatusEnum.CANCELED.getCode());
15 //将更新状态更新到数据库中
16 int row = orderMapper.updateByPrimaryKeySelective(updateOrder);
17 if(row > 0) {
18 return ServerResponse.createBySuccess();
19 }
20 return ServerResponse.createByError();
21 }
View Code
后台功能:
1.订单列表
2.订单搜索
3.订单详情
4.订单发货
学习目标:
1.设计实用、安全、扩展性强大的常量、枚举类
2.订单号生成规则、订单严谨性判断
3.POJO和VO之间的实际操练
4.mybatis批量插入