From 25ffbf192b898c48f493a6724201fc000ecab0fa Mon Sep 17 00:00:00 2001 From: xc-yjs Date: Wed, 11 Sep 2024 18:02:58 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=20=E6=9B=B4=E6=96=B0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nla-common/pom.xml | 40 ++-- .../cn/nla/common/config/RedissonConfig.java | 22 ++ .../java/cn/nla/common/constant/CacheKey.java | 4 + .../java/cn/nla/common/util/JsonData.java | 10 + .../java/tools/MyBatisPlusGeneratortest.java | 83 +++++++ .../service/impl/CouponServiceImpl.java | 2 + .../src/main/resources/application.yml | 11 + .../controller/ProductOrderController.java | 36 +-- .../nla/order/feign/CouponFeignService.java | 21 ++ .../nla/order/feign/ProductFeignService.java | 23 ++ .../cn/nla/order/feign/UserFeignService.java | 15 ++ .../cn/nla/order/model/VO/CouponRecordVO.java | 64 ++++++ .../cn/nla/order/model/VO/OrderItemVO.java | 42 ++++ .../order/model/VO/ProductOrderAddressVO.java | 55 +++++ .../request/LockCouponRecordRequest.java | 23 ++ .../model/request/LockProductRequest.java | 21 ++ .../order/model/request/OrderItemRequest.java | 18 ++ .../order/service/ProductOrderService.java | 2 +- .../service/impl/ProductOrderServiceImpl.java | 207 ++++++++++++++++++ .../src/main/resources/application.yml | 8 + nla-product-service/pom.xml | 4 + .../cn/nla/product/config/RabbitMQConfig.java | 6 - .../product/controller/CartController.java | 13 ++ .../product/controller/ProductController.java | 2 +- .../cn/nla/product/mapper/ProductMapper.java | 3 +- .../model/request/OrderItemRequest.java | 3 - .../product/mq/ProductStockMQListener.java | 6 - .../cn/nla/product/service/CartService.java | 9 + .../product/service/impl/CartServiceImpl.java | 16 ++ .../service/impl/ProductServiceImpl.java | 46 ++-- .../src/main/resources/application.yml | 19 +- .../main/resources/mapper/ProductMapper.xml | 7 +- .../nla/product/ProductApplicationTests.java | 30 +++ .../user/controller/AddressController.java | 2 +- .../user/service/impl/UserServiceImpl.java | 4 +- .../src/main/resources/application.yml | 8 + 36 files changed, 794 insertions(+), 91 deletions(-) create mode 100644 nla-common/src/test/java/tools/MyBatisPlusGeneratortest.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/feign/CouponFeignService.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/feign/ProductFeignService.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/feign/UserFeignService.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/VO/CouponRecordVO.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/VO/OrderItemVO.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/VO/ProductOrderAddressVO.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/request/LockCouponRecordRequest.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/request/LockProductRequest.java create mode 100644 nla-order-service/src/main/java/cn/nla/order/model/request/OrderItemRequest.java create mode 100644 nla-product-service/src/test/java/cn/nla/product/ProductApplicationTests.java diff --git a/nla-common/pom.xml b/nla-common/pom.xml index 1ded6a1..1f16d4d 100644 --- a/nla-common/pom.xml +++ b/nla-common/pom.xml @@ -105,26 +105,26 @@ spring-cloud-starter-openfeign - - com.alibaba.cloud - spring-cloud-starter-alibaba-seata - - - - com.alibaba.cloud - spring-cloud-starter-alibaba-seata - - - io.seata - seata-spring-boot-starter - - - - - io.seata - seata-spring-boot-starter - 1.3.0 - + + + + + + + + + + + + + + + + + + + + org.springframework.boot diff --git a/nla-common/src/main/java/cn/nla/common/config/RedissonConfig.java b/nla-common/src/main/java/cn/nla/common/config/RedissonConfig.java index d66a23d..e15b7d4 100644 --- a/nla-common/src/main/java/cn/nla/common/config/RedissonConfig.java +++ b/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空指针异常"); + } + }; + } } diff --git a/nla-common/src/main/java/cn/nla/common/constant/CacheKey.java b/nla-common/src/main/java/cn/nla/common/constant/CacheKey.java index 55aa9bd..087b309 100644 --- a/nla-common/src/main/java/cn/nla/common/constant/CacheKey.java +++ b/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"; } diff --git a/nla-common/src/main/java/cn/nla/common/util/JsonData.java b/nla-common/src/main/java/cn/nla/common/util/JsonData.java index d0b46c5..9b5fa23 100644 --- a/nla-common/src/main/java/cn/nla/common/util/JsonData.java +++ b/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 getData(TypeReference typeReference){ + return JSON.parseObject(JSON.toJSONString(data),typeReference); +} + /** * 成功,不传入数据 */ diff --git a/nla-common/src/test/java/tools/MyBatisPlusGeneratortest.java b/nla-common/src/test/java/tools/MyBatisPlusGeneratortest.java new file mode 100644 index 0000000..ce9a493 --- /dev/null +++ b/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相关代码⽣成完毕 ========"); + } +} diff --git a/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java b/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java index 089d98c..23c7c4f 100644 --- a/nla-coupon-service/src/main/java/cn/nla/coupon/service/impl/CouponServiceImpl.java +++ b/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 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()); diff --git a/nla-coupon-service/src/main/resources/application.yml b/nla-coupon-service/src/main/resources/application.yml index 5b5f297..201c080 100644 --- a/nla-coupon-service/src/main/resources/application.yml +++ b/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 + diff --git a/nla-order-service/src/main/java/cn/nla/order/controller/ProductOrderController.java b/nla-order-service/src/main/java/cn/nla/order/controller/ProductOrderController.java index dcf6a55..17bd311 100644 --- a/nla-order-service/src/main/java/cn/nla/order/controller/ProductOrderController.java +++ b/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; + /** * 查询订单状态 - * + *

* 此接口没有登录拦截,可以增加一个秘钥进行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); } diff --git a/nla-order-service/src/main/java/cn/nla/order/feign/CouponFeignService.java b/nla-order-service/src/main/java/cn/nla/order/feign/CouponFeignService.java new file mode 100644 index 0000000..7530f58 --- /dev/null +++ b/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); +} diff --git a/nla-order-service/src/main/java/cn/nla/order/feign/ProductFeignService.java b/nla-order-service/src/main/java/cn/nla/order/feign/ProductFeignService.java new file mode 100644 index 0000000..98db4b3 --- /dev/null +++ b/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 productIdList); + + /** + * 商品库存锁定 + */ + @PostMapping("/cop/couponRecord/v1/lock_products") + JsonData lockProducts(@RequestBody LockProductRequest lockProductRequest); +} diff --git a/nla-order-service/src/main/java/cn/nla/order/feign/UserFeignService.java b/nla-order-service/src/main/java/cn/nla/order/feign/UserFeignService.java new file mode 100644 index 0000000..a2d8223 --- /dev/null +++ b/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); +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/VO/CouponRecordVO.java b/nla-order-service/src/main/java/cn/nla/order/model/VO/CouponRecordVO.java new file mode 100644 index 0000000..cfe6220 --- /dev/null +++ b/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; +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/VO/OrderItemVO.java b/nla-order-service/src/main/java/cn/nla/order/model/VO/OrderItemVO.java new file mode 100644 index 0000000..7aa2286 --- /dev/null +++ b/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; +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/VO/ProductOrderAddressVO.java b/nla-order-service/src/main/java/cn/nla/order/model/VO/ProductOrderAddressVO.java new file mode 100644 index 0000000..dba9cd9 --- /dev/null +++ b/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; +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/request/LockCouponRecordRequest.java b/nla-order-service/src/main/java/cn/nla/order/model/request/LockCouponRecordRequest.java new file mode 100644 index 0000000..5f7abb8 --- /dev/null +++ b/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 lockCouponRecordIds; + /** + * 订单号 + */ + @ApiModelProperty(value = "订单号",example = "3234fw234rfd232") + private String orderOutTradeNo; + +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/request/LockProductRequest.java b/nla-order-service/src/main/java/cn/nla/order/model/request/LockProductRequest.java new file mode 100644 index 0000000..cdfa963 --- /dev/null +++ b/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 orderItemList; +} diff --git a/nla-order-service/src/main/java/cn/nla/order/model/request/OrderItemRequest.java b/nla-order-service/src/main/java/cn/nla/order/model/request/OrderItemRequest.java new file mode 100644 index 0000000..a9ffe6a --- /dev/null +++ b/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; +} diff --git a/nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java b/nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java index 22f30b7..60e58d9 100644 --- a/nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java +++ b/nla-order-service/src/main/java/cn/nla/order/service/ProductOrderService.java @@ -31,5 +31,5 @@ public interface ProductOrderService extends IService { */ JsonData confirmOrder(ConfirmOrderRequest request); - String queryProductOrderState(String outTradeNo); + String queryProductOrderState(String outTradeNo); } diff --git a/nla-order-service/src/main/java/cn/nla/order/service/impl/ProductOrderServiceImpl.java b/nla-order-service/src/main/java/cn/nla/order/service/impl/ProductOrderServiceImpl.java index e01f033..8be405c 100644 --- a/nla-order-service/src/main/java/cn/nla/order/service/impl/ProductOrderServiceImpl.java +++ b/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; + /** *

* 订单表 服务实现类 @@ -17,14 +45,117 @@ import org.springframework.stereotype.Service; * @author YJs * @since 2024-08-13 */ +@Slf4j @Service public class ProductOrderServiceImpl extends ServiceImpl 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 productIdList = request.getProductIdList(); + JsonData cartItemDate = productFeignService.confirmOrderCartItem(productIdList); + List 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 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 orderItemList, String orderOutTradeNo) { + List 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() @@ -35,4 +166,80 @@ public class ProductOrderServiceImpl extends ServiceImpl 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; + } + } diff --git a/nla-order-service/src/main/resources/application.yml b/nla-order-service/src/main/resources/application.yml index fd1f578..600812e 100644 --- a/nla-order-service/src/main/resources/application.yml +++ b/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 diff --git a/nla-product-service/pom.xml b/nla-product-service/pom.xml index bbd98ab..d2d4835 100644 --- a/nla-product-service/pom.xml +++ b/nla-product-service/pom.xml @@ -24,5 +24,9 @@ org.projectlombok lombok + + org.springframework.boot + spring-boot-starter-test + diff --git a/nla-product-service/src/main/java/cn/nla/product/config/RabbitMQConfig.java b/nla-product-service/src/main/java/cn/nla/product/config/RabbitMQConfig.java index 5ca2f0f..aabbfa2 100644 --- a/nla-product-service/src/main/java/cn/nla/product/config/RabbitMQConfig.java +++ b/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); } - - - - - } diff --git a/nla-product-service/src/main/java/cn/nla/product/controller/CartController.java b/nla-product-service/src/main/java/cn/nla/product/controller/CartController.java index 214f4c3..547110e 100644 --- a/nla-product-service/src/main/java/cn/nla/product/controller/CartController.java +++ b/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 productIdList) { + List cartItemVOList = cartService.confirmOrderCartItems(productIdList); + return JsonData.buildSuccess(cartItemVOList); + } } diff --git a/nla-product-service/src/main/java/cn/nla/product/controller/ProductController.java b/nla-product-service/src/main/java/cn/nla/product/controller/ProductController.java index 8a4af65..e3ca13d 100644 --- a/nla-product-service/src/main/java/cn/nla/product/controller/ProductController.java +++ b/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); } diff --git a/nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java b/nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java index 33189d2..77f0d3a 100644 --- a/nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java +++ b/nla-product-service/src/main/java/cn/nla/product/mapper/ProductMapper.java @@ -18,8 +18,9 @@ public interface ProductMapper extends BaseMapper { * 锁定商品库存 */ 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); } diff --git a/nla-product-service/src/main/java/cn/nla/product/model/request/OrderItemRequest.java b/nla-product-service/src/main/java/cn/nla/product/model/request/OrderItemRequest.java index f83b0f5..5545881 100644 --- a/nla-product-service/src/main/java/cn/nla/product/model/request/OrderItemRequest.java +++ b/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; diff --git a/nla-product-service/src/main/java/cn/nla/product/mq/ProductStockMQListener.java b/nla-product-service/src/main/java/cn/nla/product/mq/ProductStockMQListener.java index c1be0db..c85eee0 100644 --- a/nla-product-service/src/main/java/cn/nla/product/mq/ProductStockMQListener.java +++ b/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); } } - } diff --git a/nla-product-service/src/main/java/cn/nla/product/service/CartService.java b/nla-product-service/src/main/java/cn/nla/product/service/CartService.java index 17938fc..2c31e7f 100644 --- a/nla-product-service/src/main/java/cn/nla/product/service/CartService.java +++ b/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 confirmOrderCartItems(List productIdList); } diff --git a/nla-product-service/src/main/java/cn/nla/product/service/impl/CartServiceImpl.java b/nla-product-service/src/main/java/cn/nla/product/service/impl/CartServiceImpl.java index 07c08f7..18dd2b0 100644 --- a/nla-product-service/src/main/java/cn/nla/product/service/impl/CartServiceImpl.java +++ b/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 confirmOrderCartItems(List productIdList) { + //获取全部购物车的购物项 + List cartItemVOList = buildCartItem(true); + //根据需要的商品id进行过滤,并清空对应的购物项 + // 如果下单异常时,需要使用MQ将数据进行回滚 + List 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 mycart = getMyCartOps(); diff --git a/nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java b/nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java index b2dcdf6..53f58e6 100644 --- a/nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java +++ b/nla-product-service/src/main/java/cn/nla/product/service/impl/ProductServiceImpl.java @@ -77,19 +77,19 @@ public class ProductServiceImpl extends ServiceImpl itemList = lockProductRequest.getOrderItemList(); + List itemList = lockProductRequest.getOrderItemList(); //一行代码,提取对象里面的id并加入到集合里面 List productIdList = itemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList()); //批量查询 List productVOList = this.findProductsByIdBatch(productIdList); //分组 - Map productMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity())); - for(OrderItemRequest item:itemList){ + Map 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().eq("id",productMessage.getTaskId())); - if(taskDO == null){ - log.warn("工作单不存在,消息体为:{}",productMessage); + ProductTaskEntity taskDO = productTaskMapper.selectOne(new QueryWrapper().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().eq("id",productMessage.getTaskId())); - log.info("订单已经支付,修改库存锁定工作单FINISH状态:{}",productMessage); + productTaskMapper.update(taskDO, new QueryWrapper().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().eq("id",productMessage.getTaskId())); + productTaskMapper.update(taskDO, new QueryWrapper().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; } diff --git a/nla-product-service/src/main/resources/application.yml b/nla-product-service/src/main/resources/application.yml index 02e109a..ebece0b 100644 --- a/nla-product-service/src/main/resources/application.yml +++ b/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 diff --git a/nla-product-service/src/main/resources/mapper/ProductMapper.xml b/nla-product-service/src/main/resources/mapper/ProductMapper.xml index 78521c0..9fbffd8 100644 --- a/nla-product-service/src/main/resources/mapper/ProductMapper.xml +++ b/nla-product-service/src/main/resources/mapper/ProductMapper.xml @@ -24,10 +24,9 @@ update product set lock_stock = lock_stock + #{buyNum} where id = #{productId} and stock - lock_stock>=#{buyNum} - - - update product set lock_stock = lock_stock-#{buyNum} where id = #{productId} - + + update product set lock_stock = lock_stock-#{buyNum} where id = #{productId} + diff --git a/nla-product-service/src/test/java/cn/nla/product/ProductApplicationTests.java b/nla-product-service/src/test/java/cn/nla/product/ProductApplicationTests.java new file mode 100644 index 0000000..e5883da --- /dev/null +++ b/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); + } + +} + diff --git a/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java b/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java index aec2c6c..2c6343e 100644 --- a/nla-user-service/src/main/java/cn/nla/user/controller/AddressController.java +++ b/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)); diff --git a/nla-user-service/src/main/java/cn/nla/user/service/impl/UserServiceImpl.java b/nla-user-service/src/main/java/cn/nla/user/service/impl/UserServiceImpl.java index 7fcfb49..bf005d7 100644 --- a/nla-user-service/src/main/java/cn/nla/user/service/impl/UserServiceImpl.java +++ b/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 impleme */ // @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) @Override - @GlobalTransactional +// @GlobalTransactional public JsonData register(UserRegisterRequest registerRequest) { boolean checkCode = false; //校验验证码 diff --git a/nla-user-service/src/main/resources/application.yml b/nla-user-service/src/main/resources/application.yml index 16e975c..3ff8f83 100644 --- a/nla-user-service/src/main/resources/application.yml +++ b/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