当前位置:   article > 正文

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

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


在这里插入图片描述

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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

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);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

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();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3、订单幂等性校验分析

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

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/837880
推荐阅读
相关标签
  

闽ICP备14008679号