订单服务-提交订单业务&立即购买业务

订单服务-提交订单业务&立即购买业务订单服务 提交订单业务 amp 立即购买业务

大家好,欢迎来到IT知识分享网。

在这里插入图片描述

1、提交订单 业务

在这里插入图片描述

2、在 OrderController 创建 submitOrder 方法

@RestController
@Tag(name = "订单管理模块", description = "订单管理模块")
@RequestMapping("/api/order/orderInfo")
public class OrderController { 
     
    @Operation(summary = "提交订单")
    @PostMapping("/auth/submitOrder")
    public Result submitOrder(@RequestBody OrderSubmitDto orderSubmitDto) { 
     
        Long orderId = orderService.submitOrder(orderSubmitDto);
        return Result.ok(orderId);
    }
}

3、 在 OrderServiceImpl 中实现 submitOrder 方法

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService { 
     
    @Resource
    private CartClient cartClient;
    @Resource
    private ProductClient productClient;
    @Resource
    private UserClient userClient;
    @Resource
    private OrderItemService orderItemService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long submitOrder(OrderSubmitDto orderSubmitDto) { 
     
        //1、幂等性保证:用户订单确认页提交的相同的请求只处理一次
        //获取前端提交的token
        List<OrderItem> orderItemList = orderSubmitDto.getOrderItemList();
        if (CollectionUtils.isEmpty(orderItemList)) { 
     
            //没有订单项
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
        Long token = orderItemList.get(0).getOrderId();
        //获取redis缓存的token,如果存在删除

        Boolean delete = stringRedisTemplate.delete("spzx:order:" + token.toString());
        if (!delete) { 
     
            //幂等性保证:用户订单确认页提交的相同的请求只处理一次
            throw new SpzxException(ResultCodeEnum.ORDER_SUBMIT_REPEAT,null);
        }

        //2、保证订单中商品价格正确、库存足够

        //远程调用:service-product 验证前端提交的每个orderItem的价格 和skuId对应的商品当前价格是否一样 和库存是否足够
        orderItemList.forEach(orderItem -> { 
     
            Result<ProductSku> skuResult = productClient.getById(orderItem.getSkuId());
            if (skuResult.getCode() != 200) { 
     
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            ProductSku sku = skuResult.getData();
            if (sku.getSalePrice().compareTo(orderItem.getSkuPrice()) != 0) { 
     
                //价格不一致
                throw new SpzxException(ResultCodeEnum.ORDER_ITEM_PRICE_ERROR,null);
            }
            if (sku.getStockNum() < orderItem.getSkuNum()) { 
     
                //库存不足
                throw new SpzxException(ResultCodeEnum.ORDER_ITEM_STOCK_ERROR,null);
            }
        });
        Result<UserAddress> userAddressResult = userClient.findUserAddressById(orderSubmitDto.getUserAddressId());
        if (userAddressResult.getCode() != 200) { 
     
            //用户收件人地址信息查询失败
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
        //3、创建订单持久化
        OrderInfo orderInfo = new OrderInfo();

        UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();
        orderInfo.setUserId(userInfo.getId());

        orderInfo.setNickName(userInfo.getNickName());

        //订单号:展示给用户的唯一订单编号
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        orderInfo.setOrderNo(orderNo);

        orderInfo.setCouponId(0L);

        //计算订单总金额,并返回总金额
        BigDecimal totalAmount = orderItemList.stream().map(orderItem -> { 
     
            return orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum()));
        }).reduce(BigDecimal::add).get();
        orderInfo.setTotalAmount(totalAmount);

        orderInfo.setCouponAmount(new BigDecimal("0"));

        orderInfo.setOriginalTotalAmount(totalAmount);

        orderInfo.setFreightFee(orderSubmitDto.getFreightFee());
        //orderInfo.setPayType(0);
        orderInfo.setOrderStatus(0);
        //收件人信息
        UserAddress userAddress = userAddressResult.getData();
        orderInfo.setReceiverName(userAddress.getName());
        orderInfo.setReceiverPhone(userAddress.getPhone());
        orderInfo.setReceiverTagName(userAddress.getTagName());
        orderInfo.setReceiverProvince(userAddress.getProvinceCode());
        orderInfo.setReceiverCity(userAddress.getCityCode());
        orderInfo.setReceiverDistrict(userAddress.getDistrictCode());
        orderInfo.setReceiverAddress(userAddress.getAddress());

        orderInfo.setPaymentTime(new Date());
        orderInfo.setDeliveryTime(new Date());
        orderInfo.setReceiveTime(new Date());
        orderInfo.setCancelTime(new Date());
        orderInfo.setCancelReason("");
        orderInfo.setRemark(orderSubmitDto.getRemark());

        this.save(orderInfo);
        Long orderId = orderInfo.getId();


        //4、保存订单的所有的订单项列表
        //订单项关联订单 id 保存
        orderItemList.forEach(orderItem -> { 
     
            orderItem.setOrderId(orderId);
        });
        orderItemService.saveBatch(orderItemList);

        //5、删除购物车中已创建订单的购物项
        //远程调用:service-cart 删除当前用户选中的购物项
        cartClient.delCheckedCartInfos();

        //异步:购物车清空无需阻塞订单创建的业务 解耦合:订单创建业务不需要耦合购物车的操作
        //order服务是生产者发送消息
        //cart服务是消费者消费消息:根据userId获取他的购物车 再删除选中的购物项
        //发送订单创建成功的消息到kafka中:购物车需要userId 如果还有其他的业务需要使用订单创建成功的消息,也可以携带其他的数据
        //userId 幂等性校验使用订单id order信息
        /*HashMap<String, Object> params = new HashMap<>(); params.put("userId",userInfo.getId()); params.put("orderId", orderId); params.put("totalAmount", orderInfo.getTotalAmount()); params.put("type", "1");//type表示订单的类型 1、创建订单 2、取消订单 3、更新订单状态 //将对象转为json字符串 String json = JSON.toJSONString(params); kafkaTemplate.send(SpzxConst.SPZX_ORDER_TOPIC, json);*/

        /*Map<String,Object> params = new HashMap<String,Object>(); params.put("userId" , userInfo.getId()); params.put("orderId" , orderId); params.put("totalAmount" , orderInfo.getTotalAmount()); params.put("type","1");//type表示订单操作的类型 1创建订单 2取消订单 3更新订单状态 //将对象转为json字符串 String paramsJson = JSON.toJSONString(params); kafkaTemplate.send(SpzxConst.SPZX_ORDER_TOPIC ,paramsJson );*/


        //6、返回订单id
        return orderId;
    }
}

4、根据id查询sku详情(service-product”)

@RestController
@Tag(name = "商品模块")
@RequestMapping(value = "/api/product")
public class ProductController { 
     
    @Operation(summary = "根据id查询sku商品详情")
    @GetMapping("getById/{skuId}")
    public Result getById(@PathVariable("skuId") Long skuId) { 
     
        ProductSku productSku = productSkuService.getById(skuId);
        return Result.ok(productSku);
    }
}

@FeignClient(value = "service-product")
public interface ProductClient { 
     
    //因为远程调用时data存的是 sku对象
    @GetMapping("/api/product/getById/{skuId}")
    public Result<ProductSku> getById(@PathVariable("skuId") Long skuId);

    @PutMapping("/api/product/updateSkuSaleAndStock/{skuId}/{skuNum}")
    public Result updateSkuSaleAndStock(@PathVariable Long skuId, @PathVariable Integer skuNum);
}

5、查询用户地址保存到订单项中(service-user)

@RestController
@Tag(name = "用户地址管理模块", description = "用户地址管理模块")
@RequestMapping("/api/user/userAddress")
public class UserAddressController { 
     
    @Operation(summary = "获取地址信息")
    @GetMapping("/getUserAddress/{id}")
    public Result findUserAddressById(@PathVariable("id") Long id) { 
     
        UserAddress userAddress = userAddressService.getById(id);
        return Result.ok(userAddress);
    }
}

@FeignClient(value = "service-user")
public interface UserClient { 
     
    @Operation(summary = "获取地址信息")
    @GetMapping("/api/user/userAddress/getUserAddress/{id}")
    public Result<UserAddress> findUserAddressById(@PathVariable("id") Long id);
}

6、删除购物车选中的购物项接口(service-cart)

@RestController
@RequestMapping("/api/order/cart")
@Tag(name = "购物车模块")
public class CartController { 
     

    @Resource
    private CartService cartService;
    @Operation(summary = "删除购物车选中购物项")
    @DeleteMapping("/auth/delCheckedCartInfos")
    public Result delCheckedCartInfos()
    { 
     
        cartService.deleteCheckedCartInfos();
        return Result.ok();
    }
}

@FeignClient(value = "service-cart")
public interface CartClient { 
     

    @GetMapping("/api/order/cart/auth/checkedCartInfos")
    public Result<List<CartInfo>> checkedCartInfos();

    @DeleteMapping("/api/order/cart/auth/delCheckedCartInfos")
    public Result<Void> delCheckedCartInfos();
}

7、验价验库存

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService { 
     
    public Long submitOrder(OrderSubmitDto orderSubmitDto) { 
     
        List<OrderItem> orderItemList = orderSubmitDto.getOrderItemList();
        if (CollectionUtils.isEmpty(orderItemList)) { 
     
            //没有订单项
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
    	//2、保证订单中商品价格正确、库存足够
        //远程调用:service-product 验证前端提交的每个orderItem的价格 和skuId对应的商品当前价格是否一样 和库存是否足够
        orderItemList.forEach(orderItem -> { 
     
            Result<ProductSku> skuResult = productClient.getById(orderItem.getSkuId());
            if (skuResult.getCode() != 200) { 
     
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            ProductSku sku = skuResult.getData();
            if (sku.getSalePrice().compareTo(orderItem.getSkuPrice()) != 0) { 
     
                //价格不一致
                throw new SpzxException(ResultCodeEnum.ORDER_ITEM_PRICE_ERROR,null);
            }
            if (sku.getStockNum() < orderItem.getSkuNum()) { 
     
                //库存不足
                throw new SpzxException(ResultCodeEnum.ORDER_ITEM_STOCK_ERROR,null);
            }
        });
    }
}

8、创建订单持久化到mysql

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService { 
     

    public Long submitOrder(OrderSubmitDto orderSubmitDto) { 
     
   		 Result<UserAddress> userAddressResult = userClient.findUserAddressById(orderSubmitDto.getUserAddressId());
        if (userAddressResult.getCode() != 200) { 
     
            //用户收件人地址信息查询失败
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
        //3、创建订单持久化
        OrderInfo orderInfo = new OrderInfo();

        UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();
        orderInfo.setUserId(userInfo.getId());

        orderInfo.setNickName(userInfo.getNickName());

        //订单号:展示给用户的唯一订单编号
        String orderNo = IdUtil.getSnowflake(1, 1).nextIdStr();
        orderInfo.setOrderNo(orderNo);

        orderInfo.setCouponId(0L);

        //计算订单总金额,并返回总金额
        BigDecimal totalAmount = orderItemList.stream().map(orderItem -> { 
     
            return orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum()));
        }).reduce(BigDecimal::add).get();
        orderInfo.setTotalAmount(totalAmount);

        orderInfo.setCouponAmount(new BigDecimal("0"));

        orderInfo.setOriginalTotalAmount(totalAmount);

        orderInfo.setFreightFee(orderSubmitDto.getFreightFee());
        //orderInfo.setPayType(0);
        orderInfo.setOrderStatus(0);
        //收件人信息
        UserAddress userAddress = userAddressResult.getData();
        orderInfo.setReceiverName(userAddress.getName());
        orderInfo.setReceiverPhone(userAddress.getPhone());
        orderInfo.setReceiverTagName(userAddress.getTagName());
        orderInfo.setReceiverProvince(userAddress.getProvinceCode());
        orderInfo.setReceiverCity(userAddress.getCityCode());
        orderInfo.setReceiverDistrict(userAddress.getDistrictCode());
        orderInfo.setReceiverAddress(userAddress.getAddress());

        orderInfo.setPaymentTime(new Date());
        orderInfo.setDeliveryTime(new Date());
        orderInfo.setReceiveTime(new Date());
        orderInfo.setCancelTime(new Date());
        orderInfo.setCancelReason("");
        orderInfo.setRemark(orderSubmitDto.getRemark());

        this.save(orderInfo);
        Long orderId = orderInfo.getId();


        //4、保存订单的所有的订单项列表
        //订单项关联订单 id 保存
        orderItemList.forEach(orderItem -> { 
     
            orderItem.setOrderId(orderId);
        });
        orderItemService.saveBatch(orderItemList);
}

9、清空选中的购物车

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService { 
     

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long submitOrder(OrderSubmitDto orderSubmitDto) { 
     
    	//5、删除购物车中已创建订单的购物项
        //远程调用:service-cart 删除当前用户选中的购物项
        cartClient.delCheckedCartInfos();
    }

}

2、立即购买,不经过购物车

在这里插入图片描述

2.1、在 OrderController 创建 buy方法

@RestController
@Tag(name = "订单管理模块", description = "订单管理模块")
@RequestMapping("/api/order/orderInfo")
public class OrderController { 
     

    @Operation(summary = "立即购买:商品详情页立即购买按钮")
    @GetMapping("/auth/buy/{skuId}")
    public Result buy(@PathVariable("skuId") Long skuId) { 
     
        TradeVo tradeVo = orderService.buy(skuId);
        return Result.ok(tradeVo);
    }
}

2.2、在 OrderServiceImpl 中实现 buy 方法

    @Override
    public TradeVo buy(Long skuId) { 
     
        Result<ProductSku> skuResult = productClient.getById(skuId);
        if (skuResult.getCode() != 200) { 
     
            //商品信息查询失败
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
        ProductSku sku = skuResult.getData();
        Long token = IdUtil.getSnowflake(1,1).nextId();
        //将token存到redis:redis的大key问题
        stringRedisTemplate.opsForValue().set("spzx:order:"+token.toString(), "1",  30, TimeUnit.MINUTES);
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(token);
        orderItem.setSkuNum(1);
        orderItem.setSkuPrice(sku.getSalePrice());
        orderItem.setThumbImg(sku.getThumbImg());
        orderItem.setSkuId(skuId);
        orderItem.setSkuName(sku.getSkuName());

        TradeVo tradeVo = new TradeVo();
        tradeVo.setTotalAmount(orderItem.getSkuPrice());
        tradeVo.setOrderItemList(List.of(orderItem));
        return tradeVo;
    }

3、订单幂等性校验分析

幂等性如何保证:相同的请求多次提交如果处理的结果一致
解决思路:和防止表单重复提交一样

在这里插入图片描述


免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/130206.html

(0)
上一篇 2025-08-18 19:20
下一篇 2025-08-18 19:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信