Browse Source

feat: 更新业务逻辑

master
xc-yjs 7 months ago
parent
commit
25ffbf192b
  1. 40
      nla-common/pom.xml
  2. 22
      nla-common/src/main/java/cn/nla/common/config/RedissonConfig.java
  3. 4
      nla-common/src/main/java/cn/nla/common/constant/CacheKey.java
  4. 10
      nla-common/src/main/java/cn/nla/common/util/JsonData.java
  5. 83
      nla-common/src/test/java/tools/MyBatisPlusGeneratortest.java
  6. 2
      nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java
  7. 11
      nla-coupon-service/src/main/resources/application.yml
  8. 36
      nla-order-service/src/main/java/cn/nla/order/controller/ProductOrderController.java
  9. 21
      nla-order-service/src/main/java/cn/nla/order/feign/CouponFeignService.java
  10. 23
      nla-order-service/src/main/java/cn/nla/order/feign/ProductFeignService.java
  11. 15
      nla-order-service/src/main/java/cn/nla/order/feign/UserFeignService.java
  12. 64
      nla-order-service/src/main/java/cn/nla/order/model/VO/CouponRecordVO.java
  13. 42
      nla-order-service/src/main/java/cn/nla/order/model/VO/OrderItemVO.java
  14. 55
      nla-order-service/src/main/java/cn/nla/order/model/VO/ProductOrderAddressVO.java
  15. 23
      nla-order-service/src/main/java/cn/nla/order/model/request/LockCouponRecordRequest.java
  16. 21
      nla-order-service/src/main/java/cn/nla/order/model/request/LockProductRequest.java
  17. 18
      nla-order-service/src/main/java/cn/nla/order/model/request/OrderItemRequest.java
  18. 2
      nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java
  19. 207
      nla-order-service/src/main/java/cn/nla/order/service/impl/ProductOrderServiceImpl.java
  20. 8
      nla-order-service/src/main/resources/application.yml
  21. 4
      nla-product-service/pom.xml
  22. 6
      nla-product-service/src/main/java/cn/nla/product/config/RabbitMQConfig.java
  23. 13
      nla-product-service/src/main/java/cn/nla/product/controller/CartController.java
  24. 2
      nla-product-service/src/main/java/cn/nla/product/controller/ProductController.java
  25. 3
      nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java
  26. 3
      nla-product-service/src/main/java/cn/nla/product/model/request/OrderItemRequest.java
  27. 6
      nla-product-service/src/main/java/cn/nla/product/mq/ProductStockMQListener.java
  28. 9
      nla-product-service/src/main/java/cn/nla/product/service/CartService.java
  29. 16
      nla-product-service/src/main/java/cn/nla/product/service/impl/CartServiceImpl.java
  30. 46
      nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java
  31. 19
      nla-product-service/src/main/resources/application.yml
  32. 7
      nla-product-service/src/main/resources/mapper/ProductMapper.xml
  33. 30
      nla-product-service/src/test/java/cn/nla/product/ProductApplicationTests.java
  34. 2
      nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java
  35. 4
      nla-user-service/src/main/java/cn/nla/user/service/impl/UserServiceImpl.java
  36. 8
      nla-user-service/src/main/resources/application.yml

40
nla-common/pom.xml

@ -105,26 +105,26 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--alibaba微服务整合分布式事务,上面的方式不行 mvn 包冲突-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!--alibaba微服务整合分布式事务,这个方式才行-->
<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>1.3.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-alibaba-seata</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash;alibaba微服务整合分布式事务,这个方式才行&ndash;&gt;-->
<!-- <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>1.3.0</version>-->
<!-- </dependency>-->
<!--引入AMQP-->
<dependency>
<groupId>org.springframework.boot</groupId>

22
nla-common/src/main/java/cn/nla/common/config/RedissonConfig.java

@ -1,18 +1,25 @@
package cn.nla.common.config;
import feign.RequestInterceptor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* Redisson配置
*/
@Configuration
@Data
@Slf4j
public class RedissonConfig {
@Value("${spring.redis.host}")
private String redisHost;
@ -20,6 +27,7 @@ public class RedissonConfig {
private String redisPort;
@Value("${spring.redis.password}")
private String redisPwd;
/**
* 配置分布式锁的redisson
*/
@ -32,4 +40,18 @@ public class RedissonConfig {
// config.useClusterServers().addNodeAddress("redis://127.0.0.1:6379","redis://127.0.0.2:6379")
return Redisson.create(config);
}
@Bean("requestInterceptor")
public RequestInterceptor requestInterceptor() {
return template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
log.info(request.getHeaderNames().toString());
template.header("token", request.getHeader("token"));
} else {
log.warn("requestInterceptor获取Header空指针异常");
}
};
}
}

4
nla-common/src/main/java/cn/nla/common/constant/CacheKey.java

@ -9,4 +9,8 @@ public class CacheKey {
* 购物车 hash 结果key是用户唯一标识
*/
public static final String CART_KEY = "cart:%s";
/**
* 提交表单的token key
*/
public static final String SUBMIT_ORDER_TOKEN_KEY = "order:submit:%s";
}

10
nla-common/src/main/java/cn/nla/common/util/JsonData.java

@ -1,6 +1,8 @@
package cn.nla.common.util;
import cn.nla.common.enums.BizCodeEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -25,6 +27,14 @@ public class JsonData {
* 描述
*/
private String msg;
/**
* 获取远程调用对象
*/
public <T> T getData(TypeReference<T> typeReference){
return JSON.parseObject(JSON.toJSONString(data),typeReference);
}
/**
* 成功不传入数据
*/

83
nla-common/src/test/java/tools/MyBatisPlusGeneratortest.java

@ -0,0 +1,83 @@
package tools;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
/**
* 代码生成器
*/
public class MyBatisPlusGeneratortest {
public static void main(String[] args) {
//1. 全局配置
GlobalConfig config = new GlobalConfig();
// 是否⽀持AR模式
config.setActiveRecord(true)
// 作者
.setAuthor("YJs")
// ⽣成路径,最好使⽤绝对路径,window路径是不⼀样的
.setOutputDir("D:\\workspace\\2024\\virtual-agent-admin\\src\\main\\java")
// ⽂件覆盖
.setFileOverride(true)
// 主键策略
.setIdType(IdType.AUTO)
.setDateType(DateType.ONLY_DATE)
// 设置⽣成的service接⼝的名字的⾸字⺟是否为I,默认Service是以I开头的
.setServiceName("%sService")
//实体类结尾名称
.setEntityName("%s")
//⽣成基本的resultMap
.setBaseResultMap(true)
//不使⽤AR模式
.setActiveRecord(false)
//⽣成基本的SQL⽚段
.setBaseColumnList(true);
//2. 数据源配置
DataSourceConfig dsConfig = new DataSourceConfig();
// 设置数据库类型
dsConfig.setDbType(DbType.MYSQL)
.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://117.72.43.105:3306/virtual_web_template?useSSL=false")
.setUsername("root")
.setPassword("Yuan625621105.");
//3. 策略配置globalConfiguration中
StrategyConfig stConfig = new StrategyConfig();
//全局⼤写命名
stConfig.setCapitalMode(true)
// 数据库表映射到实体的命名策略
.setNaming(NamingStrategy.underline_to_camel)
//使⽤lombok
.setEntityLombokModel(true)
//使⽤restcontroller注解
.setRestControllerStyle(true)
// ⽣成的表, ⽀持多表⼀起⽣成,以数组形式填写
.setInclude("t_sys_resource","t_sys_role","t_sys_role_resource","t_sys_user","t_sys_user_role");
//4. 包名策略配置
PackageConfig pkConfig = new PackageConfig();
pkConfig.setParent("com.yuanjs.admin")
.setMapper("mapper")
.setService("service")
.setController("controller")
.setEntity("domain")
.setXml("mapper");
//5. 整合配置
AutoGenerator ag = new AutoGenerator();
ag.setGlobalConfig(config)
.setDataSource(dsConfig)
.setStrategy(stConfig)
.setPackageInfo(pkConfig);
//6. 执⾏操作
ag.execute();
System.out.println("======= NLA-Paas MyBatisPlusGenerator相关代码⽣成完毕 ========");
}
}

2
nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java

@ -16,6 +16,7 @@ import cn.nla.coupon.mapper.CouponMapper;
import cn.nla.coupon.model.entity.CouponRecordEntity;
import cn.nla.coupon.model.request.NewUserCouponRequest;
import cn.nla.coupon.service.CouponService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -179,6 +180,7 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, CouponEntity> i
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@Override
public JsonData initNewUserCoupon(NewUserCouponRequest newUserCouponRequest) {
log.info("into {}", JSON.toJSONString(newUserCouponRequest));
LoginUser loginUser = new LoginUser();
loginUser.setId(newUserCouponRequest.getUserId());
loginUser.setName(newUserCouponRequest.getName());

11
nla-coupon-service/src/main/resources/application.yml

@ -72,3 +72,14 @@ mq:
coupon_release_routing_key: coupon.release.routing.key
#消息过期时间,毫秒,临时改为6分钟
ttl: 360000
feign:
client:
config:
default:
# 设置Feign的连接超时时间(秒)
connectTimeout: 5000
# 设置Feign的读取超时时间(秒)
readTimeout: 10000

36
nla-order-service/src/main/java/cn/nla/order/controller/ProductOrderController.java

@ -33,18 +33,18 @@ import java.io.IOException;
public class ProductOrderController {
@Resource
private ProductOrderService orderService;
/**
* 查询订单状态
*
* <p>
* 此接口没有登录拦截可以增加一个秘钥进行rpc通信
*/
@ApiOperation("查询订单状态")
@GetMapping("query_state")
public JsonData queryProductOrderState(@ApiParam("订单号") @RequestParam("out_trade_no")String outTradeNo){
log.info("获取订单查询: {}",outTradeNo);
public JsonData queryProductOrderState(@ApiParam("订单号") @RequestParam("out_trade_no") String outTradeNo) {
log.info("获取订单查询: {}", outTradeNo);
String state = orderService.queryProductOrderState(outTradeNo);
return StringUtils.isBlank(state)?JsonData.buildResult(BizCodeEnum.ORDER_CONFIRM_NOT_EXIST):JsonData.buildSuccess(state);
return StringUtils.isBlank(state) ? JsonData.buildResult(BizCodeEnum.ORDER_CONFIRM_NOT_EXIST) : JsonData.buildSuccess(state);
}
@ApiOperation("提交订单")
@ -52,19 +52,19 @@ public class ProductOrderController {
public void confirmOrder(@ApiParam("订单对象") @RequestBody ConfirmOrderRequest orderRequest, HttpServletResponse response) {
JsonData jsonData = orderService.confirmOrder(orderRequest);
if (jsonData.getCode() == 0) {
String client = orderRequest.getClientType();
String payType = orderRequest.getPayType();
//如果是支付宝网页支付,都是跳转网页,APP除外
if (payType.equalsIgnoreCase(ProductOrderPayTypeEnum.ALIPAY.name())) {
log.info("创建支付宝订单成功:{}", orderRequest.toString());
if (client.equalsIgnoreCase(ClientType.H5.name())) {
writeData(response, jsonData);
} else if (client.equalsIgnoreCase(ClientType.APP.name())) {
//APP SDK支付 TODO
}
} else if (payType.equalsIgnoreCase(ProductOrderPayTypeEnum.WECHAT.name())) {
//微信支付 TODO
}
// String client = orderRequest.getClientType();
// String payType = orderRequest.getPayType();
// //如果是支付宝网页支付,都是跳转网页,APP除外
// if (payType.equalsIgnoreCase(ProductOrderPayTypeEnum.ALIPAY.name())) {
// log.info("创建支付宝订单成功:{}", orderRequest.toString());
// if (client.equalsIgnoreCase(ClientType.H5.name())) {
// writeData(response, jsonData);
// } else if (client.equalsIgnoreCase(ClientType.APP.name())) {
// //APP SDK支付 TODO
// }
// } else if (payType.equalsIgnoreCase(ProductOrderPayTypeEnum.WECHAT.name())) {
// //微信支付 TODO
// }
} else {
log.error("创建订单失败{}", jsonData);
}

21
nla-order-service/src/main/java/cn/nla/order/feign/CouponFeignService.java

@ -0,0 +1,21 @@
package cn.nla.order.feign;
import cn.nla.common.util.JsonData;
import cn.nla.order.model.request.LockCouponRecordRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* Feign调用优惠券服务接口
*/
@FeignClient(name = "nla-coupon-service")
public interface CouponFeignService {
/**
* 领取优惠券
*/
@GetMapping("/cop/coupon/v1/promotion/{coupon_id}")
JsonData findUserCouponRecordById(@PathVariable("record_id") long recordId);
@PostMapping("/cop/coupon/v1/lock_records")
JsonData lockCouponRecords(@RequestBody LockCouponRecordRequest recordRequest);
}

23
nla-order-service/src/main/java/cn/nla/order/feign/ProductFeignService.java

@ -0,0 +1,23 @@
package cn.nla.order.feign;
import cn.nla.common.util.JsonData;
import cn.nla.order.model.request.LockProductRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "nla-product-service")
public interface ProductFeignService {
/**
* 订单详情查询
*/
@RequestMapping("/pdt/cart/v1/confirm_order_cart_items")
JsonData confirmOrderCartItem(@RequestBody List<Long> productIdList);
/**
* 商品库存锁定
*/
@PostMapping("/cop/couponRecord/v1/lock_products")
JsonData lockProducts(@RequestBody LockProductRequest lockProductRequest);
}

15
nla-order-service/src/main/java/cn/nla/order/feign/UserFeignService.java

@ -0,0 +1,15 @@
package cn.nla.order.feign;
import cn.nla.common.util.JsonData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "nla-user-service")
public interface UserFeignService {
/**
* 查询用户地址接口本身有防止水平权限
*/
@GetMapping("/user/address/v1/find/{address_id}")
JsonData detail(@PathVariable("address_id") long addressId);
}

64
nla-order-service/src/main/java/cn/nla/order/model/VO/CouponRecordVO.java

@ -0,0 +1,64 @@
package cn.nla.order.model.VO;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class CouponRecordVO {
private Long id;
/**
* 优惠券id
*/
@JsonProperty("coupon_id")
private Long couponId;
/**
* 使用状态 可用 NEW,已使用USED,过期 EXPIRED;
*/
@JsonProperty("use_state")
private String useState;
/**
* 用户id
*/
@JsonProperty("user_id")
private Long userId;
/**
* 用户昵称
*/
@JsonProperty("user_name")
private String userName;
/**
* 优惠券标题
*/
@JsonProperty("coupon_title")
private String couponTitle;
/**
* 开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",locale = "zh",timezone = "GMT+8")
@JsonProperty("start_time")
private Date startTime;
/**
* 结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",locale = "zh",timezone = "GMT+8")
@JsonProperty("end_time")
private Date endTime;
/**
* 订单id
*/
@JsonProperty("order_id")
private Long orderId;
/**
* 抵扣价格
*/
private BigDecimal price;
/**
* 满多少才可以使用
*/
@JsonProperty("condition_price")
private BigDecimal conditionPrice;
}

42
nla-order-service/src/main/java/cn/nla/order/model/VO/OrderItemVO.java

@ -0,0 +1,42 @@
package cn.nla.order.model.VO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 购物项
*/
@Data
public class OrderItemVO {
/**
* 商品id
*/
@JsonProperty("product_id")
private Long productId;
/**
* 购买数量
*/
@JsonProperty("buy_num")
private Integer buyNum;
/**
* 商品标题
*/
@JsonProperty("product_title")
private String productTitle;
/**
* 图片
*/
@JsonProperty("product_img")
private String productImg;
/**
* 商品单价
*/
private BigDecimal amount;
/**
* 总价格单价+数量
*/
@JsonProperty("total_amount")
private BigDecimal totalAmount;
}

55
nla-order-service/src/main/java/cn/nla/order/model/VO/ProductOrderAddressVO.java

@ -0,0 +1,55 @@
package cn.nla.order.model.VO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ProductOrderAddressVO {
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 是否默认收货地址0->1->
*/
@JsonProperty("default_status")
private Integer defaultStatus;
/**
* 收发货人姓名
*/
@JsonProperty("receive_name")
private String receiveName;
/**
* 收货人电话
*/
private String phone;
/**
* /直辖市
*/
private String province;
/**
*
*/
private String city;
/**
*
*/
private String region;
/**
* 详细地址
*/
@JsonProperty("detail_address")
private String detailAddress;
}

23
nla-order-service/src/main/java/cn/nla/order/model/request/LockCouponRecordRequest.java

@ -0,0 +1,23 @@
package cn.nla.order.model.request;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@ApiModel(value = "优惠券锁定对象",description = "优惠券锁定对象")
@Data
public class LockCouponRecordRequest {
/**
* 优惠券记录id列表
*/
@ApiModelProperty(value = "优惠券记录id列表",example = "[1,2,3]")
private List<Long> lockCouponRecordIds;
/**
* 订单号
*/
@ApiModelProperty(value = "订单号",example = "3234fw234rfd232")
private String orderOutTradeNo;
}

21
nla-order-service/src/main/java/cn/nla/order/model/request/LockProductRequest.java

@ -0,0 +1,21 @@
package cn.nla.order.model.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@ApiModel(value = "商品锁定对象",description = "商品锁定对象协议")
@Data
public class LockProductRequest {
@ApiModelProperty(value = "订单id",example = "12312312312")
@JsonProperty("order_out_trade_no")
private String orderOutTradeNo;
@ApiModelProperty(value = "订单项")
@JsonProperty("order_item_list")
private List<OrderItemRequest> orderItemList;
}

18
nla-order-service/src/main/java/cn/nla/order/model/request/OrderItemRequest.java

@ -0,0 +1,18 @@
package cn.nla.order.model.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(value = "商品子项")
@Data
public class OrderItemRequest {
@ApiModelProperty(value = "商品id",example = "1")
@JsonProperty("product_id")
private long productId;
@ApiModelProperty(value = "购买数量",example = "2")
@JsonProperty("buy_num")
private int buyNum;
}

2
nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java

@ -31,5 +31,5 @@ public interface ProductOrderService extends IService<ProductOrderEntity> {
*/
JsonData confirmOrder(ConfirmOrderRequest request);
String queryProductOrderState(String outTradeNo);
String queryProductOrderState(String outTradeNo);
}

207
nla-order-service/src/main/java/cn/nla/order/service/impl/ProductOrderServiceImpl.java

@ -1,14 +1,42 @@
package cn.nla.order.service.impl;
import cn.nla.common.constant.CacheKey;
import cn.nla.common.enums.BizCodeEnum;
import cn.nla.common.enums.CouponStateEnum;
import cn.nla.common.exception.BizException;
import cn.nla.common.interceptor.LoginInterceptor;
import cn.nla.common.model.LoginUser;
import cn.nla.common.util.CommonUtil;
import cn.nla.common.util.JsonData;
import cn.nla.order.feign.CouponFeignService;
import cn.nla.order.feign.ProductFeignService;
import cn.nla.order.feign.UserFeignService;
import cn.nla.order.model.VO.CouponRecordVO;
import cn.nla.order.model.VO.OrderItemVO;
import cn.nla.order.model.VO.ProductOrderAddressVO;
import cn.nla.order.model.entity.ProductOrderEntity;
import cn.nla.order.mapper.ProductOrderMapper;
import cn.nla.order.model.request.ConfirmOrderRequest;
import cn.nla.order.model.request.LockCouponRecordRequest;
import cn.nla.order.model.request.LockProductRequest;
import cn.nla.order.model.request.OrderItemRequest;
import cn.nla.order.service.ProductOrderService;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 订单表 服务实现类
@ -17,14 +45,117 @@ import org.springframework.stereotype.Service;
* @author YJs
* @since 2024-08-13
*/
@Slf4j
@Service
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrderEntity> implements ProductOrderService {
@Autowired
private StringRedisTemplate redisTemplate;
@Resource
private UserFeignService userFeignService;
@Resource
private CouponFeignService couponFeignService;
@Resource
private ProductFeignService productFeignService;
@Override
public JsonData confirmOrder(ConfirmOrderRequest request) {
LoginUser loginUser = LoginInterceptor.threadLocal.get();
String orderToken = request.getToken();
if (StringUtils.isBlank(orderToken)) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_NOT_EXIST);
}
//原子操作 校验令牌,删除令牌
// String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
// Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
// List.of(String.format(CacheKey.SUBMIT_ORDER_TOKEN_KEY, loginUser.getId())), orderToken);
// if (result == 0L) {
// throw new BizException(BizCodeEnum.ORDER_CONFIRM_TOKEN_EQUAL_FAIL);
// }
String orderOutTradeNo = CommonUtil.getStringNumRandom(32);
//获取收货地址详情
ProductOrderAddressVO addressVO = this.getUserAddress(request.getAddressId());
log.info("收货地址信息:{}", addressVO);
//获取用户加入购物车的商品
List<Long> productIdList = request.getProductIdList();
JsonData cartItemDate = productFeignService.confirmOrderCartItem(productIdList);
List<OrderItemVO> orderItemList = cartItemDate.getData(new TypeReference<>() {
});
log.info("获取的商品:{}", orderItemList);
if (orderItemList == null) {
//购物车商品不存在
throw new BizException(BizCodeEnum.ORDER_CONFIRM_CART_ITEM_NOT_EXIST);
}
//验证价格,减去商品优惠券
this.checkPrice(orderItemList, request);
//锁定优惠券
this.lockCouponRecords(request, orderOutTradeNo);
//锁定库存
this.lockProductStocks(orderItemList, orderOutTradeNo);
// //创建订单
// ProductOrderDO productOrderDO = this.saveProductOrder(request, loginUser, orderOutTradeNo, addressVO);
return null;
}
/**
* 锁定优惠券
*/
private void lockCouponRecords(ConfirmOrderRequest orderRequest, String orderOutTradeNo) {
List<Long> lockCouponRecordIds = new ArrayList<>();
if (orderRequest.getCouponRecordId() > 0) {
lockCouponRecordIds.add(orderRequest.getCouponRecordId());
LockCouponRecordRequest lockCouponRecordRequest = new LockCouponRecordRequest();
lockCouponRecordRequest.setOrderOutTradeNo(orderOutTradeNo);
lockCouponRecordRequest.setLockCouponRecordIds(lockCouponRecordIds);
//发起锁定优惠券请求
JsonData jsonData = couponFeignService.lockCouponRecords(lockCouponRecordRequest);
if (jsonData.getCode() != 0) {
throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
}
}
}
/**
* 锁定商品库存
*/
private void lockProductStocks(List<OrderItemVO> orderItemList, String orderOutTradeNo) {
List<OrderItemRequest> itemRequestList = orderItemList.stream().map(obj -> {
OrderItemRequest request = new OrderItemRequest();
request.setBuyNum(obj.getBuyNum());
request.setProductId(obj.getProductId());
return request;
}).collect(Collectors.toList());
LockProductRequest lockProductRequest = new LockProductRequest();
lockProductRequest.setOrderOutTradeNo(orderOutTradeNo);
lockProductRequest.setOrderItemList(itemRequestList);
JsonData jsonData = productFeignService.lockProducts(lockProductRequest);
if (jsonData.getCode() != 0) {
log.error("锁定商品库存失败:{}", lockProductRequest);
throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
}
}
/**
* 获取收货地址详情后端通过id调用服务拿到地址
*/
private ProductOrderAddressVO getUserAddress(long addressId) {
JsonData addressData = userFeignService.detail(addressId);
if (addressData.getCode() != 0) {
log.error("获取收获地址失败,msg:{}", addressData);
throw new BizException(BizCodeEnum.ADDRESS_NO_EXITS);
}
return addressData.getData(new TypeReference<>() {
});
}
@Override
public String queryProductOrderState(String outTradeNo) {
ProductOrderEntity productOrderDO = baseMapper.selectOne(new QueryWrapper<ProductOrderEntity>()
@ -35,4 +166,80 @@ public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, Pro
return productOrderDO.getState();
}
}
/**
* 验证价格
* 1统计全部商品的价格
* 2) 获取优惠券(判断是否满足优惠券的条件)总价再减去优惠券的价格 就是 最终的价格
*/
private void checkPrice(List<OrderItemVO> orderItemList, ConfirmOrderRequest orderRequest) {
//统计商品总价格
BigDecimal realPayAmount = new BigDecimal("0");
if (orderItemList != null) {
for (OrderItemVO orderItemVO : orderItemList) {
BigDecimal itemRealPayAmount = orderItemVO.getTotalAmount();
realPayAmount = realPayAmount.add(itemRealPayAmount);
}
}
//获取优惠券,判断是否可以使用
CouponRecordVO couponRecordVO = getCartCouponRecord(orderRequest.getCouponRecordId());
//计算购物车价格,是否满足优惠券满减条件
if (couponRecordVO != null) {
//计算是否满足满减
if (realPayAmount.compareTo(couponRecordVO.getConditionPrice()) < 0) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL);
}
if (couponRecordVO.getPrice().compareTo(realPayAmount) > 0) {
realPayAmount = BigDecimal.ZERO;
} else {
realPayAmount = realPayAmount.subtract(couponRecordVO.getPrice());
}
}
if (realPayAmount.compareTo(orderRequest.getRealPayAmount()) != 0) {
log.error("订单验价失败:{}", orderRequest);
throw new BizException(BizCodeEnum.ORDER_CONFIRM_PRICE_FAIL);
}
}
/**
* 获取优惠券
*/
private CouponRecordVO getCartCouponRecord(Long couponRecordId) {
if (couponRecordId == null || couponRecordId < 0) {
return null;
}
JsonData couponData = couponFeignService.findUserCouponRecordById(couponRecordId);
if (couponData.getCode() != 0) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_COUPON_FAIL);
}
if (couponData.getCode() == 0) {
CouponRecordVO couponRecordVO = couponData.getData(new TypeReference<>() {
});
if (!couponAvailable(couponRecordVO)) {
log.error("优惠券使用失败");
throw new BizException(BizCodeEnum.COUPON_UNAVAILABLE);
}
return couponRecordVO;
}
return null;
}
/**
* 判断优惠券是否可用
*/
private boolean couponAvailable(CouponRecordVO couponRecordVO) {
if (couponRecordVO.getUseState().equalsIgnoreCase(CouponStateEnum.NEW.name())) {
long currentTimestamp = CommonUtil.getCurrentTimestamp();
long end = couponRecordVO.getEndTime().getTime();
long start = couponRecordVO.getStartTime().getTime();
if (currentTimestamp >= start && currentTimestamp <= end) {
return true;
}
}
return false;
}
}

8
nla-order-service/src/main/resources/application.yml

@ -31,3 +31,11 @@ mybatis-plus:
# level:
# root: INFO
feign:
client:
config:
default:
# 设置Feign的连接超时时间(秒)
connectTimeout: 5000
# 设置Feign的读取超时时间(秒)
readTimeout: 10000

4
nla-product-service/pom.xml

@ -24,5 +24,9 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>

6
nla-product-service/src/main/java/cn/nla/product/config/RabbitMQConfig.java

@ -95,12 +95,6 @@ public class RabbitMQConfig {
*/
@Bean
public Binding stockReleaseBinding(){
return new Binding(stockReleaseQueue,Binding.DestinationType.QUEUE,eventExchange,stockReleaseRoutingKey,null);
}
}

13
nla-product-service/src/main/java/cn/nla/product/controller/CartController.java

@ -1,6 +1,7 @@
package cn.nla.product.controller;
import cn.nla.common.util.JsonData;
import cn.nla.product.model.VO.CartItemVO;
import cn.nla.product.model.request.CartItemRequest;
import cn.nla.product.service.CartService;
import io.swagger.annotations.Api;
@ -9,6 +10,7 @@ import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 购物车前端控制器
@ -53,4 +55,15 @@ public class CartController {
cartService.deleteItem(productId);
return JsonData.buildSuccess();
}
/**
* 用于订单服务确认订单获取全部购物项
* 会清空购物车对应的商品
*/
@ApiOperation("下单清空购物项")
@RequestMapping("confirm_order_cart_items")
public JsonData confirmOrderCartItem(@ApiParam("商品id列表") @RequestBody List<Long> productIdList) {
List<CartItemVO> cartItemVOList = cartService.confirmOrderCartItems(productIdList);
return JsonData.buildSuccess(cartItemVOList);
}
}

2
nla-product-service/src/main/java/cn/nla/product/controller/ProductController.java

@ -48,7 +48,7 @@ public class ProductController {
@ApiOperation("rpc-锁定,商品库存锁定")
@PostMapping("lock_products")
public JsonData lockProducts(@ApiParam("商品库存锁定") @RequestBody LockProductRequest lockProductRequest){
public JsonData lockProducts(@ApiParam("商品库存锁定") @RequestBody LockProductRequest lockProductRequest) {
return productService.lockProductStock(lockProductRequest);
}

3
nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java

@ -18,8 +18,9 @@ public interface ProductMapper extends BaseMapper<ProductEntity> {
* 锁定商品库存
*/
int lockProductStock(@Param("productId") long productId, @Param("buyNum") int buyNum);
/**
* 解锁商品存储
*/
void unlockProductStock(@Param("productId")Long productId, @Param("buyNum")Integer buyNum);
void unlockProductStock(@Param("productId") Long productId, @Param("buyNum") Integer buyNum);
}

3
nla-product-service/src/main/java/cn/nla/product/model/request/OrderItemRequest.java

@ -8,12 +8,9 @@ import lombok.Data;
@ApiModel(value = "商品子项")
@Data
public class OrderItemRequest {
@ApiModelProperty(value = "商品id",example = "1")
@JsonProperty("product_id")
private long productId;
@ApiModelProperty(value = "购买数量",example = "2")
@JsonProperty("buy_num")
private int buyNum;

6
nla-product-service/src/main/java/cn/nla/product/mq/ProductStockMQListener.java

@ -11,17 +11,12 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
@Slf4j
@Component
@RabbitListener(queues = "${mq.config.stock_release_queue}")
public class ProductStockMQListener {
@Resource
private ProductService productService;
/**
*
* 重复消费-幂等性
@ -49,5 +44,4 @@ public class ProductStockMQListener {
channel.basicReject(msgTag,true);
}
}
}

9
nla-product-service/src/main/java/cn/nla/product/service/CartService.java

@ -1,9 +1,12 @@
package cn.nla.product.service;
import cn.nla.product.model.VO.CartItemVO;
import cn.nla.product.model.VO.CartVO;
import cn.nla.product.model.request.CartItemRequest;
import java.util.List;
public interface CartService {
/**
* 添加到购物车(一直缓存到redis中没有创建购物车数据表)
@ -29,4 +32,10 @@ public interface CartService {
* 删除
*/
void deleteItem(long productId);
/**
* 确认购物车商品信息
*/
List<CartItemVO> confirmOrderCartItems(List<Long> productIdList);
}

16
nla-product-service/src/main/java/cn/nla/product/service/impl/CartServiceImpl.java

@ -82,6 +82,22 @@ public class CartServiceImpl implements CartService {
getMyCartOps().delete(String.valueOf(productId));
}
@Override
public List<CartItemVO> confirmOrderCartItems(List<Long> productIdList) {
//获取全部购物车的购物项
List<CartItemVO> cartItemVOList = buildCartItem(true);
//根据需要的商品id进行过滤,并清空对应的购物项
// 如果下单异常时,需要使用MQ将数据进行回滚
List<CartItemVO> resultList = cartItemVOList.stream().filter(obj -> {
if (productIdList.contains(obj.getProductId())) {
this.deleteItem(obj.getProductId());
return true;
}
return false;
}).collect(Collectors.toList());
return resultList;
}
@Override
public void changeItemNum(CartItemRequest cartItemRequest) {
BoundHashOperations<String, Object, Object> mycart = getMyCartOps();

46
nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java

@ -77,19 +77,19 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductEntity
@Override
public JsonData lockProductStock(LockProductRequest lockProductRequest) {
String outTradeNo = lockProductRequest.getOrderOutTradeNo();
List<OrderItemRequest> itemList = lockProductRequest.getOrderItemList();
List<OrderItemRequest> itemList = lockProductRequest.getOrderItemList();
//一行代码,提取对象里面的id并加入到集合里面
List<Long> productIdList = itemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());
//批量查询
List<ProductVO> productVOList = this.findProductsByIdBatch(productIdList);
//分组
Map<Long,ProductVO> productMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));
for(OrderItemRequest item:itemList){
Map<Long, ProductVO> productMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));
for (OrderItemRequest item : itemList) {
//锁定商品记录
int rows = baseMapper.lockProductStock(item.getProductId(),item.getBuyNum());
if(rows != 1){
int rows = baseMapper.lockProductStock(item.getProductId(), item.getBuyNum());
if (rows != 1) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
}else {
} else {
//插入商品product_task
ProductVO productVO = productMap.get(item.getProductId());
ProductTaskEntity productTask = new ProductTaskEntity();
@ -99,13 +99,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductEntity
productTask.setProductName(productVO.getTitle());
productTask.setOutTradeNo(outTradeNo);
productTaskMapper.insert(productTask);
log.info("商品库存锁定-插入商品product_task成功:{}",productTask);
log.info("商品库存锁定-插入商品product_task成功:{}", productTask);
// 发送MQ延迟消息,介绍商品库存
ProductMessage productMessage = new ProductMessage();
productMessage.setOutTradeNo(outTradeNo);
productMessage.setTaskId(productTask.getId());
rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(),rabbitMQConfig.getStockReleaseDelayRoutingKey(),productMessage);
log.info("商品库存锁定信息延迟消息发送成功:{}",productMessage);
rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getStockReleaseDelayRoutingKey(), productMessage);
log.info("商品库存锁定信息延迟消息发送成功:{}", productMessage);
}
}
return JsonData.buildSuccess();
@ -114,40 +114,40 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductEntity
@Override
public boolean releaseProductStock(ProductMessage productMessage) {
//查询工作单状态
ProductTaskEntity taskDO = productTaskMapper.selectOne(new QueryWrapper<ProductTaskEntity>().eq("id",productMessage.getTaskId()));
if(taskDO == null){
log.warn("工作单不存在,消息体为:{}",productMessage);
ProductTaskEntity taskDO = productTaskMapper.selectOne(new QueryWrapper<ProductTaskEntity>().eq("id", productMessage.getTaskId()));
if (taskDO == null) {
log.warn("工作单不存在,消息体为:{}", productMessage);
}
//lock状态才处理
assert taskDO != null;
if(taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())){
if (taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
//查询订单状态
JsonData jsonData = orderFeignService.queryProductOrderState(productMessage.getOutTradeNo());
if(jsonData.getCode() == 0){
if (jsonData.getCode() == 0) {
String state = jsonData.getData().toString();
if(ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)){
if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
//状态是NEW新建状态,则返回给消息队,列重新投递
log.warn("订单状态是NEW,返回给消息队列,重新投递:{}",productMessage);
log.warn("订单状态是NEW,返回给消息队列,重新投递:{}", productMessage);
return false;
}
//如果是已经支付
if(ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)){
if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
//如果已经支付,修改task状态为finish
taskDO.setLockState(StockTaskStateEnum.FINISH.name());
productTaskMapper.update(taskDO,new QueryWrapper<ProductTaskEntity>().eq("id",productMessage.getTaskId()));
log.info("订单已经支付,修改库存锁定工作单FINISH状态:{}",productMessage);
productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskEntity>().eq("id", productMessage.getTaskId()));
log.info("订单已经支付,修改库存锁定工作单FINISH状态:{}", productMessage);
return true;
}
}
//订单不存在,或者订单被取消,确认消息,修改task状态为CANCEL,恢复优惠券使用记录为NEW
log.warn("订单不存在,或者订单被取消,确认消息,修改task状态为CANCEL,恢复商品库存,message:{}",productMessage);
log.warn("订单不存在,或者订单被取消,确认消息,修改task状态为CANCEL,恢复商品库存,message:{}", productMessage);
taskDO.setLockState(StockTaskStateEnum.CANCEL.name());
productTaskMapper.update(taskDO,new QueryWrapper<ProductTaskEntity>().eq("id",productMessage.getTaskId()));
productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskEntity>().eq("id", productMessage.getTaskId()));
//恢复商品库存,集锁定库存的值减去当前购买的值
baseMapper.unlockProductStock(taskDO.getProductId(),taskDO.getBuyNum());
baseMapper.unlockProductStock(taskDO.getProductId(), taskDO.getBuyNum());
} else {
log.warn("工作单状态不是LOCK,state={},消息体={}",taskDO.getLockState(),productMessage);
log.warn("工作单状态不是LOCK,state={},消息体={}", taskDO.getLockState(), productMessage);
}
return true;
}

19
nla-product-service/src/main/resources/application.yml

@ -37,10 +37,10 @@ spring:
#配置plus打印sql⽇志
mybatis-plus:
configuration:
log-impl:
org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus:
# configuration:
# log-impl:
# org.apache.ibatis.logging.stdout.StdOutImpl
#设置⽇志级别,ERROR/WARN/INFO/DEBUG,默认是INFO以上才显示
#logging:
# level:
@ -60,4 +60,13 @@ mq:
#消息过期,进入释放队列的key
stock_release_routing_key: stock.release.routing.key
#消息过期时间,毫秒,临时改为6分钟
ttl: 360000
ttl: 60000
feign:
client:
config:
default:
# 设置Feign的连接超时时间(秒)
connectTimeout: 5000
# 设置Feign的读取超时时间(秒)
readTimeout: 10000

7
nla-product-service/src/main/resources/mapper/ProductMapper.xml

@ -24,10 +24,9 @@
<update id="lockProductStock">
update product set lock_stock = lock_stock + #{buyNum}
where id = #{productId} and stock - lock_stock>=#{buyNum}
</update>
<update id="unlockProductStock">
update product set lock_stock = lock_stock-#{buyNum} where id = #{productId}
</update>
<update id="unlockProductStock">
update product set lock_stock = lock_stock-#{buyNum} where id = #{productId}
</update>
</mapper>

30
nla-product-service/src/test/java/cn/nla/product/ProductApplicationTests.java

@ -0,0 +1,30 @@
package cn.nla.product;
import cn.nla.common.model.ProductMessage;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProductApplication.class)
@Slf4j
public class ProductApplicationTests {
@Resource
private RabbitTemplate rabbitTemplate;
@Test
public void send() {
ProductMessage message = new ProductMessage();
message.setOutTradeNo("123456abc");
message.setTaskId(1L);
rabbitTemplate.convertAndSend("stock.event.exchange", "stock.release.delay.routing.key", message);
}
}

2
nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java

@ -32,7 +32,7 @@ public class AddressController {
@ApiOperation("根据id查找地址详情")
@GetMapping("/find/{address_id}")
public Object detail(
public JsonData detail(
@ApiParam(value = "地址id", required = true)
@PathVariable("address_id") long addressId) {
return JsonData.buildSuccess(addressService.detail(addressId));

4
nla-user-service/src/main/java/cn/nla/user/service/impl/UserServiceImpl.java

@ -17,7 +17,7 @@ import cn.nla.user.service.NotifyService;
import cn.nla.user.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
//import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.lang3.StringUtils;
@ -59,7 +59,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> impleme
*/
// @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@Override
@GlobalTransactional
// @GlobalTransactional
public JsonData register(UserRegisterRequest registerRequest) {
boolean checkCode = false;
//校验验证码

8
nla-user-service/src/main/resources/application.yml

@ -58,3 +58,11 @@ seata:
nla: 127.0.0.1:8091
vgroup-mapping:
nla-user-service-group: nla
feign:
client:
config:
default:
# 设置Feign的连接超时时间(秒)
connectTimeout: 5000
# 设置Feign的读取超时时间(秒)
readTimeout: 10000

Loading…
Cancel
Save