From 72027eefa66ac08da0e9c86b03253007a7f51186 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Fri, 8 Aug 2025 14:00:46 +0800 Subject: [PATCH] =?UTF-8?q?8.8=20=E8=A7=A3=E8=80=A6HTTP=E5=92=8CRPC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docker-compose-app-v3.0.yml | 2 +- .../trigger/MarketTradeControllerTest.java | 7 +- .../factory/TradeLockRuleFilterFactory.java | 2 +- .../trigger/basic/MarketTradeService.java | 313 ++++++++++++++++++ .../trigger/http/MarketTradeController.java | 268 +-------------- .../trigger/rpc/MarketTradeDubboService.java | 16 +- .../whut/types/exception/AppException.java | 34 +- 7 files changed, 351 insertions(+), 291 deletions(-) create mode 100644 group-buying-sys-trigger/src/main/java/edu/whut/trigger/basic/MarketTradeService.java diff --git a/docs/tag/group-buy-v3.0/docker-compose-app-v3.0.yml b/docs/tag/group-buy-v3.0/docker-compose-app-v3.0.yml index 6b50a84..96ac2d5 100644 --- a/docs/tag/group-buy-v3.0/docker-compose-app-v3.0.yml +++ b/docs/tag/group-buy-v3.0/docker-compose-app-v3.0.yml @@ -6,7 +6,7 @@ services: container_name: group-buy-market-front restart: unless-stopped ports: - - '18093:80' + - '18091:80' volumes: - ./nginx/html:/usr/share/nginx/html - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java index 34fa504..ad8acc0 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java @@ -4,6 +4,7 @@ import edu.whut.api.IMarketTradeService; import edu.whut.api.dto.LockMarketPayOrderRequestDTO; import edu.whut.api.dto.LockMarketPayOrderResponseDTO; import edu.whut.api.response.Response; +import edu.whut.trigger.http.MarketTradeController; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Test; @@ -22,14 +23,14 @@ import javax.annotation.Resource; public class MarketTradeControllerTest { @Resource - private IMarketTradeService marketTradeService; + private MarketTradeController marketTradeService; @Test public void test_lockMarketPayOrder_mq() throws InterruptedException { LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); - lockMarketPayOrderRequestDTO.setUserId("zy04"); + lockMarketPayOrderRequestDTO.setUserId("smile03"); lockMarketPayOrderRequestDTO.setTeamId(null); - lockMarketPayOrderRequestDTO.setActivityId(100124L); + lockMarketPayOrderRequestDTO.setActivityId(100123L); lockMarketPayOrderRequestDTO.setGoodsId("9890001"); lockMarketPayOrderRequestDTO.setSource("s01"); lockMarketPayOrderRequestDTO.setChannel("c01"); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeLockRuleFilterFactory.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeLockRuleFilterFactory.java index ce0a2b4..2214d0c 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeLockRuleFilterFactory.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/lock/factory/TradeLockRuleFilterFactory.java @@ -26,7 +26,7 @@ public class TradeLockRuleFilterFactory { private static final String teamStockKey = "group_buy_market_team_stock_key_"; /** - * 组装责任链 + * 组装责任链 先活动有效性校验=》用户参与活动次数校验=》抢占库存校验 * 通过 Spring @Bean 暴露:外部只需注入 BusinessLinkedList 即可调用 apply */ @Bean("tradeRuleFilter") diff --git a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/basic/MarketTradeService.java b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/basic/MarketTradeService.java new file mode 100644 index 0000000..f58ea77 --- /dev/null +++ b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/basic/MarketTradeService.java @@ -0,0 +1,313 @@ +package edu.whut.trigger.basic; + +import com.alibaba.fastjson.JSON; +import edu.whut.api.IMarketTradeService; +import edu.whut.api.dto.*; +import edu.whut.api.response.Response; +import edu.whut.domain.activity.model.entity.MarketProductEntity; +import edu.whut.domain.activity.model.entity.TrialBalanceEntity; +import edu.whut.domain.activity.model.valobj.GroupBuyActivityDiscountVO; +import edu.whut.domain.activity.service.IIndexGroupBuyMarketService; +import edu.whut.domain.trade.model.entity.*; +import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; +import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO; +import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO; +import edu.whut.domain.trade.service.ITradeLockOrderService; +import edu.whut.domain.trade.service.ITradeRefundOrderService; +import edu.whut.domain.trade.service.ITradeSettlementOrderService; +import edu.whut.types.enums.ResponseCode; +import edu.whut.types.exception.AppException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestBody; +import java.util.Objects; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MarketTradeService implements IMarketTradeService { + //价格试算 + private final IIndexGroupBuyMarketService indexGroupBuyMarketService; + //拼团锁单 + private final ITradeLockOrderService tradeOrderService; + //拼团结算 + private final ITradeSettlementOrderService tradeSettlementOrderService; + //退单 + private final ITradeRefundOrderService tradeRefundOrderService; + + /** + * 锁定营销预支付订单(拼团 / 普通优惠) + */ + @Override + public Response lockMarketPayOrder(@RequestBody LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO) { + try { + /* ---------- 1. 基础参数提取与校验 ---------- */ + String userId = lockMarketPayOrderRequestDTO.getUserId(); + String source = lockMarketPayOrderRequestDTO.getSource(); + String channel = lockMarketPayOrderRequestDTO.getChannel(); + String goodsId = lockMarketPayOrderRequestDTO.getGoodsId(); + Long activityId = lockMarketPayOrderRequestDTO.getActivityId(); + String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo(); + String teamId = lockMarketPayOrderRequestDTO.getTeamId(); //可为空,对应参与拼团or创建拼团 + LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO(); + + log.info("营销锁单开始执行:拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO)); + + // 空值校验(任何一个关键字段为空则直接返回错误) + boolean httpWithoutUrl = + "HTTP".equals(notifyConfigVO.getNotifyType()) + && StringUtils.isBlank(notifyConfigVO.getNotifyUrl()); + + if (StringUtils.isAnyBlank(userId, source, channel, goodsId) + || activityId == null + || httpWithoutUrl) { + return Response.builder() + .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) + .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) + .build(); + } + + + /* ---------- 2. 查询是否已存在未支付锁单 ---------- */ + MarketPayOrderEntity marketPayOrderEntity = + tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo); + if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) { + // 若已锁单未支付,直接返回原锁单信息(幂等) + return buildSuccessResp(marketPayOrderEntity); + } + + /* ---------- 3. 拼团目标人数校验 可能前端显示可参与,实际点击之后人数已满 ---------- */ + //(teamId 不为空表示 参与拼团 ) + if (StringUtils.isNotBlank(teamId)) { + // 查询当前拼团的 目标数量 已完成下单数量 锁单数量 + GroupBuyProgressVO progress = tradeOrderService.queryGroupBuyProgress(teamId); + // 如果目标人数已满,则拒绝本次锁单 目前逻辑是结算完成LockCount也不会减。 + if (progress != null && Objects.equals(progress.getTargetCount(), progress.getLockCount())) { + log.info("交易锁单拦截-拼单目标已达成 userId={} teamId={} target={} lock={}", + userId, teamId, progress.getTargetCount(), progress.getLockCount()); + return Response.builder() + .code(ResponseCode.E0006.getCode()) + .info(ResponseCode.E0006.getInfo()) + .build(); + } + } + + /* ---------- 4. 调用营销服务进行优惠试算 ---------- */ + TrialBalanceEntity trialBalance = indexGroupBuyMarketService.indexMarketTrial( + MarketProductEntity.builder() + .userId(userId) + .source(source) + .channel(channel) + .goodsId(goodsId) + .activityId(activityId) + .build()); + + // 人群限定,非目前人群不允许参与活动 + if (!trialBalance.getIsVisible() || !trialBalance.getIsEnable()){ + return Response.builder() + .code(ResponseCode.E0007.getCode()) + .info(ResponseCode.E0007.getInfo()) + .build(); + } + + //获取拼团活动配置信息 + GroupBuyActivityDiscountVO discountVO = trialBalance.getGroupBuyActivityDiscountVO(); + + /* ---------- 5. 组装领域对象后调用真正的锁单 ---------- */ + marketPayOrderEntity = tradeOrderService.lockMarketPayOrder( + UserEntity.builder().userId(userId).build(), + PayActivityEntity.builder() + .teamId(teamId) + .activityId(activityId) + .activityName(discountVO.getActivityName()) + .startTime(discountVO.getStartTime()) + .endTime(discountVO.getEndTime()) + .validTime(discountVO.getValidTime()) + .targetCount(discountVO.getTarget()) + .build(), + PayDiscountEntity.builder() + .source(source) + .channel(channel) + .goodsId(goodsId) + .goodsName(trialBalance.getGoodsName()) + .originalPrice(trialBalance.getOriginalPrice()) + .deductionPrice(trialBalance.getDeductionPrice()) + .payPrice(trialBalance.getPayPrice()) + .outTradeNo(outTradeNo) + .notifyConfigVO( + // 构建回调通知对象 + NotifyConfigVO.builder() + .notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType())) + .notifyMQ(notifyConfigVO.getNotifyMQ()) + .notifyUrl(notifyConfigVO.getNotifyUrl()) + .build()) + .build()); + + log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity)); + + /* ---------- 6. 构建成功返回 ---------- */ + return buildSuccessResp(marketPayOrderEntity); + } catch (AppException e) { + // 可预期的业务异常(如活动已过期、优惠额度不足等) + log.error("拼团交易锁单业务异常 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(), + JSON.toJSONString(lockMarketPayOrderRequestDTO), e); + return Response.builder() + .code(e.getCode()) + .info(e.getInfo()) + .build(); + } catch (Exception e) { + // 系统异常(NPE、RPC 调用失败等) + log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(), + JSON.toJSONString(lockMarketPayOrderRequestDTO), e); + return Response.builder() + .code(ResponseCode.UN_ERROR.getCode()) + .info(ResponseCode.UN_ERROR.getInfo()) + .build(); + } + } + + /** + * 拼团交易结算 + * @param requestDTO 结算商品信息 + * @return + */ + @Override + public Response settlementMarketPayOrder( + @RequestBody SettlementMarketPayOrderRequestDTO requestDTO) { + log.info("营销交易组队结算开始: requestDTO={}", JSON.toJSONString(requestDTO)); + + // —— 1. 参数校验 —— + if (StringUtils.isAnyBlank(requestDTO.getUserId(), requestDTO.getSource(), requestDTO.getChannel(), requestDTO.getOutTradeNo()) + || requestDTO.getOutTradeTime() == null) { + return Response.builder() + .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) + .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) + .build(); + } + + try { + // —— 2. 调用结算服务 —— + TradePaySuccessEntity successEntity = new TradePaySuccessEntity(); + BeanUtils.copyProperties(requestDTO, successEntity); + + //开始结算 + TradePaySettlementEntity settlement = tradeSettlementOrderService.settlementMarketPayOrder(successEntity); + + // —— 3. 构造返回 DTO —— + SettlementMarketPayOrderResponseDTO responseDTO = new SettlementMarketPayOrderResponseDTO(); + BeanUtils.copyProperties(settlement, responseDTO); + + Response resp = + Response.builder() + .code(ResponseCode.SUCCESS.getCode()) + .info(ResponseCode.SUCCESS.getInfo()) + .data(responseDTO) + .build(); + + log.info("营销交易组队结算完成: userId={} outTradeNo={} response={}", + requestDTO.getUserId(), + requestDTO.getOutTradeNo(), + JSON.toJSONString(resp)); + + return resp; + + } catch (AppException e) { + log.error("营销交易组队结算业务异常: userId={} requestDTO={}", + requestDTO.getUserId(), + JSON.toJSONString(requestDTO), e); + return Response.builder() + .code(e.getCode()) + .info(e.getInfo()) + .build(); + } catch (Exception e) { + log.error("营销交易组队结算失败: userId={} requestDTO={}", + requestDTO.getUserId(), + JSON.toJSONString(requestDTO), e); + return Response.builder() + .code(ResponseCode.UN_ERROR.getCode()) + .info(ResponseCode.UN_ERROR.getInfo()) + .build(); + } + } + + + /** + * 构建成功响应体,避免重复写样板代码 + */ + private Response buildSuccessResp(MarketPayOrderEntity entity) { + return Response.builder() + .code(ResponseCode.SUCCESS.getCode()) + .info(ResponseCode.SUCCESS.getInfo()) + .data(LockMarketPayOrderResponseDTO.builder() + .orderId(entity.getOrderId()) + .originalPrice(entity.getOriginalPrice()) + .deductionPrice(entity.getDeductionPrice()) + .payPrice(entity.getPayPrice()) + .teamId(entity.getTeamId()) + .tradeOrderStatus(entity.getTradeOrderStatusEnumVO().getCode()) + .build()) + .build(); + } + + /** + * 用户退单接口 + * @param requestDTO 退单请求信息 + * @return + */ + @Override + public Response refundMarketPayOrder(@RequestBody RefundMarketPayOrderRequestDTO requestDTO) { + try { + log.info("营销拼团退单开始:{} outTradeNo:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo()); + + if (StringUtils.isBlank(requestDTO.getUserId()) || StringUtils.isBlank(requestDTO.getOutTradeNo()) || StringUtils.isBlank(requestDTO.getSource()) || StringUtils.isBlank(requestDTO.getChannel())) { + return Response.builder() + .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) + .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) + .build(); + } + + // 1. 退单服务 + TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(TradeRefundCommandEntity.builder() + .userId(requestDTO.getUserId()) + .outTradeNo(requestDTO.getOutTradeNo()) + .source(requestDTO.getSource()) + .channel(requestDTO.getChannel()) + .build()); + + RefundMarketPayOrderResponseDTO responseDTO = RefundMarketPayOrderResponseDTO.builder() + .userId(tradeRefundBehaviorEntity.getUserId()) + .orderId(tradeRefundBehaviorEntity.getOrderId()) + .teamId(tradeRefundBehaviorEntity.getTeamId()) + .code(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getCode()) + .info(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getInfo()) + .build(); + + // 返回结果 + Response response = Response.builder() + .code(ResponseCode.SUCCESS.getCode()) + .info(ResponseCode.SUCCESS.getInfo()) + .data(responseDTO) + .build(); + + log.info("营销拼团退单完成:{} outTradeNo:{} response:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo(), JSON.toJSONString(response)); + + return response; + } catch (AppException e) { + log.error("营销拼团退单异常:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e); + return Response.builder() + .code(e.getCode()) + .info(e.getInfo()) + .build(); + } catch (Exception e) { + log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e); + return Response.builder() + .code(ResponseCode.UN_ERROR.getCode()) + .info(ResponseCode.UN_ERROR.getInfo()) + .build(); + } + } +} diff --git a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java index fbd97be..99c5548 100644 --- a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java +++ b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java @@ -16,6 +16,7 @@ import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO; import edu.whut.domain.trade.service.ITradeLockOrderService; import edu.whut.domain.trade.service.ITradeRefundOrderService; import edu.whut.domain.trade.service.ITradeSettlementOrderService; +import edu.whut.trigger.basic.MarketTradeService; import edu.whut.types.enums.ResponseCode; import edu.whut.types.exception.AppException; import lombok.RequiredArgsConstructor; @@ -43,147 +44,16 @@ import java.util.Objects; @CrossOrigin("*") @RequiredArgsConstructor @RequestMapping("/api/v1/gbm/trade") -public class MarketTradeController implements IMarketTradeService { +public class MarketTradeController { - //价格试算 - private final IIndexGroupBuyMarketService indexGroupBuyMarketService; - //拼团锁单 - private final ITradeLockOrderService tradeOrderService; - //拼团结算 - private final ITradeSettlementOrderService tradeSettlementOrderService; - //退单 - private final ITradeRefundOrderService tradeRefundOrderService; + private final MarketTradeService marketTradeService; /** * 锁定营销预支付订单(拼团 / 普通优惠) */ @PostMapping("/lock_market_pay_order") - @Override public Response lockMarketPayOrder(@RequestBody LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO) { - try { - /* ---------- 1. 基础参数提取与校验 ---------- */ - String userId = lockMarketPayOrderRequestDTO.getUserId(); - String source = lockMarketPayOrderRequestDTO.getSource(); - String channel = lockMarketPayOrderRequestDTO.getChannel(); - String goodsId = lockMarketPayOrderRequestDTO.getGoodsId(); - Long activityId = lockMarketPayOrderRequestDTO.getActivityId(); - String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo(); - String teamId = lockMarketPayOrderRequestDTO.getTeamId(); //可为空,对应参与拼团or创建拼团 - LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO(); - - log.info("营销锁单开始执行:拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO)); - - // 空值校验(任何一个关键字段为空则直接返回错误) - boolean httpWithoutUrl = - "HTTP".equals(notifyConfigVO.getNotifyType()) - && StringUtils.isBlank(notifyConfigVO.getNotifyUrl()); - - if (StringUtils.isAnyBlank(userId, source, channel, goodsId) - || activityId == null - || httpWithoutUrl) { - return Response.builder() - .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) - .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) - .build(); - } - - - /* ---------- 2. 查询是否已存在未支付锁单 ---------- */ - MarketPayOrderEntity marketPayOrderEntity = - tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo); - if (marketPayOrderEntity != null && TradeOrderStatusEnumVO.CREATE.equals(marketPayOrderEntity.getTradeOrderStatusEnumVO())) { - // 若已锁单未支付,直接返回原锁单信息(幂等) - return buildSuccessResp(marketPayOrderEntity); - } - - /* ---------- 3. 拼团目标人数校验 可能前端显示可参与,实际点击之后人数已满 ---------- */ - //(teamId 不为空表示 参与拼团 ) - if (StringUtils.isNotBlank(teamId)) { - // 查询当前拼团的 目标数量 已完成下单数量 锁单数量 - GroupBuyProgressVO progress = tradeOrderService.queryGroupBuyProgress(teamId); - // 如果目标人数已满,则拒绝本次锁单 目前逻辑是结算完成LockCount也不会减。 - if (progress != null && Objects.equals(progress.getTargetCount(), progress.getLockCount())) { - log.info("交易锁单拦截-拼单目标已达成 userId={} teamId={} target={} lock={}", - userId, teamId, progress.getTargetCount(), progress.getLockCount()); - return Response.builder() - .code(ResponseCode.E0006.getCode()) - .info(ResponseCode.E0006.getInfo()) - .build(); - } - } - - /* ---------- 4. 调用营销服务进行优惠试算 ---------- */ - TrialBalanceEntity trialBalance = indexGroupBuyMarketService.indexMarketTrial( - MarketProductEntity.builder() - .userId(userId) - .source(source) - .channel(channel) - .goodsId(goodsId) - .activityId(activityId) - .build()); - - // 人群限定,非目前人群不允许参与活动 - if (!trialBalance.getIsVisible() || !trialBalance.getIsEnable()){ - return Response.builder() - .code(ResponseCode.E0007.getCode()) - .info(ResponseCode.E0007.getInfo()) - .build(); - } - - //获取拼团活动配置信息 - GroupBuyActivityDiscountVO discountVO = trialBalance.getGroupBuyActivityDiscountVO(); - - /* ---------- 5. 组装领域对象后调用真正的锁单 ---------- */ - marketPayOrderEntity = tradeOrderService.lockMarketPayOrder( - UserEntity.builder().userId(userId).build(), - PayActivityEntity.builder() - .teamId(teamId) - .activityId(activityId) - .activityName(discountVO.getActivityName()) - .startTime(discountVO.getStartTime()) - .endTime(discountVO.getEndTime()) - .validTime(discountVO.getValidTime()) - .targetCount(discountVO.getTarget()) - .build(), - PayDiscountEntity.builder() - .source(source) - .channel(channel) - .goodsId(goodsId) - .goodsName(trialBalance.getGoodsName()) - .originalPrice(trialBalance.getOriginalPrice()) - .deductionPrice(trialBalance.getDeductionPrice()) - .payPrice(trialBalance.getPayPrice()) - .outTradeNo(outTradeNo) - .notifyConfigVO( - // 构建回调通知对象 - NotifyConfigVO.builder() - .notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType())) - .notifyMQ(notifyConfigVO.getNotifyMQ()) - .notifyUrl(notifyConfigVO.getNotifyUrl()) - .build()) - .build()); - - log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity)); - - /* ---------- 6. 构建成功返回 ---------- */ - return buildSuccessResp(marketPayOrderEntity); - } catch (AppException e) { - // 可预期的业务异常(如活动已过期、优惠额度不足等) - log.error("拼团交易锁单业务异常 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(), - JSON.toJSONString(lockMarketPayOrderRequestDTO), e); - return Response.builder() - .code(e.getCode()) - .info(e.getInfo()) - .build(); - } catch (Exception e) { - // 系统异常(NPE、RPC 调用失败等) - log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(), - JSON.toJSONString(lockMarketPayOrderRequestDTO), e); - return Response.builder() - .code(ResponseCode.UN_ERROR.getCode()) - .info(ResponseCode.UN_ERROR.getInfo()) - .build(); - } + return marketTradeService.lockMarketPayOrder(lockMarketPayOrderRequestDTO); } /** @@ -192,140 +62,18 @@ public class MarketTradeController implements IMarketTradeService { * @return */ @PostMapping("/settlement_market_pay_order") - @Override - public Response settlementMarketPayOrder( - @RequestBody SettlementMarketPayOrderRequestDTO requestDTO) { - log.info("营销交易组队结算开始: requestDTO={}", JSON.toJSONString(requestDTO)); - - // —— 1. 参数校验 —— - if (StringUtils.isAnyBlank(requestDTO.getUserId(), requestDTO.getSource(), requestDTO.getChannel(), requestDTO.getOutTradeNo()) - || requestDTO.getOutTradeTime() == null) { - return Response.builder() - .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) - .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) - .build(); - } - - try { - // —— 2. 调用结算服务 —— - TradePaySuccessEntity successEntity = new TradePaySuccessEntity(); - BeanUtils.copyProperties(requestDTO, successEntity); - - //开始结算 - TradePaySettlementEntity settlement = tradeSettlementOrderService.settlementMarketPayOrder(successEntity); - - // —— 3. 构造返回 DTO —— - SettlementMarketPayOrderResponseDTO responseDTO = new SettlementMarketPayOrderResponseDTO(); - BeanUtils.copyProperties(settlement, responseDTO); - - Response resp = - Response.builder() - .code(ResponseCode.SUCCESS.getCode()) - .info(ResponseCode.SUCCESS.getInfo()) - .data(responseDTO) - .build(); - - log.info("营销交易组队结算完成: userId={} outTradeNo={} response={}", - requestDTO.getUserId(), - requestDTO.getOutTradeNo(), - JSON.toJSONString(resp)); - - return resp; - - } catch (AppException e) { - log.error("营销交易组队结算业务异常: userId={} requestDTO={}", - requestDTO.getUserId(), - JSON.toJSONString(requestDTO), e); - return Response.builder() - .code(e.getCode()) - .info(e.getInfo()) - .build(); - } catch (Exception e) { - log.error("营销交易组队结算失败: userId={} requestDTO={}", - requestDTO.getUserId(), - JSON.toJSONString(requestDTO), e); - return Response.builder() - .code(ResponseCode.UN_ERROR.getCode()) - .info(ResponseCode.UN_ERROR.getInfo()) - .build(); - } + public Response settlementMarketPayOrder(@RequestBody SettlementMarketPayOrderRequestDTO requestDTO) { + return marketTradeService.settlementMarketPayOrder(requestDTO); } - /** - * 构建成功响应体,避免重复写样板代码 - */ - private Response buildSuccessResp(MarketPayOrderEntity entity) { - return Response.builder() - .code(ResponseCode.SUCCESS.getCode()) - .info(ResponseCode.SUCCESS.getInfo()) - .data(LockMarketPayOrderResponseDTO.builder() - .orderId(entity.getOrderId()) - .originalPrice(entity.getOriginalPrice()) - .deductionPrice(entity.getDeductionPrice()) - .payPrice(entity.getPayPrice()) - .teamId(entity.getTeamId()) - .tradeOrderStatus(entity.getTradeOrderStatusEnumVO().getCode()) - .build()) - .build(); - } - /** * 用户退单接口 * @param requestDTO 退单请求信息 * @return */ - @RequestMapping(value = "refund_market_pay_order", method = RequestMethod.POST) - @Override + @PostMapping("/refund_market_pay_order") public Response refundMarketPayOrder(@RequestBody RefundMarketPayOrderRequestDTO requestDTO) { - try { - log.info("营销拼团退单开始:{} outTradeNo:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo()); - - if (StringUtils.isBlank(requestDTO.getUserId()) || StringUtils.isBlank(requestDTO.getOutTradeNo()) || StringUtils.isBlank(requestDTO.getSource()) || StringUtils.isBlank(requestDTO.getChannel())) { - return Response.builder() - .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) - .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) - .build(); - } - - // 1. 退单服务 - TradeRefundBehaviorEntity tradeRefundBehaviorEntity = tradeRefundOrderService.refundOrder(TradeRefundCommandEntity.builder() - .userId(requestDTO.getUserId()) - .outTradeNo(requestDTO.getOutTradeNo()) - .source(requestDTO.getSource()) - .channel(requestDTO.getChannel()) - .build()); - - RefundMarketPayOrderResponseDTO responseDTO = RefundMarketPayOrderResponseDTO.builder() - .userId(tradeRefundBehaviorEntity.getUserId()) - .orderId(tradeRefundBehaviorEntity.getOrderId()) - .teamId(tradeRefundBehaviorEntity.getTeamId()) - .code(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getCode()) - .info(tradeRefundBehaviorEntity.getTradeRefundBehaviorEnum().getInfo()) - .build(); - - // 返回结果 - Response response = Response.builder() - .code(ResponseCode.SUCCESS.getCode()) - .info(ResponseCode.SUCCESS.getInfo()) - .data(responseDTO) - .build(); - - log.info("营销拼团退单完成:{} outTradeNo:{} response:{}", requestDTO.getUserId(), requestDTO.getOutTradeNo(), JSON.toJSONString(response)); - - return response; - } catch (AppException e) { - log.error("营销拼团退单异常:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e); - return Response.builder() - .code(e.getCode()) - .info(e.getInfo()) - .build(); - } catch (Exception e) { - log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e); - return Response.builder() - .code(ResponseCode.UN_ERROR.getCode()) - .info(ResponseCode.UN_ERROR.getInfo()) - .build(); - } + return marketTradeService.refundMarketPayOrder(requestDTO); } } diff --git a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/rpc/MarketTradeDubboService.java b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/rpc/MarketTradeDubboService.java index 937dbfb..892cea1 100644 --- a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/rpc/MarketTradeDubboService.java +++ b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/rpc/MarketTradeDubboService.java @@ -3,31 +3,29 @@ package edu.whut.trigger.rpc; import edu.whut.api.IMarketTradeService; import edu.whut.api.dto.*; import edu.whut.api.response.Response; -import edu.whut.trigger.http.MarketTradeController; +import edu.whut.trigger.basic.MarketTradeService; import org.apache.dubbo.config.annotation.DubboService; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; @DubboService(version = "1.0.0") // 关键注解 @RequiredArgsConstructor -public class MarketTradeDubboService implements IMarketTradeService { +public class MarketTradeDubboService { - private final MarketTradeController delegate; // 复用现有业务 + private final MarketTradeService marketTradeService; // 复用现有业务 - @Override public Response lockMarketPayOrder( LockMarketPayOrderRequestDTO dto) { - return delegate.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑 + return marketTradeService.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑 } - @Override public Response settlementMarketPayOrder( SettlementMarketPayOrderRequestDTO dto) { - return delegate.settlementMarketPayOrder(dto); + return marketTradeService.settlementMarketPayOrder(dto); } - @Override public Response refundMarketPayOrder( RefundMarketPayOrderRequestDTO dto) { - return delegate.refundMarketPayOrder(dto); + return marketTradeService.refundMarketPayOrder(dto); } } diff --git a/group-buying-sys-types/src/main/java/edu/whut/types/exception/AppException.java b/group-buying-sys-types/src/main/java/edu/whut/types/exception/AppException.java index ddb29a1..570d711 100644 --- a/group-buying-sys-types/src/main/java/edu/whut/types/exception/AppException.java +++ b/group-buying-sys-types/src/main/java/edu/whut/types/exception/AppException.java @@ -7,46 +7,46 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) @Data public class AppException extends RuntimeException { - private static final long serialVersionUID = 5317680961212299217L; - /** 异常码 */ - private String code; - - /** 异常信息 */ - private String info; + private final String code; + private final String info; public AppException(String code) { + super(code); // 至少给个非空 message this.code = code; + this.info = null; } - public AppException(ResponseCode responseCode) { - this.code = responseCode.getCode(); - this.info = responseCode.getInfo(); + public AppException(ResponseCode rc) { + super(rc.getInfo()); // 关键:作为 Throwable 的 message + this.code = rc.getCode(); + this.info = rc.getInfo(); } public AppException(String code, Throwable cause) { + super(code, cause); // 用父类带 cause 的构造器 this.code = code; - super.initCause(cause); + this.info = null; } public AppException(String code, String message) { + super(message); this.code = code; this.info = message; } public AppException(String code, String message, Throwable cause) { + super(message, cause); this.code = code; this.info = message; - super.initCause(cause); } - @Override - public String toString() { - return "edu.whut.types.exception.AppException{" + - "code='" + code + '\'' + - ", info='" + info + '\'' + - '}'; + @Override public String getMessage() { + return (info != null) ? info : super.getMessage(); } + @Override public String toString() { + return "AppException{code='" + code + "', info='" + info + "'}"; + } }