Commit c89accbf060d4828601be1fba35a3594ef078ab2
1 parent
2df46a7c
完成支付通知的逻辑
Showing
4 changed files
with
102 additions
and
23 deletions
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/notify/PayNotifyLogDO.java
| @@ -3,9 +3,7 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify; | @@ -3,9 +3,7 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify; | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum; | 3 | import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 5 | import com.baomidou.mybatisplus.annotation.TableName; | 5 | import com.baomidou.mybatisplus.annotation.TableName; |
| 6 | -import lombok.Data; | ||
| 7 | -import lombok.EqualsAndHashCode; | ||
| 8 | -import lombok.experimental.Accessors; | 6 | +import lombok.*; |
| 9 | 7 | ||
| 10 | /** | 8 | /** |
| 11 | * 商户支付、退款等的通知 Log | 9 | * 商户支付、退款等的通知 Log |
| @@ -16,7 +14,9 @@ import lombok.experimental.Accessors; | @@ -16,7 +14,9 @@ import lombok.experimental.Accessors; | ||
| 16 | @TableName("pay_notify_log") | 14 | @TableName("pay_notify_log") |
| 17 | @Data | 15 | @Data |
| 18 | @EqualsAndHashCode(callSuper = true) | 16 | @EqualsAndHashCode(callSuper = true) |
| 19 | -@Accessors(chain = true) | 17 | +@Builder |
| 18 | +@NoArgsConstructor | ||
| 19 | +@AllArgsConstructor | ||
| 20 | public class PayNotifyLogDO extends BaseDO { | 20 | public class PayNotifyLogDO extends BaseDO { |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| @@ -24,13 +24,15 @@ public class PayNotifyLogDO extends BaseDO { | @@ -24,13 +24,15 @@ public class PayNotifyLogDO extends BaseDO { | ||
| 24 | */ | 24 | */ |
| 25 | private Long id; | 25 | private Long id; |
| 26 | /** | 26 | /** |
| 27 | - * 通知编号 | 27 | + * 通知任务编号 |
| 28 | * | 28 | * |
| 29 | * 关联 {@link PayNotifyTaskDO#getId()} | 29 | * 关联 {@link PayNotifyTaskDO#getId()} |
| 30 | */ | 30 | */ |
| 31 | - private Long notifyId; | 31 | + private Long taskId; |
| 32 | /** | 32 | /** |
| 33 | - * 当前通知次数 | 33 | + * 第几次被通知 |
| 34 | + * | ||
| 35 | + * 对应到 {@link PayNotifyTaskDO#getNotifyTimes()} | ||
| 34 | */ | 36 | */ |
| 35 | private Integer notifyTimes; | 37 | private Integer notifyTimes; |
| 36 | /** | 38 | /** |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/notify/PayNotifyLogCoreMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyLogDO; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 5 | +import org.apache.ibatis.annotations.Mapper; | ||
| 6 | + | ||
| 7 | +@Mapper | ||
| 8 | +public interface PayNotifyLogCoreMapper extends BaseMapperX<PayNotifyLogDO> { | ||
| 9 | +} |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/notify/impl/PayNotifyCoreServiceImpl.java
| @@ -2,8 +2,10 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.notify.impl; | @@ -2,8 +2,10 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.notify.impl; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.http.HttpUtil; | 4 | import cn.hutool.http.HttpUtil; |
| 5 | +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyLogDO; | ||
| 5 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyTaskDO; | 6 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyTaskDO; |
| 6 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; | 7 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 8 | +import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyLogCoreMapper; | ||
| 7 | import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyTaskCoreMapper; | 9 | import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyTaskCoreMapper; |
| 8 | import cn.iocoder.yudao.coreservice.modules.pay.dal.redis.notify.PayNotifyLockCoreRedisDAO; | 10 | import cn.iocoder.yudao.coreservice.modules.pay.dal.redis.notify.PayNotifyLockCoreRedisDAO; |
| 9 | import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum; | 11 | import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum; |
| @@ -25,12 +27,14 @@ import org.springframework.transaction.annotation.Transactional; | @@ -25,12 +27,14 @@ import org.springframework.transaction.annotation.Transactional; | ||
| 25 | 27 | ||
| 26 | import javax.annotation.Resource; | 28 | import javax.annotation.Resource; |
| 27 | import javax.validation.Valid; | 29 | import javax.validation.Valid; |
| 30 | +import java.util.Calendar; | ||
| 28 | import java.util.Date; | 31 | import java.util.Date; |
| 29 | import java.util.List; | 32 | import java.util.List; |
| 30 | import java.util.Objects; | 33 | import java.util.Objects; |
| 31 | import java.util.concurrent.CountDownLatch; | 34 | import java.util.concurrent.CountDownLatch; |
| 32 | import java.util.concurrent.TimeUnit; | 35 | import java.util.concurrent.TimeUnit; |
| 33 | 36 | ||
| 37 | +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; | ||
| 34 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.SECOND_MILLIS; | 38 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.SECOND_MILLIS; |
| 35 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 39 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 36 | 40 | ||
| @@ -59,6 +63,8 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -59,6 +63,8 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 59 | 63 | ||
| 60 | @Resource | 64 | @Resource |
| 61 | private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper; | 65 | private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper; |
| 66 | + @Resource | ||
| 67 | + private PayNotifyLogCoreMapper payNotifyLogCoreMapper; | ||
| 62 | 68 | ||
| 63 | @Resource | 69 | @Resource |
| 64 | private ThreadPoolTaskExecutor threadPoolTaskExecutor; // TODO 芋艿:未来提供独立的线程池 | 70 | private ThreadPoolTaskExecutor threadPoolTaskExecutor; // TODO 芋艿:未来提供独立的线程池 |
| @@ -105,7 +111,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -105,7 +111,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 105 | CountDownLatch latch = new CountDownLatch(tasks.size()); | 111 | CountDownLatch latch = new CountDownLatch(tasks.size()); |
| 106 | tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> { | 112 | tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> { |
| 107 | try { | 113 | try { |
| 108 | - executeNotify(task); | 114 | + executeNotifySync(task); |
| 109 | } finally { | 115 | } finally { |
| 110 | latch.countDown(); | 116 | latch.countDown(); |
| 111 | } | 117 | } |
| @@ -141,7 +147,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -141,7 +147,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 141 | */ | 147 | */ |
| 142 | @Async | 148 | @Async |
| 143 | public void executeNotifyAsync(PayNotifyTaskDO task) { | 149 | public void executeNotifyAsync(PayNotifyTaskDO task) { |
| 144 | - self.executeNotify(task); // 使用 self,避免事务不发起 | 150 | + self.executeNotifySync(task); // 使用 self,避免事务不发起 |
| 145 | } | 151 | } |
| 146 | 152 | ||
| 147 | /** | 153 | /** |
| @@ -149,7 +155,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -149,7 +155,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 149 | * | 155 | * |
| 150 | * @param task 通知任务 | 156 | * @param task 通知任务 |
| 151 | */ | 157 | */ |
| 152 | - public void executeNotify(PayNotifyTaskDO task) { | 158 | + public void executeNotifySync(PayNotifyTaskDO task) { |
| 153 | // 分布式锁,避免并发问题 | 159 | // 分布式锁,避免并发问题 |
| 154 | payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { | 160 | payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> { |
| 155 | // 校验,当前任务是否已经被通知过 | 161 | // 校验,当前任务是否已经被通知过 |
| @@ -161,12 +167,12 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -161,12 +167,12 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 161 | } | 167 | } |
| 162 | 168 | ||
| 163 | // 执行通知 | 169 | // 执行通知 |
| 164 | - executeNotify0(dbTask); | 170 | + executeNotify(dbTask); |
| 165 | }); | 171 | }); |
| 166 | } | 172 | } |
| 167 | 173 | ||
| 168 | @Transactional | 174 | @Transactional |
| 169 | - public void executeNotify0(PayNotifyTaskDO task) { | 175 | + public void executeNotify(PayNotifyTaskDO task) { |
| 170 | // 发起回调 | 176 | // 发起回调 |
| 171 | CommonResult<?> invokeResult = null; | 177 | CommonResult<?> invokeResult = null; |
| 172 | Throwable invokeException = null; | 178 | Throwable invokeException = null; |
| @@ -176,19 +182,13 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -176,19 +182,13 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 176 | invokeException = e; | 182 | invokeException = e; |
| 177 | } | 183 | } |
| 178 | 184 | ||
| 179 | - // 设置通用的更新 PayNotifyTaskDO 的字段 | ||
| 180 | - PayNotifyTaskDO updateTask = new PayNotifyTaskDO() | ||
| 181 | - .setId(task.getId()) | ||
| 182 | - .setLastExecuteTime(new Date()) | ||
| 183 | - .setNotifyTimes(task.getNotifyTimes() + 1); | ||
| 184 | - | ||
| 185 | - // 情况一:调用成功 | ||
| 186 | - | ||
| 187 | - // 情况二:调用失败 | ||
| 188 | - | ||
| 189 | - // 调用三:调用异常 | 185 | + // 处理 |
| 186 | + Integer newStatus = this.processNotifyResult(task, invokeResult, invokeException); | ||
| 190 | 187 | ||
| 191 | // 记录 PayNotifyLog 日志 | 188 | // 记录 PayNotifyLog 日志 |
| 189 | + String response = invokeException != null ? getRootCauseMessage(invokeException) : toJsonString(invokeResult); | ||
| 190 | + payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId()) | ||
| 191 | + .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build()); | ||
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | /** | 194 | /** |
| @@ -216,4 +216,41 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | @@ -216,4 +216,41 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService { | ||
| 216 | return JsonUtils.parseObject(response, CommonResult.class); | 216 | return JsonUtils.parseObject(response, CommonResult.class); |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | + /** | ||
| 220 | + * 处理并更新通知结果 | ||
| 221 | + * | ||
| 222 | + * @param task 通知任务 | ||
| 223 | + * @param invokeResult 通知结果 | ||
| 224 | + * @param invokeException 通知异常 | ||
| 225 | + * @return 最终任务的状态 | ||
| 226 | + */ | ||
| 227 | + private Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) { | ||
| 228 | + // 设置通用的更新 PayNotifyTaskDO 的字段 | ||
| 229 | + PayNotifyTaskDO updateTask = new PayNotifyTaskDO() | ||
| 230 | + .setId(task.getId()) | ||
| 231 | + .setLastExecuteTime(new Date()) | ||
| 232 | + .setNotifyTimes(task.getNotifyTimes() + 1); | ||
| 233 | + | ||
| 234 | + // 情况一:调用成功 | ||
| 235 | + if (invokeResult != null && invokeResult.isSuccess()) { | ||
| 236 | + updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()); | ||
| 237 | + return updateTask.getStatus(); | ||
| 238 | + } | ||
| 239 | + // 情况二:调用失败、调用异常 | ||
| 240 | + // 2.1 超过最大回调次数 | ||
| 241 | + if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) { | ||
| 242 | + updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()); | ||
| 243 | + return updateTask.getStatus(); | ||
| 244 | + } | ||
| 245 | + // 2.2 未超过最大回调次数 | ||
| 246 | + updateTask.setNextNotifyTime(DateUtils.addDate(Calendar.SECOND, PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()])); | ||
| 247 | + updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus() | ||
| 248 | + : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()); | ||
| 249 | + return updateTask.getStatus(); | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + private void processNotifySuccess(PayNotifyTaskDO task, PayNotifyTaskDO updateTask) { | ||
| 253 | + payNotifyTaskCoreMapper.updateById(updateTask); | ||
| 254 | + } | ||
| 255 | + | ||
| 219 | } | 256 | } |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
| @@ -89,4 +89,35 @@ public class DateUtils { | @@ -89,4 +89,35 @@ public class DateUtils { | ||
| 89 | return date.getTime() >= System.currentTimeMillis(); | 89 | return date.getTime() >= System.currentTimeMillis(); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | + /** | ||
| 93 | + * 计算当期时间相差的日期 | ||
| 94 | + * | ||
| 95 | + * @param field 日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等. | ||
| 96 | + * @param amount 相差的数值 | ||
| 97 | + * @return 计算后的日志 | ||
| 98 | + */ | ||
| 99 | + public static Date addDate(int field, int amount) { | ||
| 100 | + return addDate(null, field, amount); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * 计算当期时间相差的日期 | ||
| 105 | + * | ||
| 106 | + * @param date 设置时间 | ||
| 107 | + * @param field 日历字段 例如说,{@link Calendar#DAY_OF_MONTH} 等 | ||
| 108 | + * @param amount 相差的数值 | ||
| 109 | + * @return 计算后的日志 | ||
| 110 | + */ | ||
| 111 | + public static Date addDate(Date date, int field, int amount) { | ||
| 112 | + if (amount == 0) { | ||
| 113 | + return date; | ||
| 114 | + } | ||
| 115 | + Calendar c = Calendar.getInstance(); | ||
| 116 | + if (date != null) { | ||
| 117 | + c.setTime(date); | ||
| 118 | + } | ||
| 119 | + c.add(field, amount); | ||
| 120 | + return c.getTime(); | ||
| 121 | + } | ||
| 122 | + | ||
| 92 | } | 123 | } |