refactor: Seata实验室案例调整为Seata官网购买商品示例

This commit is contained in:
haoxr 2022-11-29 23:33:37 +08:00
parent fdfcd93b4b
commit 43ee28ac8a
23 changed files with 359 additions and 225 deletions

View File

@ -2,8 +2,8 @@ package com.youlai.laboratory.seata.controller;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.laboratory.seata.pojo.form.SeataForm; import com.youlai.laboratory.seata.pojo.form.SeataForm;
import com.youlai.laboratory.seata.pojo.vo.SeataDataVO; import com.youlai.laboratory.seata.pojo.vo.SeataVO;
import com.youlai.laboratory.seata.service.ISeataService; import com.youlai.laboratory.seata.service.SeataService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -22,26 +22,12 @@ import org.springframework.web.bind.annotation.*;
@Slf4j @Slf4j
public class SeataController { public class SeataController {
private final ISeataService seataService; private final SeataService 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);
}
@ApiOperation("获取模拟数据") @ApiOperation("获取模拟数据")
@GetMapping("/data") @GetMapping("/data")
public Result getData() { public Result getData() {
SeataDataVO result = seataService.getData(); SeataVO result = seataService.getData();
return Result.success(result); return Result.success(result);
} }
@ -52,4 +38,19 @@ public class SeataController {
return Result.success(result); 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);
}
} }

View File

@ -3,12 +3,28 @@ package com.youlai.laboratory.seata.pojo.form;
import lombok.Data; import lombok.Data;
/** /**
*
*
* @author haoxr * @author haoxr
* @date 2022/4/21 23:16 * @date 2022/4/21 23:16
*/ */
@Data @Data
public class SeataForm { 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 openTx;
/** /**
* 订单异常 * 是否开启异常
*/ */
private boolean orderEx; private boolean openEx;
} }

View File

@ -12,7 +12,7 @@ import lombok.Data;
*/ */
@ApiModel("Seata模拟数据视图对象") @ApiModel("Seata模拟数据视图对象")
@Data @Data
public class SeataDataVO { public class SeataVO {
@ApiModelProperty("商品库存信息") @ApiModelProperty("商品库存信息")
private StockInfo stockInfo; private StockInfo stockInfo;

View File

@ -1,35 +1,20 @@
package com.youlai.laboratory.seata.service; package com.youlai.laboratory.seata.service;
import com.youlai.laboratory.seata.pojo.form.SeataForm; 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 * @author haoxr
* @date 2022/4/16 20:49 * @date 2022/4/16 20:49
*/ */
public interface ISeataService { public interface SeataService {
/**
* 模拟订单支付
*
* @return
*/
boolean payOrder(SeataForm seataForm);
/**
* 模拟订单支付(分布式事务)
*
* @param seataForm
* @return
*/
boolean payOrderWithGlobalTx(SeataForm seataForm);
/** /**
* 获取模拟数据 * 获取模拟数据
* *
* @return * @return
*/ */
SeataDataVO getData(); SeataVO getData();
/** /**
* 重置模拟数据 * 重置模拟数据
@ -37,4 +22,18 @@ public interface ISeataService {
* @return * @return
*/ */
boolean resetData(); boolean resetData();
/**
* 购买商品
*
* @return 订单号
*/
String purchaseGoods(SeataForm seataForm);
/**
* 购买商品(全局事务)
*
* @return 订单号
*/
String purchaseGoodsWithGlobalTx(SeataForm seataForm);
} }

View File

@ -1,11 +1,13 @@
package com.youlai.laboratory.seata.service.impl; package com.youlai.laboratory.seata.service.impl;
import cn.hutool.core.bean.BeanUtil; 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.form.SeataForm;
import com.youlai.laboratory.seata.pojo.vo.SeataDataVO; import com.youlai.laboratory.seata.pojo.vo.SeataVO;
import com.youlai.laboratory.seata.service.ISeataService; import com.youlai.laboratory.seata.service.SeataService;
import com.youlai.mall.oms.api.OrderFeignClient; import com.youlai.mall.oms.api.OrderFeignClient;
import com.youlai.mall.oms.dto.OrderInfoDTO; 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.api.SkuFeignClient;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO; import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.ums.api.MemberFeignClient; import com.youlai.mall.ums.api.MemberFeignClient;
@ -24,7 +26,7 @@ import org.springframework.stereotype.Service;
@Service @Service
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class SeataServiceImpl implements ISeataService { public class SeataServiceImpl implements SeataService {
private final SkuFeignClient skuFeignClient; private final SkuFeignClient skuFeignClient;
private final OrderFeignClient orderFeignClient; private final OrderFeignClient orderFeignClient;
@ -66,12 +68,14 @@ public class SeataServiceImpl implements ISeataService {
log.info("========扣减商品库存(Seata)========"); log.info("========扣减商品库存(Seata)========");
skuFeignClient.deductStock(skuId, 1); // 扣减库存 skuFeignClient.deductStock(skuId, 1); // 扣减库存
log.info("========扣减账户余额(Seata)========"); log.info("========修改订单状态(Seata)========");
memberFeignClient.deductBalance(memberId, 1000 * 100l); // 扣款1000 orderFeignClient.createOrder(orderId, 201, seataForm.isOrderEx()); // 已支付
log.info("========修改订单状态(Seata)========"); log.info("========修改订单状态(Seata)========");
orderFeignClient.updateOrderStatus(orderId, 201, seataForm.isOrderEx()); // 已支付 orderFeignClient.updateOrderStatus(orderId, 201, seataForm.isOrderEx()); // 已支付
log.info("========扣减账户余额(Seata)========");
memberFeignClient.deductBalance(memberId, 1000 * 100l); // 扣款1000
return true; return true;
} }
@ -81,26 +85,26 @@ public class SeataServiceImpl implements ISeataService {
* @return * @return
*/ */
@Override @Override
public SeataDataVO getData() { public SeataVO getData() {
SeataDataVO seataDataVO = new SeataDataVO(); SeataVO seataVO = new SeataVO();
SkuInfoDTO skuInfoDTO = skuFeignClient.getSkuInfo(skuId).getData(); SkuInfoDTO skuInfoDTO = skuFeignClient.getSkuInfo(skuId).getData();
SeataDataVO.StockInfo stockInfo = new SeataDataVO.StockInfo(); SeataVO.StockInfo stockInfo = new SeataVO.StockInfo();
BeanUtil.copyProperties(skuInfoDTO, stockInfo); BeanUtil.copyProperties(skuInfoDTO, stockInfo);
stockInfo.setName(skuInfoDTO.getSkuName()); stockInfo.setName(skuInfoDTO.getSkuName());
seataDataVO.setStockInfo(stockInfo); seataVO.setStockInfo(stockInfo);
MemberInfoDTO memberInfoDTO = memberFeignClient.getMemberInfo(memberId).getData(); MemberInfoDTO memberInfoDTO = memberFeignClient.getMemberInfo(memberId).getData();
SeataDataVO.AccountInfo accountInfo = new SeataDataVO.AccountInfo(); SeataVO.AccountInfo accountInfo = new SeataVO.AccountInfo();
BeanUtil.copyProperties(memberInfoDTO, accountInfo); BeanUtil.copyProperties(memberInfoDTO, accountInfo);
seataDataVO.setAccountInfo(accountInfo); seataVO.setAccountInfo(accountInfo);
OrderInfoDTO orderInfoDTO = orderFeignClient.getOrderInfo(orderId).getData(); OrderInfoDTO orderInfoDTO = orderFeignClient.getOrderInfo(orderId).getData();
SeataDataVO.OrderInfo orderInfo = new SeataDataVO.OrderInfo(); SeataVO.OrderInfo orderInfo = new SeataVO.OrderInfo();
BeanUtil.copyProperties(orderInfoDTO, 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 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<String> 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<String> result = orderFeignClient.createOrder(seataOrderDTO, openEx);
String orderSn = result.getData();
return orderSn;
}
} }

View File

@ -2,11 +2,9 @@ package com.youlai.mall.oms.api;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.mall.oms.dto.OrderInfoDTO; import com.youlai.mall.oms.dto.OrderInfoDTO;
import com.youlai.mall.oms.dto.SeataOrderDTO;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
/** /**
* 订单Feign客户端 * 订单Feign客户端
@ -38,4 +36,13 @@ public interface OrderFeignClient {
@GetMapping("/api/v1/orders/{orderId}/info") @GetMapping("/api/v1/orders/{orderId}/info")
Result<OrderInfoDTO> getOrderInfo(@PathVariable Long orderId); Result<OrderInfoDTO> getOrderInfo(@PathVariable Long orderId);
/**
* 实验室创建订单
*
* @param orderDTO
* @param openEx 是否出现异常
* @return
*/
@PostMapping("/api/v1/orders")
Result<String> createOrder(SeataOrderDTO orderDTO, boolean openEx);
} }

View File

@ -3,10 +3,10 @@ package com.youlai.mall.oms.dto;
import lombok.Data; import lombok.Data;
/** /**
* 订单信息传输层对象 * 订单传输层对象
* *
* @author <a href="mailto:xianrui0365@163.com">haoxr</a> * @author haoxr
* @date 2022/4/17 21:12 * @date 2022/4/17
*/ */
@Data @Data
public class OrderInfoDTO { public class OrderInfoDTO {

View File

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

View File

@ -11,17 +11,17 @@ import lombok.Getter;
*/ */
@AllArgsConstructor @AllArgsConstructor
public enum OrderTypeEnum { public enum OrderSourceTypeEnum {
WEB(0), // PC订单 PC(0), // PC订单
APP(1), // APP订单 APP(1), // APP订单
; ;
@Getter @Getter
private Integer code; private Integer code;
public static OrderTypeEnum getValue(Integer code){ public static OrderSourceTypeEnum getValue(Integer code){
for (OrderTypeEnum value : values()) { for (OrderSourceTypeEnum value : values()) {
if (value.getCode().equals(code)) { if (value.getCode().equals(code)) {
return value; return value;
} }

View File

@ -1,46 +1,56 @@
package com.youlai.mall.oms.enums; package com.youlai.mall.oms.enums;
import lombok.AllArgsConstructor; import com.youlai.common.base.IBaseEnum;
import lombok.Getter; import lombok.Getter;
/** /**
* @author huawei * 订单状态枚举
* @desc *
* @email huawei_code@163.com * @author haoxr
* @date 2021/1/16 * @date 2022/11/28
*/ */
@AllArgsConstructor public enum OrderStatusEnum implements IBaseEnum<Integer> {
public enum OrderStatusEnum {
PENDING_PAYMENT(101, "待支付"), /**
USER_CANCEL(102, "用户取消"), * 1. 订单创建阶段
AUTO_CANCEL(103, "系统自动取消"), */
PENDING_PAYMENT(10, "待支付"),
USER_CANCEL(11, "用户取消"),
AUTO_CANCEL(12, "系统自动取消"),
PAYED(201, "已支付"), /**
APPLY_REFUND(202, "申请退款"), * 2. 订单付款阶段
REFUNDED(203, "已退款"), */
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, "已完成"); /**
* 订单完结
*/
COMPLETED(99, "已完成");
OrderStatusEnum(int value, String label) {
this.value = value;
this.label = label;
}
@Getter @Getter
private Integer code; private Integer value;
@Getter @Getter
private String text; private String label;
public static OrderStatusEnum getValue(Integer code) {
for (OrderStatusEnum value : values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}
} }

View File

@ -48,22 +48,7 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- 分布式事务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.youlai</groupId> <groupId>com.youlai</groupId>
@ -104,6 +89,12 @@
<groupId>com.github.binarywang</groupId> <groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId> <artifactId>weixin-java-pay</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-seata</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.common.result.PageResult; import com.youlai.common.result.PageResult;
import com.youlai.common.result.Result; import com.youlai.common.result.Result;
import com.youlai.mall.oms.dto.OrderInfoDTO; 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.dto.OrderDTO;
import com.youlai.mall.oms.pojo.entity.OmsOrder; import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.entity.OmsOrderItem; import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
@ -24,7 +25,7 @@ import java.util.Optional;
/** /**
* @author huawei * @author huawei
* @email huawei_code@163.com * @email huawei_code@163.com
* @date 2020-12-30 22:31:10 * @date 2020/12/30
*/ */
@Api(tags = "「管理端」订单管理") @Api(tags = "「管理端」订单管理")
@RestController @RestController
@ -62,11 +63,11 @@ public class OmsOrderController {
return Result.success(orderDTO); return Result.success(orderDTO);
} }
@ApiOperation(value = "修改订单状态", notes = "实验室模拟接口", hidden = true) @ApiOperation(value = "「实验室」创建订单", notes = "实验室模拟接口", hidden = true)
@PutMapping("/{orderId}/status") @PostMapping
public Result updateOrderStatus(@PathVariable Long orderId, @RequestParam Integer status,@RequestParam Boolean orderEx) { public Result<String> createOrder(@RequestBody SeataOrderDTO orderDTO, @RequestParam Boolean openEx) {
boolean result = orderService.updateOrderStatus(orderId, status,orderEx); String orderSn = orderService.createOrder(orderDTO, openEx);
return Result.judge(result); return Result.success(orderSn);
} }
@ApiOperation(value = "获取订单信息", notes = "实验室模拟接口", hidden = true) @ApiOperation(value = "获取订单信息", notes = "实验室模拟接口", hidden = true)

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader; import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import com.youlai.mall.oms.dto.OrderInfoDTO; 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.enums.PayTypeEnum;
import com.youlai.mall.oms.pojo.entity.OmsOrder; import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.query.OrderPageQuery; import com.youlai.mall.oms.pojo.query.OrderPageQuery;
@ -36,7 +37,7 @@ public interface IOrderService extends IService<OmsOrder> {
/** /**
* 订单提交 * 订单提交
*/ */
OrderSubmitVO submitOrder(OrderSubmitForm orderSubmitForm) ; OrderSubmitVO submitOrder(OrderSubmitForm orderSubmitForm);
/** /**
* 订单支付 * 订单支付
@ -84,18 +85,22 @@ public interface IOrderService extends IService<OmsOrder> {
*/ */
IPage<OmsOrder> listOrderPages(OrderPageQuery queryParams); IPage<OmsOrder> listOrderPages(OrderPageQuery queryParams);
/**
* 修改订单状态
*
* @param orderId 订单ID
* @param status 订单状态
* @param orderEx 订单是否异常
* @return
*/
boolean updateOrderStatus(Long orderId, Integer status,Boolean orderEx);
/** /**
* 获取订单信息 * 实验室创建订单
* <p>
* 非商城业务
*
* @param orderDTO
* @param openEx
* @return
*/
String createOrder(SeataOrderDTO orderDTO, Boolean openEx);
/**
* 实验室获取订单信息
* <p>
* 非商城业务
* *
* @param orderId * @param orderId
* @return * @return

View File

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

View File

@ -58,10 +58,10 @@ public interface SkuFeignClient {
* 实验室扣减商品库存 * 实验室扣减商品库存
* *
* @param skuId * @param skuId
* @param num 扣减数量 * @param count 扣减数量
* @return * @return
*/ */
@PutMapping("/api/v1/sku/{skuId}/stock/_deduct") @PutMapping("/api/v1/sku/{skuId}/stock/_deduct")
Result deductStock(@PathVariable Long skuId, @RequestParam Integer num); Result deductStock(@PathVariable Long skuId, @RequestParam Integer count);
} }

View File

@ -11,6 +11,12 @@ import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
/**
* 会员Feign客户端
*
* @author haoxr
* @date 2022/11/29
*/
@FeignClient(name = "mall-ums", contextId = "member") @FeignClient(name = "mall-ums", contextId = "member")
public interface MemberFeignClient { public interface MemberFeignClient {
@ -61,7 +67,6 @@ public interface MemberFeignClient {
@GetMapping("/app-api/v1/members/mobile/{mobile}") @GetMapping("/app-api/v1/members/mobile/{mobile}")
Result<MemberAuthDTO> loadUserByMobile(@PathVariable String mobile); Result<MemberAuthDTO> loadUserByMobile(@PathVariable String mobile);
/** /**
* 获取会员地址列表 * 获取会员地址列表
* *
@ -71,16 +76,6 @@ public interface MemberFeignClient {
@GetMapping("/app-api/v1/members/{memberId}/addresses") @GetMapping("/app-api/v1/members/{memberId}/addresses")
Result<List<MemberAddressDTO>> listMemberAddresses(@PathVariable Long memberId); Result<List<MemberAddressDTO>> listMemberAddresses(@PathVariable Long memberId);
/**
* 实验室修改会员余额
*
* @param memberId
* @param balance 余额(单位:)
* @return
*/
@PutMapping("/api/v1/members/{memberId}/balance")
Result updateBalance(@PathVariable Long memberId, @RequestParam Integer balance);
/** /**
* 实验室扣减会员余额 * 实验室扣减会员余额
* *

View File

@ -81,17 +81,6 @@ public class UmsMemberController {
return Result.judge(status); 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) @ApiOperation(value = "扣减会员余额", notes = "实验室模拟", hidden = true)
@PutMapping(value = "/{memberId}/balance/_deduct") @PutMapping(value = "/{memberId}/balance/_deduct")
public Result deductBalance( public Result deductBalance(

View File

@ -276,6 +276,12 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-seata</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.whvcse</groupId> <groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId> <artifactId>easy-captcha</artifactId>

View File

@ -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<Integer> {
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;
}
}

View File

@ -1,7 +1,6 @@
package com.youlai.common.redis; package com.youlai.common.redis;
import com.youlai.common.constant.RedisConstants; import com.youlai.common.constant.RedisConstants;
import com.youlai.common.enums.BusinessTypeEnum;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@ -14,26 +13,24 @@ import java.time.format.DateTimeFormatter;
@Component @Component
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class BusinessNoGenerator { public class BusinessSnGenerator {
private final RedisTemplate redisTemplate; private final RedisTemplate redisTemplate;
/** /**
* @param businessType 业务类型枚举
* @param digit 业务序号位数 * @param digit 业务序号位数
* @return * @return
*/ */
public String generate(BusinessTypeEnum businessType, Integer digit) { public String generateSerialNo(Integer digit) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String date = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter); 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); 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) { public String generateSerialNo(){
Integer defaultDigit = 6; return this.generateSerialNo(6);
return generate(businessType, defaultDigit);
} }
} }

View File

@ -1,6 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.youlai.common.redis.RedisConfig,\ com.youlai.common.redis.RedisConfig,\
com.youlai.common.redis.BusinessNoGenerator,\ com.youlai.common.redis.BusinessSnGenerator,\
com.youlai.common.redis.RedissonConfig,\ com.youlai.common.redis.RedissonConfig,\
com.youlai.common.redis.RedisCacheConfig com.youlai.common.redis.RedisCacheConfig

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>youlai-common</artifactId>
<groupId>com.youlai</groupId>
<version>2.1.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-seata</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -24,5 +24,6 @@
<module>common-sms</module> <module>common-sms</module>
<module>common-file</module> <module>common-file</module>
<module>common-security</module> <module>common-security</module>
<module>common-seata</module>
</modules> </modules>
</project> </project>