From 5d04837d46b6ff8c3fc871b23faac2e8c92ed820 Mon Sep 17 00:00:00 2001 From: JACKYMYPERSON <1627832236@qq.com> Date: Tue, 3 Mar 2026 20:10:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=A6=E4=B9=A0=E5=88=B0=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mayiming/Controller/OrderController.java | 53 ++++++++----- .../cn/mayiming/Service/OrderService.java | 74 +++++++++++++------ .../cn/mayiming/entity/PayTriggerMsgDTO.java | 14 ++++ .../cn/mayiming/Consumer/payConsumer.java | 27 +++++-- .../cn/mayiming/Entity/PayTriggerMsgDTO.java | 14 ++++ .../java/cn/mayiming/Mapper/payMapper.java | 5 ++ 6 files changed, 138 insertions(+), 49 deletions(-) create mode 100644 order-service/src/main/java/cn/mayiming/entity/PayTriggerMsgDTO.java create mode 100644 pay-service/src/main/java/cn/mayiming/Entity/PayTriggerMsgDTO.java create mode 100644 pay-service/src/main/java/cn/mayiming/Mapper/payMapper.java diff --git a/order-service/src/main/java/cn/mayiming/Controller/OrderController.java b/order-service/src/main/java/cn/mayiming/Controller/OrderController.java index eeb477f..f31bed8 100644 --- a/order-service/src/main/java/cn/mayiming/Controller/OrderController.java +++ b/order-service/src/main/java/cn/mayiming/Controller/OrderController.java @@ -32,59 +32,72 @@ public class OrderController { } @PostMapping("/create") - public Result createOrder(@RequestBody Map jsonMap){ + public Result createOrder(@RequestBody Map jsonMap) { + // ========== 1. 校验businessId(原有逻辑保留) ========== Object businessIdObj = jsonMap.get("businessId"); String businessId = null; if (businessIdObj != null) { - businessId = businessIdObj.toString().trim(); // 转字符串并去除首尾空格 + businessId = businessIdObj.toString().trim(); } - - // 2. 判断businessId是否存在(核心逻辑) if (businessId == null || businessId.isEmpty()) { - // businessId不存在/为空 → 返回参数错误 return Result.fail(400, "businessId不能为空"); } + try { - // 1. 安全获取userId:先转Number,再取int值(兼容Integer/Long) + // ========== 2. 安全解析参数(原有逻辑保留,仅优化提示) ========== + // 2.1 解析userId Number userIdNum = (Number) jsonMap.get("userId"); if (userIdNum == null) { return Result.fail(400, "userId不能为空"); } int userId = userIdNum.intValue(); - // 2. 安全获取stockid:先转Number,再取long值(兼容Integer/Long) + // 2.2 解析stockid Number stockIdNum = (Number) jsonMap.get("stockid"); if (stockIdNum == null) { return Result.fail(400, "stockid不能为空"); } Long stockId = stockIdNum.longValue(); - // 3. 安全获取deductnum:先转Number,再取int值(兼容Integer/Long) + // 2.3 解析deductnum Number deductNumNum = (Number) jsonMap.get("deductnum"); if (deductNumNum == null) { return Result.fail(400, "deductnum不能为空"); } int deductNum = deductNumNum.intValue(); - // 4. 组装DTO + // ========== 3. 组装DTO ========== StockDeductDTO stockDeductDTO = new StockDeductDTO(); stockDeductDTO.setId(stockId); stockDeductDTO.setDeductNum(deductNum); - // 5. 调用服务 - int serviceResult = orderService.createOrder(stockDeductDTO, userId,businessId); - if (serviceResult != 0) { - // 库存扣减/订单创建失败 - return Result.fail("库存扣减失败,订单创建失败"); + // ========== 4. 调用Service(核心改动:接收Map结果,获取订单号) ========== + // 注意:原Service返回int,需改为返回Map(包含success、msg、orderNo) + Map serviceResult = orderService.createOrder(stockDeductDTO, userId, businessId); + + // 4.1 解析Service返回结果 + boolean isSuccess = (boolean) serviceResult.get("success"); + if (!isSuccess) { + return Result.fail(500, serviceResult.get("msg").toString()); } - // 成功:可以返回额外数据(比如订单ID) - return Result.success("库存扣减成功,订单创建成功"); - } catch (Exception e) { - // 捕获所有异常,返回友好提示 + // 4.2 成功:返回订单号(供前端轮询支付链接) + String orderNo = serviceResult.get("orderNo").toString(); + return Result.success( + Map.of( + "msg", "订单创建成功,已触发支付流程", + "orderNo", orderNo, // 核心:返回订单号 + "tips", "请轮询 /order/detail?orderNo=" + orderNo + " 获取支付链接" + ) + ); + + } catch (ClassCastException e) { + // 补充类型转换异常处理(前端传参类型错误) e.printStackTrace(); - return Result.fail("订单创建异常:" + e.getMessage()); + return Result.fail(400, "参数类型错误:userId/stockid/deductnum需为数字"); + } catch (Exception e) { + e.printStackTrace(); + return Result.fail(500, "订单创建异常:" + e.getMessage()); } - } } diff --git a/order-service/src/main/java/cn/mayiming/Service/OrderService.java b/order-service/src/main/java/cn/mayiming/Service/OrderService.java index dbb8e79..9ad1e01 100644 --- a/order-service/src/main/java/cn/mayiming/Service/OrderService.java +++ b/order-service/src/main/java/cn/mayiming/Service/OrderService.java @@ -2,6 +2,7 @@ package cn.mayiming.Service; import cn.mayiming.Mapper.OrderMapper; import cn.mayiming.entity.Order; +import cn.mayiming.entity.PayTriggerMsgDTO; import cn.mayiming.entity.StockDeductDTO; import cn.mayiming.entity.User; import cn.mayiming.feign.StockFeignClient; @@ -13,7 +14,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Service public class OrderService { @@ -29,6 +32,8 @@ public class OrderService { @Resource private RocketMQTemplate rocketMQTemplate; + private static final String PAY_TRIGGER_TOPIC = "pay_topic"; + public User SearchUserbyname (User user) { return userFeignClient.selectByUsername(user); } @@ -59,54 +64,75 @@ public class OrderService { } @Transactional(rollbackFor = Exception.class) - public int createOrder(StockDeductDTO stockDeductDTO,int userId,String businessId) { + public Map createOrder(StockDeductDTO stockDeductDTO, int userId, String businessId) { + Map result = new HashMap<>(); + + // ========== 原有核心逻辑(幂等+用户+扣库存+插订单)========== Integer count = orderMapper.countByBusinessId(businessId); if (count != null && count > 0) { - return 1; // 已存在,直接返回失败 + result.put("success", false); + result.put("msg", "重复请求,下单失败"); + return result; } - // 1.2 校验用户是否存在(远程只读,无事务管控) if (userFeignClient.GetUserByid(userId) == null) { - return 1; // 用户不存在,直接返回失败 + result.put("success", false); + result.put("msg", "用户不存在,下单失败"); + return result; } + Order order = null; // 声明订单对象,方便后续发送消息 try { - // 步骤1:调用库存服务扣减库存(远程操作,需库存服务自身保证事务) int stockResult = stockFeignClient.deductstock(stockDeductDTO); - if (stockResult == 0) { // 假设返回0是失败,非0是成功(按你原有逻辑) - throw new RuntimeException("库存扣减失败,返回码:" + stockResult); + if (stockResult == 0) { + throw new RuntimeException("库存不足,扣减失败"); } - // 步骤2:构建订单对象(适配t_order表) - Order order = new Order(); - order.setOrderNo(orderMapper.generateOrderNo()); // 生成唯一订单号 - order.setUserId(Long.valueOf(userId)); // 转换为Long适配表结构 - order.setGoodsId(stockDeductDTO.getId()); // 商品ID(从库存DTO获取) - order.setOrderAmount(new BigDecimal("99.99")); // 订单金额(实际需从商品服务获取) - order.setOrderStatus(0); // 0-待支付 + // 构建并插入订单 + order = new Order(); + order.setOrderNo(orderMapper.generateOrderNo()); + order.setUserId(Long.valueOf(userId)); + order.setGoodsId(stockDeductDTO.getId()); + order.setOrderAmount(new BigDecimal("99.99")); + order.setOrderStatus(0); // 0-待支付 - // 步骤3:插入订单记录(核心!事务管控) Integer orderInsertResult = orderMapper.insertOrder(order); if (orderInsertResult == null || orderInsertResult == 0) { throw new RuntimeException("订单插入失败"); } - // 步骤4:插入幂等记录(占坑,事务管控) - Integer idempotentInsertResult = orderMapper.insertIdempotentRecord(businessId, 1); // 直接标记为成功 + // 插入幂等记录 + Integer idempotentInsertResult = orderMapper.insertIdempotentRecord(businessId, 1); if (idempotentInsertResult == null || idempotentInsertResult == 0) { throw new RuntimeException("幂等记录插入失败"); } - // 所有操作成功,返回0 - return 0; + // ========== 核心新增:发送RocketMQ支付触发消息 ========== + PayTriggerMsgDTO payMsg = new PayTriggerMsgDTO(); + payMsg.setOrderNo(order.getOrderNo()); + payMsg.setUserId(order.getUserId()); + payMsg.setPayAmount(order.getOrderAmount()); + payMsg.setBusinessId(businessId); + payMsg.setGoodsId(order.getGoodsId()); + + // 发送异步消息(本地模拟用同步发送,确保消息投递成功) + try { + rocketMQTemplate.convertAndSend(PAY_TRIGGER_TOPIC, payMsg); + System.out.println("订单" + order.getOrderNo() + "支付触发消息已发送到RocketMQ"); + } catch (Exception e) { + throw new RuntimeException("发送支付触发消息失败", e); + } + + // 返回结果(包含订单号,前端后续用订单号调用模拟支付接口) + result.put("success", true); + result.put("msg", "订单创建成功,已触发支付流程"); + result.put("orderNo", order.getOrderNo()); } catch (Exception e) { - // 任何异常触发事务回滚:订单插入、幂等插入都会回滚 e.printStackTrace(); - // 可选:幂等记录标记为失败(方便排查) orderMapper.updateIdempotentStatus(businessId, 2); - return 1; + result.put("success", false); + result.put("msg", "下单失败:" + e.getMessage()); } - + return result; } - } diff --git a/order-service/src/main/java/cn/mayiming/entity/PayTriggerMsgDTO.java b/order-service/src/main/java/cn/mayiming/entity/PayTriggerMsgDTO.java new file mode 100644 index 0000000..f75aa2f --- /dev/null +++ b/order-service/src/main/java/cn/mayiming/entity/PayTriggerMsgDTO.java @@ -0,0 +1,14 @@ +package cn.mayiming.entity; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class PayTriggerMsgDTO { + private String orderNo; // 订单号(核心关联) + private Long userId; // 用户ID + private BigDecimal payAmount; // 支付金额 + private String businessId; // 幂等ID(透传) + private Long goodsId; // 商品ID(用于关单恢复库存) +} \ No newline at end of file diff --git a/pay-service/src/main/java/cn/mayiming/Consumer/payConsumer.java b/pay-service/src/main/java/cn/mayiming/Consumer/payConsumer.java index 02645ac..b97855a 100644 --- a/pay-service/src/main/java/cn/mayiming/Consumer/payConsumer.java +++ b/pay-service/src/main/java/cn/mayiming/Consumer/payConsumer.java @@ -1,18 +1,35 @@ package cn.mayiming.Consumer; +import cn.mayiming.Entity.PayTriggerMsgDTO; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component @RocketMQMessageListener( topic = "pay_topic", consumerGroup = "pay-service-consumer", - selectorExpression = "pay_success" + selectorExpression = "*" ) -public class payConsumer implements RocketMQListener { +public class payConsumer implements RocketMQListener { + @Override - public void onMessage(String s) { - System.out.println("接收到消息"+s); + public void onMessage(PayTriggerMsgDTO msg) { + // 消费者接收到消息,模拟支付流程(本地仅生成支付链接,记录到日志/订单) + try { + System.out.println("========== 接收到支付触发消息 =========="); + System.out.println("订单号:" + msg.getOrderNo()); + System.out.println("用户ID:" + msg.getUserId()); + System.out.println("支付金额:" + msg.getPayAmount()); + System.out.println("模拟支付链接:http://localhost:8080/order/mock/pay?orderNo=" + msg.getOrderNo()); + System.out.println("======================================="); + + + } catch (Exception e) { + e.printStackTrace(); + // 本地模拟:消息消费失败可记录日志,生产环境需配置重试 + System.err.println("消费支付触发消息失败,订单号:" + msg.getOrderNo() + ",原因:" + e.getMessage()); + } } -} +} \ No newline at end of file diff --git a/pay-service/src/main/java/cn/mayiming/Entity/PayTriggerMsgDTO.java b/pay-service/src/main/java/cn/mayiming/Entity/PayTriggerMsgDTO.java new file mode 100644 index 0000000..2d39830 --- /dev/null +++ b/pay-service/src/main/java/cn/mayiming/Entity/PayTriggerMsgDTO.java @@ -0,0 +1,14 @@ +package cn.mayiming.Entity; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class PayTriggerMsgDTO { + private String orderNo; // 订单号(核心关联) + private Long userId; // 用户ID + private BigDecimal payAmount; // 支付金额 + private String businessId; // 幂等ID(透传) + private Long goodsId; // 商品ID(用于关单恢复库存) +} \ No newline at end of file diff --git a/pay-service/src/main/java/cn/mayiming/Mapper/payMapper.java b/pay-service/src/main/java/cn/mayiming/Mapper/payMapper.java new file mode 100644 index 0000000..5c44fb7 --- /dev/null +++ b/pay-service/src/main/java/cn/mayiming/Mapper/payMapper.java @@ -0,0 +1,5 @@ +package cn.mayiming.Mapper; + +public interface payMapper { + +}