文章目录 1、提交订单 业务 2、在 OrderController 创建 submitOrder 方法 3、 在 OrderServiceImpl 中实现 submitOrder 方法 4、根据id查询sku详情(service-product") 5、查询用户地址保存到订单项中(service-user) 6、删除购物车选中的购物项接口(service-cart) 7、验价验库存 8、创建订单持久化到mysql 9、清空选中的购物车 2、立即购买,不经过购物车 2.1、在 OrderController 创建 buy方法 2.2、在 OrderServiceImpl 中实现 buy 方法 3、订单幂等性校验分析
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) { List < OrderItem > orderItemList = orderSubmitDto. getOrderItemList ( ) ; if ( CollectionUtils . isEmpty ( orderItemList) ) { throw new SpzxException ( ResultCodeEnum . FAIL , null ) ; } Long token = orderItemList. get ( 0 ) . getOrderId ( ) ; Boolean delete = stringRedisTemplate. delete ( "spzx:order:" + token. toString ( ) ) ; if ( ! delete) { throw new SpzxException ( ResultCodeEnum . ORDER_SUBMIT_REPEAT , null ) ; } 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 ) ; } 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. 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 ( ) ; orderItemList. forEach ( orderItem -> { orderItem. setOrderId ( orderId) ; } ) ; orderItemService. saveBatch ( orderItemList) ; cartClient. delCheckedCartInfos ( ) ; 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 { @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 { @Resourceprivate 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 ) ; } 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 ) ; } 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. 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 ( ) ; 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) { 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 ( ) ; 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、订单幂等性校验分析
幂等性如何保证:相同的请求多次提交如果处理的结果一致
解决思路:和防止表单重复提交一样