From 43ee28ac8a4340368299511ca54874d833be6141 Mon Sep 17 00:00:00 2001 From: haoxr <1490493387@qq.com> Date: Tue, 29 Nov 2022 23:33:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20Seata=E5=AE=9E=E9=AA=8C=E5=AE=A4?= =?UTF-8?q?=E6=A1=88=E4=BE=8B=E8=B0=83=E6=95=B4=E4=B8=BASeata=E5=AE=98?= =?UTF-8?q?=E7=BD=91=E8=B4=AD=E4=B9=B0=E5=95=86=E5=93=81=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seata/controller/SeataController.java | 37 +++---- .../laboratory/seata/pojo/form/SeataForm.java | 20 +++- .../vo/{SeataDataVO.java => SeataVO.java} | 2 +- .../{ISeataService.java => SeataService.java} | 35 ++++--- .../seata/service/impl/SeataServiceImpl.java | 80 ++++++++++++--- .../youlai/mall/oms/api/OrderFeignClient.java | 15 ++- .../com/youlai/mall/oms/dto/OrderInfoDTO.java | 6 +- .../youlai/mall/oms/dto/SeataOrderDTO.java | 28 ++++++ ...TypeEnum.java => OrderSourceTypeEnum.java} | 8 +- .../mall/oms/enums/OrderStatusEnum.java | 70 +++++++------ mall-oms/oms-boot/pom.xml | 23 ++--- .../controller/admin/OmsOrderController.java | 13 +-- .../mall/oms/service/IOrderService.java | 27 ++--- .../oms/service/impl/OrderServiceImpl.java | 99 ++++++++++++------- .../youlai/mall/pms/api/SkuFeignClient.java | 4 +- .../mall/ums/api/MemberFeignClient.java | 17 ++-- .../controller/admin/UmsMemberController.java | 11 --- pom.xml | 6 ++ .../youlai/common/enums/BusinessTypeEnum.java | 28 ------ ...enerator.java => BusinessSnGenerator.java} | 15 ++- .../main/resources/META-INF/spring.factories | 2 +- youlai-common/common-seata/pom.xml | 37 +++++++ youlai-common/pom.xml | 1 + 23 files changed, 359 insertions(+), 225 deletions(-) rename laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/{SeataDataVO.java => SeataVO.java} (98%) rename laboratory/src/main/java/com/youlai/laboratory/seata/service/{ISeataService.java => SeataService.java} (51%) create mode 100644 mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/SeataOrderDTO.java rename mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/{OrderTypeEnum.java => OrderSourceTypeEnum.java} (71%) delete mode 100644 youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java rename youlai-common/common-redis/src/main/java/com/youlai/common/redis/{BusinessNoGenerator.java => BusinessSnGenerator.java} (59%) create mode 100644 youlai-common/common-seata/pom.xml diff --git a/laboratory/src/main/java/com/youlai/laboratory/seata/controller/SeataController.java b/laboratory/src/main/java/com/youlai/laboratory/seata/controller/SeataController.java index 73b08d49b..9f2f41ed8 100644 --- a/laboratory/src/main/java/com/youlai/laboratory/seata/controller/SeataController.java +++ b/laboratory/src/main/java/com/youlai/laboratory/seata/controller/SeataController.java @@ -2,8 +2,8 @@ package com.youlai.laboratory.seata.controller; import com.youlai.common.result.Result; import com.youlai.laboratory.seata.pojo.form.SeataForm; -import com.youlai.laboratory.seata.pojo.vo.SeataDataVO; -import com.youlai.laboratory.seata.service.ISeataService; +import com.youlai.laboratory.seata.pojo.vo.SeataVO; +import com.youlai.laboratory.seata.service.SeataService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; @@ -22,26 +22,12 @@ import org.springframework.web.bind.annotation.*; @Slf4j public class SeataController { - private final ISeataService seataService; - - @ApiOperation("订单支付") - @PostMapping("/order/_pay") - public Result payOrder(@RequestBody SeataForm seataForm) { - - boolean openTx = seataForm.isOpenTx(); - boolean result; - if (openTx) { - result = seataService.payOrderWithGlobalTx(seataForm); - } else { - result = seataService.payOrder(seataForm); - } - return Result.success(result); - } + private final SeataService seataService; @ApiOperation("获取模拟数据") @GetMapping("/data") public Result getData() { - SeataDataVO result = seataService.getData(); + SeataVO result = seataService.getData(); return Result.success(result); } @@ -52,4 +38,19 @@ public class SeataController { return Result.success(result); } + @ApiOperation("购买商品") + @PostMapping("/purchaseGoods") + public Result purchaseGoods(@RequestBody SeataForm seataForm) { + boolean openTx = seataForm.isOpenTx(); + + String orderSn = null; + if (openTx) { + // 开启全局事务 + orderSn = seataService.purchaseGoodsWithGlobalTx(seataForm); + } else { + orderSn = seataService.purchaseGoods(seataForm); + } + + return Result.success(orderSn); + } } diff --git a/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/form/SeataForm.java b/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/form/SeataForm.java index d53a1fe14..91220479d 100644 --- a/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/form/SeataForm.java +++ b/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/form/SeataForm.java @@ -3,12 +3,28 @@ package com.youlai.laboratory.seata.pojo.form; import lombok.Data; /** + * + * * @author haoxr * @date 2022/4/21 23:16 */ @Data public class SeataForm { + /** + * 会员ID + */ + private Long memberId; + + /** + * 商品ID + */ + private Long skuId; + + /** + * 订单金额 + */ + private Long amount; /** * 是否开启事务 @@ -16,9 +32,9 @@ public class SeataForm { private boolean openTx; /** - * 订单异常 + * 是否开启异常 */ - private boolean orderEx; + private boolean openEx; } diff --git a/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataDataVO.java b/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataVO.java similarity index 98% rename from laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataDataVO.java rename to laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataVO.java index bb6dc3a1f..2112511d8 100644 --- a/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataDataVO.java +++ b/laboratory/src/main/java/com/youlai/laboratory/seata/pojo/vo/SeataVO.java @@ -12,7 +12,7 @@ import lombok.Data; */ @ApiModel("Seata模拟数据视图对象") @Data -public class SeataDataVO { +public class SeataVO { @ApiModelProperty("商品库存信息") private StockInfo stockInfo; diff --git a/laboratory/src/main/java/com/youlai/laboratory/seata/service/ISeataService.java b/laboratory/src/main/java/com/youlai/laboratory/seata/service/SeataService.java similarity index 51% rename from laboratory/src/main/java/com/youlai/laboratory/seata/service/ISeataService.java rename to laboratory/src/main/java/com/youlai/laboratory/seata/service/SeataService.java index 3634f752c..f087bda65 100644 --- a/laboratory/src/main/java/com/youlai/laboratory/seata/service/ISeataService.java +++ b/laboratory/src/main/java/com/youlai/laboratory/seata/service/SeataService.java @@ -1,35 +1,20 @@ package com.youlai.laboratory.seata.service; import com.youlai.laboratory.seata.pojo.form.SeataForm; -import com.youlai.laboratory.seata.pojo.vo.SeataDataVO; +import com.youlai.laboratory.seata.pojo.vo.SeataVO; /** * @author haoxr * @date 2022/4/16 20:49 */ -public interface ISeataService { - - /** - * 模拟订单支付 - * - * @return - */ - boolean payOrder(SeataForm seataForm); - - /** - * 模拟订单支付(分布式事务) - * - * @param seataForm - * @return - */ - boolean payOrderWithGlobalTx(SeataForm seataForm); +public interface SeataService { /** * 获取模拟数据 * * @return */ - SeataDataVO getData(); + SeataVO getData(); /** * 重置模拟数据 @@ -37,4 +22,18 @@ public interface ISeataService { * @return */ boolean resetData(); + + /** + * 购买商品 + * + * @return 订单号 + */ + String purchaseGoods(SeataForm seataForm); + + /** + * 购买商品(全局事务) + * + * @return 订单号 + */ + String purchaseGoodsWithGlobalTx(SeataForm seataForm); } diff --git a/laboratory/src/main/java/com/youlai/laboratory/seata/service/impl/SeataServiceImpl.java b/laboratory/src/main/java/com/youlai/laboratory/seata/service/impl/SeataServiceImpl.java index d2789dc1c..8e78e2686 100644 --- a/laboratory/src/main/java/com/youlai/laboratory/seata/service/impl/SeataServiceImpl.java +++ b/laboratory/src/main/java/com/youlai/laboratory/seata/service/impl/SeataServiceImpl.java @@ -1,11 +1,13 @@ package com.youlai.laboratory.seata.service.impl; import cn.hutool.core.bean.BeanUtil; +import com.youlai.common.result.Result; import com.youlai.laboratory.seata.pojo.form.SeataForm; -import com.youlai.laboratory.seata.pojo.vo.SeataDataVO; -import com.youlai.laboratory.seata.service.ISeataService; +import com.youlai.laboratory.seata.pojo.vo.SeataVO; +import com.youlai.laboratory.seata.service.SeataService; import com.youlai.mall.oms.api.OrderFeignClient; import com.youlai.mall.oms.dto.OrderInfoDTO; +import com.youlai.mall.oms.dto.SeataOrderDTO; import com.youlai.mall.pms.api.SkuFeignClient; import com.youlai.mall.pms.pojo.dto.SkuInfoDTO; import com.youlai.mall.ums.api.MemberFeignClient; @@ -24,7 +26,7 @@ import org.springframework.stereotype.Service; @Service @Slf4j @RequiredArgsConstructor -public class SeataServiceImpl implements ISeataService { +public class SeataServiceImpl implements SeataService { private final SkuFeignClient skuFeignClient; private final OrderFeignClient orderFeignClient; @@ -66,12 +68,14 @@ public class SeataServiceImpl implements ISeataService { log.info("========扣减商品库存(Seata)========"); skuFeignClient.deductStock(skuId, 1); // 扣减库存 - log.info("========扣减账户余额(Seata)========"); - memberFeignClient.deductBalance(memberId, 1000 * 100l); // 扣款1000 + log.info("========修改订单状态(Seata)========"); + orderFeignClient.createOrder(orderId, 201, seataForm.isOrderEx()); // 已支付 log.info("========修改订单状态(Seata)========"); orderFeignClient.updateOrderStatus(orderId, 201, seataForm.isOrderEx()); // 已支付 + log.info("========扣减账户余额(Seata)========"); + memberFeignClient.deductBalance(memberId, 1000 * 100l); // 扣款1000 return true; } @@ -81,26 +85,26 @@ public class SeataServiceImpl implements ISeataService { * @return */ @Override - public SeataDataVO getData() { - SeataDataVO seataDataVO = new SeataDataVO(); + public SeataVO getData() { + SeataVO seataVO = new SeataVO(); SkuInfoDTO skuInfoDTO = skuFeignClient.getSkuInfo(skuId).getData(); - SeataDataVO.StockInfo stockInfo = new SeataDataVO.StockInfo(); + SeataVO.StockInfo stockInfo = new SeataVO.StockInfo(); BeanUtil.copyProperties(skuInfoDTO, stockInfo); stockInfo.setName(skuInfoDTO.getSkuName()); - seataDataVO.setStockInfo(stockInfo); + seataVO.setStockInfo(stockInfo); MemberInfoDTO memberInfoDTO = memberFeignClient.getMemberInfo(memberId).getData(); - SeataDataVO.AccountInfo accountInfo = new SeataDataVO.AccountInfo(); + SeataVO.AccountInfo accountInfo = new SeataVO.AccountInfo(); BeanUtil.copyProperties(memberInfoDTO, accountInfo); - seataDataVO.setAccountInfo(accountInfo); + seataVO.setAccountInfo(accountInfo); OrderInfoDTO orderInfoDTO = orderFeignClient.getOrderInfo(orderId).getData(); - SeataDataVO.OrderInfo orderInfo = new SeataDataVO.OrderInfo(); + SeataVO.OrderInfo orderInfo = new SeataVO.OrderInfo(); BeanUtil.copyProperties(orderInfoDTO, orderInfo); - seataDataVO.setOrderInfo(orderInfo); + seataVO.setOrderInfo(orderInfo); - return seataDataVO; + return seataVO; } /** @@ -116,4 +120,52 @@ public class SeataServiceImpl implements ISeataService { return true; } + + /** + * 购买商品 + * + * @return 订单号 + */ + @Override + public String purchaseGoods(SeataForm seataForm) { + log.info("========扣减商品库存(全局事务)========"); + skuFeignClient.deductStock(seataForm.getSkuId(), 1); // 扣减库存 + + log.info("========创建订单(全局事务)========"); + SeataOrderDTO seataOrderDTO = new SeataOrderDTO( + seataForm.getMemberId(), + seataForm.getSkuId(), + seataForm.getAmount() + ); + boolean openEx = seataForm.isOpenEx(); // 是否开启异常 + Result result = orderFeignClient.createOrder(seataOrderDTO, openEx); + String orderSn = result.getData(); + + return orderSn; + } + + /** + * 购买商品(全局事务) + * + * @return 订单号 + */ + @GlobalTransactional + @Override + public String purchaseGoodsWithGlobalTx(SeataForm seataForm) { + + log.info("========扣减商品库存(全局事务)========"); + skuFeignClient.deductStock(seataForm.getSkuId(), 1); // 扣减库存 + + log.info("========创建订单(全局事务)========"); + SeataOrderDTO seataOrderDTO = new SeataOrderDTO( + seataForm.getMemberId(), + seataForm.getSkuId(), + seataForm.getAmount() + ); + boolean openEx = seataForm.isOpenEx(); // 是否开启异常 + Result result = orderFeignClient.createOrder(seataOrderDTO, openEx); + String orderSn = result.getData(); + + return orderSn; + } } diff --git a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/api/OrderFeignClient.java b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/api/OrderFeignClient.java index 4620e958e..dad4bd133 100644 --- a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/api/OrderFeignClient.java +++ b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/api/OrderFeignClient.java @@ -2,11 +2,9 @@ package com.youlai.mall.oms.api; import com.youlai.common.result.Result; import com.youlai.mall.oms.dto.OrderInfoDTO; +import com.youlai.mall.oms.dto.SeataOrderDTO; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; /** * 订单Feign客户端 @@ -38,4 +36,13 @@ public interface OrderFeignClient { @GetMapping("/api/v1/orders/{orderId}/info") Result getOrderInfo(@PathVariable Long orderId); + /** + * 「实验室」创建订单 + * + * @param orderDTO + * @param openEx 是否出现异常 + * @return + */ + @PostMapping("/api/v1/orders") + Result createOrder(SeataOrderDTO orderDTO, boolean openEx); } diff --git a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/OrderInfoDTO.java b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/OrderInfoDTO.java index 3ad8f03aa..4c887b93f 100644 --- a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/OrderInfoDTO.java +++ b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/OrderInfoDTO.java @@ -3,10 +3,10 @@ package com.youlai.mall.oms.dto; import lombok.Data; /** - * 订单信息传输层对象 + * 订单传输层对象 * - * @author haoxr - * @date 2022/4/17 21:12 + * @author haoxr + * @date 2022/4/17 */ @Data public class OrderInfoDTO { diff --git a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/SeataOrderDTO.java b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/SeataOrderDTO.java new file mode 100644 index 000000000..f0721c1d5 --- /dev/null +++ b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/dto/SeataOrderDTO.java @@ -0,0 +1,28 @@ +package com.youlai.mall.oms.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SeataOrderDTO { + + /** + * 会员ID + */ + private Long memberId; + + /** + * 商品ID + */ + private Long skuId; + + /** + * 订单金额 + */ + private Long amount; + + +} diff --git a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderTypeEnum.java b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderSourceTypeEnum.java similarity index 71% rename from mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderTypeEnum.java rename to mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderSourceTypeEnum.java index abb3435f8..de6f24f42 100644 --- a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderTypeEnum.java +++ b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderSourceTypeEnum.java @@ -11,17 +11,17 @@ import lombok.Getter; */ @AllArgsConstructor -public enum OrderTypeEnum { +public enum OrderSourceTypeEnum { - WEB(0), // PC订单 + PC(0), // PC订单 APP(1), // APP订单 ; @Getter private Integer code; - public static OrderTypeEnum getValue(Integer code){ - for (OrderTypeEnum value : values()) { + public static OrderSourceTypeEnum getValue(Integer code){ + for (OrderSourceTypeEnum value : values()) { if (value.getCode().equals(code)) { return value; } diff --git a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderStatusEnum.java b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderStatusEnum.java index 1fb7ccdca..802b7ee5e 100644 --- a/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderStatusEnum.java +++ b/mall-oms/oms-api/src/main/java/com/youlai/mall/oms/enums/OrderStatusEnum.java @@ -1,46 +1,56 @@ package com.youlai.mall.oms.enums; -import lombok.AllArgsConstructor; +import com.youlai.common.base.IBaseEnum; import lombok.Getter; /** - * @author huawei - * @desc - * @email huawei_code@163.com - * @date 2021/1/16 + * 订单状态枚举 + * + * @author haoxr + * @date 2022/11/28 */ -@AllArgsConstructor -public enum OrderStatusEnum { +public enum OrderStatusEnum implements IBaseEnum { - PENDING_PAYMENT(101, "待支付"), - USER_CANCEL(102, "用户取消"), - AUTO_CANCEL(103, "系统自动取消"), + /** + * 1. 订单创建阶段 + */ + PENDING_PAYMENT(10, "待支付"), + USER_CANCEL(11, "用户取消"), + AUTO_CANCEL(12, "系统自动取消"), - PAYED(201, "已支付"), - APPLY_REFUND(202, "申请退款"), - REFUNDED(203, "已退款"), + /** + * 2. 订单付款阶段 + */ + PAYED(20, "已支付"), + APPLY_REFUND(21, "申请退款"), + REFUNDED(22, "已退款"), - DELIVERED(301, "已发货"), + /** + * 订单发货阶段 + */ + DELIVERED(30, "已发货"), - USER_RECEIVE(401, "用户收货"), - AUTO_RECEIVE(402, "系统自动收货"), + /** + * 订单收货阶段 + */ + USER_RECEIVE(40, "用户收货"), + AUTO_RECEIVE(41, "系统自动收货"), - FINISHED(901, "已完成"); - - @Getter - private Integer code; - - @Getter - private String text; + /** + * 订单完结 + */ + COMPLETED(99, "已完成"); - public static OrderStatusEnum getValue(Integer code) { - for (OrderStatusEnum value : values()) { - if (value.getCode().equals(code)) { - return value; - } - } - return null; + OrderStatusEnum(int value, String label) { + this.value = value; + this.label = label; } + @Getter + private Integer value; + + @Getter + private String label; + } diff --git a/mall-oms/oms-boot/pom.xml b/mall-oms/oms-boot/pom.xml index 26f2c0f5e..b0afbd807 100644 --- a/mall-oms/oms-boot/pom.xml +++ b/mall-oms/oms-boot/pom.xml @@ -48,22 +48,7 @@ test - - - com.alibaba.cloud - spring-cloud-starter-alibaba-seata - - - io.seata - seata-spring-boot-starter - - - - - io.seata - seata-spring-boot-starter - ${seata.version} - + com.youlai @@ -104,6 +89,12 @@ com.github.binarywang weixin-java-pay + + + com.youlai + common-seata + + diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/controller/admin/OmsOrderController.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/controller/admin/OmsOrderController.java index 5f18f7269..e1f390d8d 100644 --- a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/controller/admin/OmsOrderController.java +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/controller/admin/OmsOrderController.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.youlai.common.result.PageResult; import com.youlai.common.result.Result; import com.youlai.mall.oms.dto.OrderInfoDTO; +import com.youlai.mall.oms.dto.SeataOrderDTO; import com.youlai.mall.oms.pojo.dto.OrderDTO; import com.youlai.mall.oms.pojo.entity.OmsOrder; import com.youlai.mall.oms.pojo.entity.OmsOrderItem; @@ -24,7 +25,7 @@ import java.util.Optional; /** * @author huawei * @email huawei_code@163.com - * @date 2020-12-30 22:31:10 + * @date 2020/12/30 */ @Api(tags = "「管理端」订单管理") @RestController @@ -62,11 +63,11 @@ public class OmsOrderController { return Result.success(orderDTO); } - @ApiOperation(value = "修改订单状态", notes = "实验室模拟接口", hidden = true) - @PutMapping("/{orderId}/status") - public Result updateOrderStatus(@PathVariable Long orderId, @RequestParam Integer status,@RequestParam Boolean orderEx) { - boolean result = orderService.updateOrderStatus(orderId, status,orderEx); - return Result.judge(result); + @ApiOperation(value = "「实验室」创建订单", notes = "实验室模拟接口", hidden = true) + @PostMapping + public Result createOrder(@RequestBody SeataOrderDTO orderDTO, @RequestParam Boolean openEx) { + String orderSn = orderService.createOrder(orderDTO, openEx); + return Result.success(orderSn); } @ApiOperation(value = "获取订单信息", notes = "实验室模拟接口", hidden = true) diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java index 0f165144b..63e811223 100644 --- a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.github.binarywang.wxpay.bean.notify.SignatureHeader; import com.github.binarywang.wxpay.exception.WxPayException; import com.youlai.mall.oms.dto.OrderInfoDTO; +import com.youlai.mall.oms.dto.SeataOrderDTO; import com.youlai.mall.oms.enums.PayTypeEnum; import com.youlai.mall.oms.pojo.entity.OmsOrder; import com.youlai.mall.oms.pojo.query.OrderPageQuery; @@ -36,7 +37,7 @@ public interface IOrderService extends IService { /** * 订单提交 */ - OrderSubmitVO submitOrder(OrderSubmitForm orderSubmitForm) ; + OrderSubmitVO submitOrder(OrderSubmitForm orderSubmitForm); /** * 订单支付 @@ -84,18 +85,22 @@ public interface IOrderService extends IService { */ IPage listOrderPages(OrderPageQuery queryParams); - /** - * 修改订单状态 - * - * @param orderId 订单ID - * @param status 订单状态 - * @param orderEx 订单是否异常 - * @return - */ - boolean updateOrderStatus(Long orderId, Integer status,Boolean orderEx); /** - * 获取订单信息 + * 「实验室」创建订单 + *

+ * 非商城业务 + * + * @param orderDTO + * @param openEx + * @return + */ + String createOrder(SeataOrderDTO orderDTO, Boolean openEx); + + /** + * 「实验室」获取订单信息 + *

+ * 非商城业务 * * @param orderId * @return diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java index 1b164aed7..763e87388 100644 --- a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java @@ -8,7 +8,6 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -21,15 +20,15 @@ import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; -import com.youlai.common.enums.BusinessTypeEnum; -import com.youlai.common.redis.BusinessNoGenerator; +import com.youlai.common.redis.BusinessSnGenerator; import com.youlai.common.result.Result; import com.youlai.common.security.util.SecurityUtils; import com.youlai.common.web.exception.ApiException; import com.youlai.mall.oms.config.WxPayProperties; import com.youlai.mall.oms.dto.OrderInfoDTO; +import com.youlai.mall.oms.dto.SeataOrderDTO; import com.youlai.mall.oms.enums.OrderStatusEnum; -import com.youlai.mall.oms.enums.OrderTypeEnum; +import com.youlai.mall.oms.enums.OrderSourceTypeEnum; import com.youlai.mall.oms.enums.PayTypeEnum; import com.youlai.mall.oms.mapper.OrderMapper; import com.youlai.mall.oms.pojo.dto.CartItemDTO; @@ -58,7 +57,6 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @@ -78,9 +76,9 @@ import static com.youlai.mall.oms.constant.OmsConstants.*; * @author haoxr * @date 2022/2/12 */ -@RequiredArgsConstructor -@Slf4j @Service +@Slf4j +@RequiredArgsConstructor public class OrderServiceImpl extends ServiceImpl implements IOrderService { private final WxPayProperties wxPayProperties; @@ -90,7 +88,7 @@ public class OrderServiceImpl extends ServiceImpl impleme private final StringRedisTemplate redisTemplate; private final ThreadPoolExecutor threadPoolExecutor; private final MemberFeignClient memberFeignClient; - private final BusinessNoGenerator businessNoGenerator; + private final BusinessSnGenerator businessSnGenerator; private final SkuFeignClient skuFeignClient; private final RedissonClient redissonClient; private final WxPayService wxPayService; @@ -128,7 +126,7 @@ public class OrderServiceImpl extends ServiceImpl impleme CompletableFuture getOrderItemsFuture = CompletableFuture.runAsync(() -> { // 请求参数传递给子线程 RequestContextHolder.setRequestAttributes(attributes); - List orderItems = this.getOrderItems(skuId,memberId); + List orderItems = this.getOrderItems(skuId, memberId); orderConfirmVO.setOrderItems(orderItems); }, threadPoolExecutor); @@ -147,7 +145,7 @@ public class OrderServiceImpl extends ServiceImpl impleme // 进入订单确认页面生成唯一token,订单提交根据此token判断是否重复提交 CompletableFuture getOrderTokenFuture = CompletableFuture.runAsync(() -> { RequestContextHolder.setRequestAttributes(attributes); - String orderToken = businessNoGenerator.generate(BusinessTypeEnum.ORDER); + String orderToken = businessSnGenerator.generateSerialNo(); orderConfirmVO.setOrderToken(orderToken); redisTemplate.opsForValue().set(ORDER_TOKEN_PREFIX + orderToken, orderToken); }, threadPoolExecutor); @@ -186,7 +184,15 @@ public class OrderServiceImpl extends ServiceImpl impleme // 创建订单 order = new OmsOrder().setOrderSn(orderToken) // 把orderToken赋值给订单编号 - .setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode()).setSourceType(OrderTypeEnum.APP.getCode()).setMemberId(SecurityUtils.getMemberId()).setRemark(orderSubmitForm.getRemark()).setPayAmount(orderSubmitForm.getPayAmount()).setTotalQuantity(orderItems.stream().map(OrderItemDTO::getCount).reduce(0, Integer::sum)).setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()).reduce(0L, Long::sum)); + .setStatus(OrderStatusEnum.PENDING_PAYMENT.getValue()) + .setSourceType(OrderSourceTypeEnum.APP.getCode()) + .setMemberId(SecurityUtils.getMemberId()) + .setRemark(orderSubmitForm.getRemark()) + .setPayAmount(orderSubmitForm.getPayAmount()) + .setTotalQuantity(orderItems.stream() + .map(OrderItemDTO::getCount).reduce(0, Integer::sum)) + .setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()) + .reduce(0L, Long::sum)); boolean result = this.save(order); // 添加订单明细 @@ -225,7 +231,7 @@ public class OrderServiceImpl extends ServiceImpl impleme public T pay(Long orderId, String appId, PayTypeEnum payTypeEnum) { OmsOrder order = this.getById(orderId); Assert.isTrue(order != null, "订单不存在"); - Assert.isTrue(OrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus()), "订单不可支付,请检查订单状态"); + Assert.isTrue(OrderStatusEnum.PENDING_PAYMENT.getValue().equals(order.getStatus()), "订单不可支付,请检查订单状态"); RLock lock = redissonClient.getLock(ORDER_SN_PREFIX + order.getOrderSn()); try { @@ -266,7 +272,7 @@ public class OrderServiceImpl extends ServiceImpl impleme Assert.isTrue(Result.isSuccess(deductBalanceResult), "扣减账户余额失败"); // 更新订单状态 - order.setStatus(OrderStatusEnum.PAYED.getCode()); + order.setStatus(OrderStatusEnum.PAYED.getValue()); order.setPayType(PayTypeEnum.BALANCE.getValue()); order.setPayTime(new Date()); this.updateById(order); @@ -318,7 +324,7 @@ public class OrderServiceImpl extends ServiceImpl impleme public boolean closeOrder(String orderToken) { log.info("订单超时取消,orderToken:{}", orderToken); OmsOrder order = this.getOne(new LambdaQueryWrapper().eq(OmsOrder::getOrderSn, orderToken)); - if (order == null || !OrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) { + if (order == null || !OrderStatusEnum.PENDING_PAYMENT.getValue().equals(order.getStatus())) { return false; } // 如果已经有outTradeNo了就先进行关单 @@ -331,7 +337,7 @@ public class OrderServiceImpl extends ServiceImpl impleme throw new ApiException("微信关单异常"); } } - order.setStatus(OrderStatusEnum.AUTO_CANCEL.getCode()); + order.setStatus(OrderStatusEnum.AUTO_CANCEL.getValue()); return this.updateById(order); } @@ -343,7 +349,7 @@ public class OrderServiceImpl extends ServiceImpl impleme throw new ApiException("订单不存在"); } - if (!OrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) { + if (!OrderStatusEnum.PENDING_PAYMENT.getValue().equals(order.getStatus())) { throw new ApiException("取消失败,订单状态不支持取消"); // 通过自定义异常,将异常信息抛出由异常处理器捕获显示给前端页面 } // 如果已经有outTradeNo了就先进行关单 @@ -356,7 +362,7 @@ public class OrderServiceImpl extends ServiceImpl impleme throw new ApiException("微信关单异常"); } } - order.setStatus(OrderStatusEnum.USER_CANCEL.getCode()); + order.setStatus(OrderStatusEnum.USER_CANCEL.getValue()); boolean result = this.updateById(order); if (result) { // 释放被锁定的库存 @@ -369,11 +375,11 @@ public class OrderServiceImpl extends ServiceImpl impleme } @Override - @Transactional(rollbackFor = Exception.class) public boolean deleteOrder(Long id) { log.info("=======================订单删除,订单ID:{}=======================", id); OmsOrder order = this.getById(id); - if (order != null && !OrderStatusEnum.AUTO_CANCEL.getCode().equals(order.getStatus()) && !OrderStatusEnum.USER_CANCEL.getCode().equals(order.getStatus())) { + if (order != null && !OrderStatusEnum.AUTO_CANCEL.getValue().equals(order.getStatus()) + && !OrderStatusEnum.USER_CANCEL.getValue().equals(order.getStatus())) { throw new ApiException("订单删除失败,订单不存在或订单状态不支持删除"); } return this.removeById(id); @@ -387,12 +393,12 @@ public class OrderServiceImpl extends ServiceImpl impleme final WxPayOrderNotifyV3Result.DecryptNotifyResult result = this.wxPayService.parseOrderNotifyV3Result(notifyData, signatureHeader).getResult(); log.debug("支付通知解密成功:[{}]", result.toString()); // 根据商户订单号查询订单 - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(OmsOrder::getOutTradeNo, result.getOutTradeNo()); - OmsOrder orderDO = this.getOne(wrapper); + OmsOrder orderDO = this.getOne(new LambdaQueryWrapper() + .eq(OmsOrder::getOutTradeNo, result.getOutTradeNo()) + ); // 支付成功处理 if (WxPayConstants.WxpayTradeStatus.SUCCESS.equals(result.getTradeState())) { - orderDO.setStatus(OrderStatusEnum.PAYED.getCode()); + orderDO.setStatus(OrderStatusEnum.PAYED.getValue()); orderDO.setTransactionId(result.getTransactionId()); orderDO.setPayTime(new Date()); this.updateById(orderDO); @@ -414,7 +420,7 @@ public class OrderServiceImpl extends ServiceImpl impleme OmsOrder orderDO = this.getOne(wrapper); // 退款成功处理 if (WxPayConstants.RefundStatus.SUCCESS.equals(result.getRefundStatus())) { - orderDO.setStatus(OrderStatusEnum.REFUNDED.getCode()); + orderDO.setStatus(OrderStatusEnum.REFUNDED.getValue()); orderDO.setRefundId(result.getRefundId()); this.updateById(orderDO); } @@ -455,7 +461,7 @@ public class OrderServiceImpl extends ServiceImpl impleme * @param skuId 直接购买必有值,购物车结算必没值 * @return */ - private List getOrderItems(Long skuId,Long memberId) { + private List getOrderItems(Long skuId, Long memberId) { List orderItems; if (skuId != null) { // 直接购买 orderItems = new ArrayList<>(); @@ -486,7 +492,12 @@ public class OrderServiceImpl extends ServiceImpl impleme LockStockDTO lockStockDTO = new LockStockDTO(); lockStockDTO.setOrderToken(orderToken); - List lockedSkuList = orderItems.stream().map(orderItem -> new LockStockDTO.LockedSku().setSkuId(orderItem.getSkuId()).setCount(orderItem.getCount())).collect(Collectors.toList()); + List lockedSkuList = orderItems.stream() + .map(orderItem -> new LockStockDTO + .LockedSku() + .setSkuId(orderItem.getSkuId()) + .setCount(orderItem.getCount())) + .collect(Collectors.toList()); lockStockDTO.setLockedSkuList(lockedSkuList); skuFeignClient.lockStock(lockStockDTO); @@ -494,26 +505,42 @@ public class OrderServiceImpl extends ServiceImpl impleme /** - * 「实验室」修改订单状态 + * 「实验室」创建订单 + *

+ * 非商城业务 * - * @param orderId 订单ID - * @param status 订单状态 - * @param orderEx 订单是否异常 + * @param orderDTO + * @param openEx * @return */ @Override - @Transactional - public boolean updateOrderStatus(Long orderId, Integer status, Boolean orderEx) { - boolean result = this.update(new LambdaUpdateWrapper().eq(OmsOrder::getId, orderId).set(OmsOrder::getStatus, status)); + public String createOrder(SeataOrderDTO orderDTO, Boolean openEx) { - if (orderEx) { + // 扣减账户越 + Long memberId = orderDTO.getMemberId(); + Long amount = orderDTO.getAmount(); + memberFeignClient.deductBalance(memberId, amount); + + // 生成订单 + String orderSn = businessSnGenerator.generateSerialNo(); + new OmsOrder().setOrderSn(orderSn) + .setStatus(OrderStatusEnum.COMPLETED.getValue()) + .setSourceType(OrderSourceTypeEnum.APP.getCode()) + .setMemberId(memberId) + .setPayAmount(amount) + .setTotalQuantity(1) + .setTotalAmount(amount); + // 开启异常,制造运行时异常 + if (openEx) { int i = 1 / 0; } - return result; + return orderSn; } /** - * 获取订单信息 + * 「实验室」获取订单信息 + *

+ * 非商城业务 * * @param orderId * @return diff --git a/mall-pms/pms-api/src/main/java/com/youlai/mall/pms/api/SkuFeignClient.java b/mall-pms/pms-api/src/main/java/com/youlai/mall/pms/api/SkuFeignClient.java index 848a54dac..fc135956b 100644 --- a/mall-pms/pms-api/src/main/java/com/youlai/mall/pms/api/SkuFeignClient.java +++ b/mall-pms/pms-api/src/main/java/com/youlai/mall/pms/api/SkuFeignClient.java @@ -58,10 +58,10 @@ public interface SkuFeignClient { * 「实验室」扣减商品库存 * * @param skuId - * @param num 扣减数量 + * @param count 扣减数量 * @return */ @PutMapping("/api/v1/sku/{skuId}/stock/_deduct") - Result deductStock(@PathVariable Long skuId, @RequestParam Integer num); + Result deductStock(@PathVariable Long skuId, @RequestParam Integer count); } diff --git a/mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java b/mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java index d954759fd..1030307e1 100644 --- a/mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java +++ b/mall-ums/ums-api/src/main/java/com/youlai/mall/ums/api/MemberFeignClient.java @@ -11,6 +11,12 @@ import org.springframework.web.bind.annotation.*; import java.util.List; +/** + * 会员Feign客户端 + * + * @author haoxr + * @date 2022/11/29 + */ @FeignClient(name = "mall-ums", contextId = "member") public interface MemberFeignClient { @@ -61,7 +67,6 @@ public interface MemberFeignClient { @GetMapping("/app-api/v1/members/mobile/{mobile}") Result loadUserByMobile(@PathVariable String mobile); - /** * 获取会员地址列表 * @@ -71,16 +76,6 @@ public interface MemberFeignClient { @GetMapping("/app-api/v1/members/{memberId}/addresses") Result> listMemberAddresses(@PathVariable Long memberId); - /** - * 「实验室」修改会员余额 - * - * @param memberId - * @param balance 余额(单位:分) - * @return - */ - @PutMapping("/api/v1/members/{memberId}/balance") - Result updateBalance(@PathVariable Long memberId, @RequestParam Integer balance); - /** * 「实验室」扣减会员余额 * diff --git a/mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/admin/UmsMemberController.java b/mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/admin/UmsMemberController.java index 39290f4f7..c8f17ad97 100644 --- a/mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/admin/UmsMemberController.java +++ b/mall-ums/ums-boot/src/main/java/com/youlai/mall/ums/controller/admin/UmsMemberController.java @@ -81,17 +81,6 @@ public class UmsMemberController { return Result.judge(status); } - - @ApiOperation(value = "修改会员余额", notes = "实验室模拟", hidden = true) - @PutMapping(value = "/{memberId}/balance") - public Result updateBalance( - @PathVariable Long memberId, - @RequestParam Long balance - ) { - boolean result = memberService.updateBalance(memberId, balance); - return Result.judge(result); - } - @ApiOperation(value = "扣减会员余额", notes = "实验室模拟", hidden = true) @PutMapping(value = "/{memberId}/balance/_deduct") public Result deductBalance( diff --git a/pom.xml b/pom.xml index b5cb5c978..89667f57d 100644 --- a/pom.xml +++ b/pom.xml @@ -276,6 +276,12 @@ ${project.version} + + com.youlai + common-seata + ${project.version} + + com.github.whvcse easy-captcha diff --git a/youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java b/youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java deleted file mode 100644 index c891be501..000000000 --- a/youlai-common/common-core/src/main/java/com/youlai/common/enums/BusinessTypeEnum.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.youlai.common.enums; - -import com.youlai.common.base.IBaseEnum; -import lombok.Getter; - -/** - * 业务类型枚举 - * - * @author haoxr - * @date 2021-02-17 - */ -public enum BusinessTypeEnum implements IBaseEnum { - - USER(100, "用户"), - MEMBER(200, "会员"), - ORDER(300, "订单"); - - @Getter - private Integer value; - - @Getter - private String label; - - BusinessTypeEnum(Integer value, String label) { - this.value = value; - this.label = label; - } -} diff --git a/youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessNoGenerator.java b/youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessSnGenerator.java similarity index 59% rename from youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessNoGenerator.java rename to youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessSnGenerator.java index 02bebdb3c..2429a512b 100644 --- a/youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessNoGenerator.java +++ b/youlai-common/common-redis/src/main/java/com/youlai/common/redis/BusinessSnGenerator.java @@ -1,7 +1,6 @@ package com.youlai.common.redis; import com.youlai.common.constant.RedisConstants; -import com.youlai.common.enums.BusinessTypeEnum; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; @@ -14,26 +13,24 @@ import java.time.format.DateTimeFormatter; @Component @Slf4j @RequiredArgsConstructor -public class BusinessNoGenerator { +public class BusinessSnGenerator { private final RedisTemplate redisTemplate; /** - * @param businessType 业务类型枚举 * @param digit 业务序号位数 * @return */ - public String generate(BusinessTypeEnum businessType, Integer digit) { + public String generateSerialNo(Integer digit) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); String date = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter); - String key = RedisConstants.BUSINESS_NO_PREFIX + businessType.getValue() + ":" + date; + String key = RedisConstants.BUSINESS_NO_PREFIX +":" + date; Long increment = redisTemplate.opsForValue().increment(key); - return date + businessType.getValue() + String.format("%0" + digit + "d", increment); + return date + String.format("%0" + digit + "d", increment); } - public String generate(BusinessTypeEnum businessType) { - Integer defaultDigit = 6; - return generate(businessType, defaultDigit); + public String generateSerialNo(){ + return this.generateSerialNo(6); } } diff --git a/youlai-common/common-redis/src/main/resources/META-INF/spring.factories b/youlai-common/common-redis/src/main/resources/META-INF/spring.factories index 1545bfe46..20fdfd17e 100644 --- a/youlai-common/common-redis/src/main/resources/META-INF/spring.factories +++ b/youlai-common/common-redis/src/main/resources/META-INF/spring.factories @@ -1,6 +1,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.youlai.common.redis.RedisConfig,\ - com.youlai.common.redis.BusinessNoGenerator,\ + com.youlai.common.redis.BusinessSnGenerator,\ com.youlai.common.redis.RedissonConfig,\ com.youlai.common.redis.RedisCacheConfig diff --git a/youlai-common/common-seata/pom.xml b/youlai-common/common-seata/pom.xml new file mode 100644 index 000000000..98f691329 --- /dev/null +++ b/youlai-common/common-seata/pom.xml @@ -0,0 +1,37 @@ + + + + youlai-common + com.youlai + 2.1.4 + + 4.0.0 + + common-seata + + + 8 + 8 + UTF-8 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-seata + + + io.seata + seata-spring-boot-starter + + + + + io.seata + seata-spring-boot-starter + ${seata.version} + + + \ No newline at end of file diff --git a/youlai-common/pom.xml b/youlai-common/pom.xml index 499081673..23cb2a93e 100644 --- a/youlai-common/pom.xml +++ b/youlai-common/pom.xml @@ -24,5 +24,6 @@ common-sms common-file common-security + common-seata