8.8 解耦HTTP和RPC

This commit is contained in:
zhangsan 2025-08-08 14:00:46 +08:00
parent 33d803dd44
commit 72027eefa6
7 changed files with 351 additions and 291 deletions

View File

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

View File

@ -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");

View File

@ -26,7 +26,7 @@ public class TradeLockRuleFilterFactory {
private static final String teamStockKey = "group_buy_market_team_stock_key_";
/**
* 组装责任链
* 组装责任链 先活动有效性校验=用户参与活动次数校验=抢占库存校验
* 通过 Spring @Bean 暴露外部只需注入 BusinessLinkedList 即可调用 apply
*/
@Bean("tradeRuleFilter")

View File

@ -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<LockMarketPayOrderResponseDTO> 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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
// 系统异常NPERPC 调用失败等
log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
return Response.<LockMarketPayOrderResponseDTO>builder()
.code(ResponseCode.UN_ERROR.getCode())
.info(ResponseCode.UN_ERROR.getInfo())
.build();
}
}
/**
* 拼团交易结算
* @param requestDTO 结算商品信息
* @return
*/
@Override
public Response<SettlementMarketPayOrderResponseDTO> 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.<SettlementMarketPayOrderResponseDTO>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<SettlementMarketPayOrderResponseDTO> resp =
Response.<SettlementMarketPayOrderResponseDTO>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.<SettlementMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
log.error("营销交易组队结算失败: userId={} requestDTO={}",
requestDTO.getUserId(),
JSON.toJSONString(requestDTO), e);
return Response.<SettlementMarketPayOrderResponseDTO>builder()
.code(ResponseCode.UN_ERROR.getCode())
.info(ResponseCode.UN_ERROR.getInfo())
.build();
}
}
/**
* 构建成功响应体避免重复写样板代码
*/
private Response<LockMarketPayOrderResponseDTO> buildSuccessResp(MarketPayOrderEntity entity) {
return Response.<LockMarketPayOrderResponseDTO>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<RefundMarketPayOrderResponseDTO> 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.<RefundMarketPayOrderResponseDTO>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<RefundMarketPayOrderResponseDTO> response = Response.<RefundMarketPayOrderResponseDTO>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.<RefundMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
return Response.<RefundMarketPayOrderResponseDTO>builder()
.code(ResponseCode.UN_ERROR.getCode())
.info(ResponseCode.UN_ERROR.getInfo())
.build();
}
}
}

View File

@ -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<LockMarketPayOrderResponseDTO> 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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>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.<LockMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
// 系统异常NPERPC 调用失败等
log.error("拼团交易锁单未知错误 userId={} req={}", lockMarketPayOrderRequestDTO.getUserId(),
JSON.toJSONString(lockMarketPayOrderRequestDTO), e);
return Response.<LockMarketPayOrderResponseDTO>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<SettlementMarketPayOrderResponseDTO> 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.<SettlementMarketPayOrderResponseDTO>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<SettlementMarketPayOrderResponseDTO> resp =
Response.<SettlementMarketPayOrderResponseDTO>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.<SettlementMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
log.error("营销交易组队结算失败: userId={} requestDTO={}",
requestDTO.getUserId(),
JSON.toJSONString(requestDTO), e);
return Response.<SettlementMarketPayOrderResponseDTO>builder()
.code(ResponseCode.UN_ERROR.getCode())
.info(ResponseCode.UN_ERROR.getInfo())
.build();
}
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(@RequestBody SettlementMarketPayOrderRequestDTO requestDTO) {
return marketTradeService.settlementMarketPayOrder(requestDTO);
}
/**
* 构建成功响应体避免重复写样板代码
*/
private Response<LockMarketPayOrderResponseDTO> buildSuccessResp(MarketPayOrderEntity entity) {
return Response.<LockMarketPayOrderResponseDTO>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<RefundMarketPayOrderResponseDTO> 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.<RefundMarketPayOrderResponseDTO>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<RefundMarketPayOrderResponseDTO> response = Response.<RefundMarketPayOrderResponseDTO>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.<RefundMarketPayOrderResponseDTO>builder()
.code(e.getCode())
.info(e.getInfo())
.build();
} catch (Exception e) {
log.error("营销拼团退单失败:{} RefundMarketPayOrderRequestDTO:{}", requestDTO.getUserId(), JSON.toJSONString(requestDTO), e);
return Response.<RefundMarketPayOrderResponseDTO>builder()
.code(ResponseCode.UN_ERROR.getCode())
.info(ResponseCode.UN_ERROR.getInfo())
.build();
}
return marketTradeService.refundMarketPayOrder(requestDTO);
}
}

View File

@ -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<LockMarketPayOrderResponseDTO> lockMarketPayOrder(
LockMarketPayOrderRequestDTO dto) {
return delegate.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑
return marketTradeService.lockMarketPayOrder(dto); // 直接委托原 Controller 逻辑
}
@Override
public Response<SettlementMarketPayOrderResponseDTO> settlementMarketPayOrder(
SettlementMarketPayOrderRequestDTO dto) {
return delegate.settlementMarketPayOrder(dto);
return marketTradeService.settlementMarketPayOrder(dto);
}
@Override
public Response<RefundMarketPayOrderResponseDTO> refundMarketPayOrder(
RefundMarketPayOrderRequestDTO dto) {
return delegate.refundMarketPayOrder(dto);
return marketTradeService.refundMarketPayOrder(dto);
}
}

View File

@ -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 + "'}";
}
}