Commit 1cd9085c5938bdad7312a80bdadb3d41dc8afe2d
1 parent
0247fd5c
pay: PayNotifyJob 增加多租户的支持
Showing
12 changed files
with
123 additions
and
73 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
| ... | ... | @@ -2,6 +2,10 @@ package cn.iocoder.yudao.framework.tenant.core.util; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 4 | 4 | |
| 5 | +import java.util.Map; | |
| 6 | + | |
| 7 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; | |
| 8 | + | |
| 5 | 9 | /** |
| 6 | 10 | * 多租户 Util |
| 7 | 11 | * |
| ... | ... | @@ -32,4 +36,16 @@ public class TenantUtils { |
| 32 | 36 | } |
| 33 | 37 | } |
| 34 | 38 | |
| 39 | + /** | |
| 40 | + * 将多租户编号,添加到 header 中 | |
| 41 | + * | |
| 42 | + * @param headers HTTP 请求 headers | |
| 43 | + */ | |
| 44 | + public static void addTenantHeader(Map<String, String> headers) { | |
| 45 | + Long tenantId = TenantContextHolder.getTenantId(); | |
| 46 | + if (tenantId != null) { | |
| 47 | + headers.put(HEADER_TENANT_ID, tenantId.toString()); | |
| 48 | + } | |
| 49 | + } | |
| 50 | + | |
| 35 | 51 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 7 | 7 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 8 | +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | |
| 8 | 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 9 | 10 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderGetCreateInfoRespVO; |
| 10 | 11 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.TradeOrderPageReqVO; |
| ... | ... | @@ -33,7 +34,7 @@ public class AppTradeOrderController { |
| 33 | 34 | @GetMapping("/get-create-info") |
| 34 | 35 | @ApiOperation("基于商品,确认创建订单") |
| 35 | 36 | @PreAuthenticated |
| 36 | - public CommonResult<AppTradeOrderGetCreateInfoRespVO> getTradeOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) { | |
| 37 | + public CommonResult<AppTradeOrderGetCreateInfoRespVO> getOrderCreateInfo(AppTradeOrderCreateReqVO createReqVO) { | |
| 37 | 38 | // return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId)); |
| 38 | 39 | return null; |
| 39 | 40 | } |
| ... | ... | @@ -41,8 +42,8 @@ public class AppTradeOrderController { |
| 41 | 42 | @PostMapping("/create") |
| 42 | 43 | @ApiOperation("创建订单") |
| 43 | 44 | @PreAuthenticated |
| 44 | - public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, | |
| 45 | - HttpServletRequest servletRequest) { | |
| 45 | + public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, | |
| 46 | + HttpServletRequest servletRequest) { | |
| 46 | 47 | // 获取登录用户、用户 IP 地址 |
| 47 | 48 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 48 | 49 | String clientIp = ServletUtil.getClientIP(servletRequest); |
| ... | ... | @@ -51,6 +52,12 @@ public class AppTradeOrderController { |
| 51 | 52 | return CommonResult.success(orderId); |
| 52 | 53 | } |
| 53 | 54 | |
| 55 | + @PostMapping("/update-paid") | |
| 56 | + @ApiOperation(value = "更新订单为已支付", notes = "由 pay-module 支付服务,进行回调,可见 PayNotifyJob") | |
| 57 | + public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) { | |
| 58 | + return null; | |
| 59 | + } | |
| 60 | + | |
| 54 | 61 | @GetMapping("/get") |
| 55 | 62 | @ApiOperation("获得交易订单") |
| 56 | 63 | @ApiImplicitParam(name = "tradeOrderId", value = "交易订单编号", required = true, dataTypeClass = Long.class) | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayOrderNotifyReqDTO.java
| 1 | -package cn.iocoder.yudao.module.pay.service.notify.vo; | |
| 1 | +package cn.iocoder.yudao.module.pay.api.notify.dto; | |
| 2 | 2 | |
| 3 | -import io.swagger.annotations.ApiModel; | |
| 4 | -import io.swagger.annotations.ApiModelProperty; | |
| 5 | 3 | import lombok.AllArgsConstructor; |
| 6 | 4 | import lombok.Builder; |
| 7 | 5 | import lombok.Data; |
| ... | ... | @@ -10,18 +8,26 @@ import lombok.NoArgsConstructor; |
| 10 | 8 | import javax.validation.constraints.NotEmpty; |
| 11 | 9 | import javax.validation.constraints.NotNull; |
| 12 | 10 | |
| 13 | -@ApiModel(value = "支付单的通知 Request VO", description = "业务方接入支付回调时,使用该 VO 对象") | |
| 11 | +/** | |
| 12 | + * 支付单的通知 Request DTO | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 14 | 16 | @Data |
| 15 | 17 | @Builder |
| 16 | 18 | @NoArgsConstructor |
| 17 | 19 | @AllArgsConstructor |
| 18 | -public class PayNotifyOrderReqVO { | |
| 20 | +public class PayOrderNotifyReqDTO { | |
| 19 | 21 | |
| 20 | - @ApiModelProperty(value = "商户订单编号", required = true, example = "10") | |
| 22 | + /** | |
| 23 | + * 商户订单编号 | |
| 24 | + */ | |
| 21 | 25 | @NotEmpty(message = "商户订单号不能为空") |
| 22 | 26 | private String merchantOrderId; |
| 23 | 27 | |
| 24 | - @ApiModelProperty(value = "支付订单编号", required = true, example = "20") | |
| 28 | + /** | |
| 29 | + * 支付订单编号 | |
| 30 | + */ | |
| 25 | 31 | @NotNull(message = "支付订单编号不能为空") |
| 26 | 32 | private Long payOrderId; |
| 27 | 33 | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayRefundNotifyReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.api.notify.dto; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Builder; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.NoArgsConstructor; | |
| 7 | + | |
| 8 | +import javax.validation.constraints.NotEmpty; | |
| 9 | +import javax.validation.constraints.NotNull; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 退款单的通知 Request DTO | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +@Builder | |
| 18 | +@NoArgsConstructor | |
| 19 | +@AllArgsConstructor | |
| 20 | +public class PayRefundNotifyReqDTO { | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 商户退款单编号 | |
| 24 | + */ | |
| 25 | + @NotEmpty(message = "商户退款单编号不能为空") | |
| 26 | + private String merchantOrderId; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 支付退款编号 | |
| 30 | + */ | |
| 31 | + @NotNull(message = "支付退款编号不能为空") | |
| 32 | + private Long payRefundId; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 退款状态 | |
| 36 | + * | |
| 37 | + * (成功,失败) TODO 芋艿:枚举 | |
| 38 | + */ | |
| 39 | + @NotNull(message = "退款状态不能为空") | |
| 40 | + private Integer status; | |
| 41 | + | |
| 42 | +} | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/package-info.java
0 → 100644
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/notify/PayNotifyJob.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/package-info.java
| ... | ... | @@ -2,8 +2,8 @@ |
| 2 | 2 | * pay 模块,我们放支付业务,提供业务的支付能力。 |
| 3 | 3 | * 例如说:商户、应用、支付、退款等等 |
| 4 | 4 | * |
| 5 | - * 1. Controller URL:以 /member/ 开头,避免和其它 Module 冲突 | |
| 6 | - * 2. DataObject 表名:以 member_ 开头,方便在数据库中区分 | |
| 5 | + * 1. Controller URL:以 /pay/ 开头,避免和其它 Module 冲突 | |
| 6 | + * 2. DataObject 表名:以 pay_ 开头,方便在数据库中区分 | |
| 7 | 7 | * |
| 8 | 8 | * 注意,由于 Pay 模块和 Trade 模块,容易重名,所以类名都加载 Pay 的前缀~ |
| 9 | 9 | */ | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
| ... | ... | @@ -2,7 +2,13 @@ package cn.iocoder.yudao.module.pay.service.notify; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.exceptions.ExceptionUtil; |
| 5 | +import cn.hutool.http.HttpResponse; | |
| 5 | 6 | import cn.hutool.http.HttpUtil; |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.date.DateUtils; | |
| 9 | +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | |
| 10 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 11 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 6 | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; |
| 7 | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; |
| 8 | 14 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| ... | ... | @@ -13,11 +19,8 @@ import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; |
| 13 | 19 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; |
| 14 | 20 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 15 | 21 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 16 | -import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO; | |
| 17 | -import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO; | |
| 18 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 19 | -import cn.iocoder.yudao.framework.common.util.date.DateUtils; | |
| 20 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 22 | +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | |
| 23 | +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; | |
| 21 | 24 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 22 | 25 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 23 | 26 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -30,7 +33,9 @@ import org.springframework.transaction.annotation.Transactional; |
| 30 | 33 | import javax.annotation.Resource; |
| 31 | 34 | import javax.validation.Valid; |
| 32 | 35 | import java.time.LocalDateTime; |
| 36 | +import java.util.HashMap; | |
| 33 | 37 | import java.util.List; |
| 38 | +import java.util.Map; | |
| 34 | 39 | import java.util.Objects; |
| 35 | 40 | import java.util.concurrent.CountDownLatch; |
| 36 | 41 | import java.util.concurrent.TimeUnit; |
| ... | ... | @@ -164,8 +169,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 164 | 169 | // 校验,当前任务是否已经被通知过 |
| 165 | 170 | // 虽然已经通过分布式加锁,但是可能同时满足通知的条件,然后都去获得锁。此时,第一个执行完后,第二个还是能拿到锁,然后会再执行一次。 |
| 166 | 171 | PayNotifyTaskDO dbTask = payNotifyTaskCoreMapper.selectById(task.getId()); |
| 167 | - if (DateUtils.afterNow(dbTask.getNextNotifyTime())) { | |
| 168 | - log.info("[executeNotify][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", JsonUtils.toJsonString(dbTask)); | |
| 172 | + if (LocalDateTimeUtils.afterNow(dbTask.getNextNotifyTime())) { | |
| 173 | + log.info("[executeNotifySync][dbTask({}) 任务被忽略,原因是未到达下次通知时间,可能是因为并发执行了]", | |
| 174 | + JsonUtils.toJsonString(dbTask)); | |
| 169 | 175 | return; |
| 170 | 176 | } |
| 171 | 177 | |
| ... | ... | @@ -185,11 +191,12 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 185 | 191 | invokeException = e; |
| 186 | 192 | } |
| 187 | 193 | |
| 188 | - // 处理 | |
| 189 | - Integer newStatus = this.processNotifyResult(task, invokeResult, invokeException); | |
| 194 | + // 处理结果 | |
| 195 | + Integer newStatus = processNotifyResult(task, invokeResult, invokeException); | |
| 190 | 196 | |
| 191 | 197 | // 记录 PayNotifyLog 日志 |
| 192 | - String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : JsonUtils.toJsonString(invokeResult); | |
| 198 | + String response = invokeException != null ? ExceptionUtil.getRootCauseMessage(invokeException) : | |
| 199 | + JsonUtils.toJsonString(invokeResult); | |
| 193 | 200 | payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) |
| 194 | 201 | .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); |
| 195 | 202 | } |
| ... | ... | @@ -201,22 +208,28 @@ public class PayNotifyServiceImpl implements PayNotifyService { |
| 201 | 208 | * @return HTTP 响应 |
| 202 | 209 | */ |
| 203 | 210 | private CommonResult<?> executeNotifyInvoke(PayNotifyTaskDO task) { |
| 204 | - // 拼接参数 | |
| 211 | + // 拼接 body 参数 | |
| 205 | 212 | Object request; |
| 206 | 213 | if (Objects.equals(task.getType(), PayNotifyTypeEnum.ORDER.getType())) { |
| 207 | - request = PayNotifyOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId()) | |
| 214 | + request = PayOrderNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) | |
| 208 | 215 | .payOrderId(task.getDataId()).build(); |
| 209 | 216 | } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { |
| 210 | - request = PayRefundOrderReqVO.builder().merchantOrderId(task.getMerchantOrderId()) | |
| 217 | + request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) | |
| 211 | 218 | .payRefundId(task.getDataId()).build(); |
| 212 | 219 | } else { |
| 213 | 220 | throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task)); |
| 214 | 221 | } |
| 215 | - // 请求地址 | |
| 216 | - String response = HttpUtil.post(task.getNotifyUrl(), JsonUtils.toJsonString(request), | |
| 217 | - (int) NOTIFY_TIMEOUT_MILLIS); | |
| 218 | - // 解析结果 | |
| 219 | - return JsonUtils.parseObject(response, CommonResult.class); | |
| 222 | + // 拼接 header 参数 | |
| 223 | + Map<String, String> headers = new HashMap<>(); | |
| 224 | + TenantUtils.addTenantHeader(headers); | |
| 225 | + | |
| 226 | + // 发起请求 | |
| 227 | + try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl()) | |
| 228 | + .body(JsonUtils.toJsonString(request)).addHeaders(headers) | |
| 229 | + .timeout((int) NOTIFY_TIMEOUT_MILLIS).execute()) { | |
| 230 | + // 解析结果 | |
| 231 | + return JsonUtils.parseObject(response.body(), CommonResult.class); | |
| 232 | + } | |
| 220 | 233 | } |
| 221 | 234 | |
| 222 | 235 | /** | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.pay.service.notify.vo; | |
| 2 | - | |
| 3 | -import io.swagger.annotations.ApiModel; | |
| 4 | -import io.swagger.annotations.ApiModelProperty; | |
| 5 | -import lombok.AllArgsConstructor; | |
| 6 | -import lombok.Builder; | |
| 7 | -import lombok.Data; | |
| 8 | -import lombok.NoArgsConstructor; | |
| 9 | - | |
| 10 | -import javax.validation.constraints.NotEmpty; | |
| 11 | -import javax.validation.constraints.NotNull; | |
| 12 | - | |
| 13 | -@ApiModel(value = "退款单的通知 Request VO", description = "业务方接入退款回调时,使用该 VO 对象") | |
| 14 | -@Data | |
| 15 | -@Builder | |
| 16 | -@NoArgsConstructor | |
| 17 | -@AllArgsConstructor | |
| 18 | -public class PayRefundOrderReqVO { | |
| 19 | - | |
| 20 | - @ApiModelProperty(value = "商户退款单编号", required = true, example = "10") | |
| 21 | - @NotEmpty(message = "商户退款单编号不能为空") | |
| 22 | - private String merchantOrderId; | |
| 23 | - | |
| 24 | - @ApiModelProperty(value = "支付退款编号", required = true, example = "20") | |
| 25 | - @NotNull(message = "支付退款编号不能为空") | |
| 26 | - private Long payRefundId; | |
| 27 | - | |
| 28 | - @ApiModelProperty(value = "退款状态(成功,失败)", required = true, example = "10") | |
| 29 | - private Integer status; | |
| 30 | - | |
| 31 | -} |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/package-info.java deleted
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.pay.service; |
yudao-server/src/main/java/cn/iocoder/yudao/module/shop/controller/app/AppShopOrderController.java
| 1 | 1 | package cn.iocoder.yudao.module.shop.controller.app; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.pay.service.notify.vo.PayNotifyOrderReqVO; | |
| 5 | -import cn.iocoder.yudao.module.pay.service.notify.vo.PayRefundOrderReqVO; | |
| 4 | +import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | |
| 5 | +import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; | |
| 6 | 6 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 7 | 7 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 8 | 8 | import cn.iocoder.yudao.module.pay.util.PaySeqUtils; |
| ... | ... | @@ -58,14 +58,14 @@ public class AppShopOrderController { |
| 58 | 58 | |
| 59 | 59 | @PostMapping("/pay-notify") |
| 60 | 60 | @ApiOperation("支付回调") |
| 61 | - public CommonResult<Boolean> payNotify(@RequestBody @Valid PayNotifyOrderReqVO reqVO) { | |
| 61 | + public CommonResult<Boolean> payNotify(@RequestBody @Valid PayOrderNotifyReqDTO reqVO) { | |
| 62 | 62 | log.info("[payNotify][回调成功]"); |
| 63 | 63 | return success(true); |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | 66 | @PostMapping("/refund-notify") |
| 67 | 67 | @ApiOperation("退款回调") |
| 68 | - public CommonResult<Boolean> refundNotify(@RequestBody @Valid PayRefundOrderReqVO reqVO) { | |
| 68 | + public CommonResult<Boolean> refundNotify(@RequestBody @Valid PayRefundNotifyReqDTO reqVO) { | |
| 69 | 69 | log.info("[refundNotify][回调成功]"); |
| 70 | 70 | return success(true); |
| 71 | 71 | } | ... | ... |