Browse Source

完成支付通知的逻辑

YunaiV 3 years ago
parent
commit
c89accbf06

+ 9 - 7
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;
 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.experimental.Accessors;
+import lombok.*;
 
 /**
  * 商户支付、退款等的通知 Log
@@ -16,7 +14,9 @@ import lombok.experimental.Accessors;
 @TableName("pay_notify_log")
 @Data
 @EqualsAndHashCode(callSuper = true)
-@Accessors(chain = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class PayNotifyLogDO extends BaseDO {
 
     /**
@@ -24,13 +24,15 @@ public class PayNotifyLogDO extends BaseDO {
      */
     private Long id;
     /**
-     * 通知编号
+     * 通知任务编号
      *
      * 关联 {@link PayNotifyTaskDO#getId()}
      */
-    private Long notifyId;
+    private Long taskId;
     /**
-     * 当前通知次数
+     * 第几次被通知
+     *
+     * 对应到 {@link PayNotifyTaskDO#getNotifyTimes()}
      */
     private Integer notifyTimes;
     /**

+ 9 - 0
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/notify/PayNotifyLogCoreMapper.java

@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify;
+
+import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyLogDO;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface PayNotifyLogCoreMapper extends BaseMapperX<PayNotifyLogDO> {
+}

+ 53 - 16
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;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.http.HttpUtil;
+import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyLogDO;
 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyTaskDO;
 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
+import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyLogCoreMapper;
 import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyTaskCoreMapper;
 import cn.iocoder.yudao.coreservice.modules.pay.dal.redis.notify.PayNotifyLockCoreRedisDAO;
 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum;
@@ -25,12 +27,14 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.SECOND_MILLIS;
 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 
@@ -59,6 +63,8 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
 
     @Resource
     private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper;
+    @Resource
+    private PayNotifyLogCoreMapper payNotifyLogCoreMapper;
 
     @Resource
     private ThreadPoolTaskExecutor threadPoolTaskExecutor; // TODO 芋艿:未来提供独立的线程池
@@ -105,7 +111,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
         CountDownLatch latch = new CountDownLatch(tasks.size());
         tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
             try {
-                executeNotify(task);
+                executeNotifySync(task);
             } finally {
                 latch.countDown();
             }
@@ -141,7 +147,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
      */
     @Async
     public void executeNotifyAsync(PayNotifyTaskDO task) {
-        self.executeNotify(task); // 使用 self,避免事务不发起
+        self.executeNotifySync(task); // 使用 self,避免事务不发起
     }
 
     /**
@@ -149,7 +155,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
      *
      * @param task 通知任务
      */
-    public void executeNotify(PayNotifyTaskDO task) {
+    public void executeNotifySync(PayNotifyTaskDO task) {
         // 分布式锁,避免并发问题
         payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
             // 校验,当前任务是否已经被通知过
@@ -161,12 +167,12 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
             }
 
             // 执行通知
-            executeNotify0(dbTask);
+            executeNotify(dbTask);
         });
     }
 
     @Transactional
-    public void executeNotify0(PayNotifyTaskDO task) {
+    public void executeNotify(PayNotifyTaskDO task) {
         // 发起回调
         CommonResult<?> invokeResult = null;
         Throwable invokeException = null;
@@ -176,19 +182,13 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
             invokeException = e;
         }
 
-        // 设置通用的更新 PayNotifyTaskDO 的字段
-        PayNotifyTaskDO updateTask = new PayNotifyTaskDO()
-                .setId(task.getId())
-                .setLastExecuteTime(new Date())
-                .setNotifyTimes(task.getNotifyTimes() + 1);
-
-        // 情况一:调用成功
-
-        // 情况二:调用失败
-
-        // 调用三:调用异常
+        // 处理
+        Integer newStatus = this.processNotifyResult(task, invokeResult, invokeException);
 
         // 记录 PayNotifyLog 日志
+        String response = invokeException != null ? getRootCauseMessage(invokeException) : toJsonString(invokeResult);
+        payNotifyLogCoreMapper.insert(PayNotifyLogDO.builder().taskId(task.getId())
+                .notifyTimes(task.getNotifyTimes() + 1).status(newStatus).response(response).build());
     }
 
     /**
@@ -216,4 +216,41 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
         return JsonUtils.parseObject(response, CommonResult.class);
     }
 
+    /**
+     * 处理并更新通知结果
+     *
+     * @param task 通知任务
+     * @param invokeResult 通知结果
+     * @param invokeException 通知异常
+     * @return 最终任务的状态
+     */
+    private Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) {
+        // 设置通用的更新 PayNotifyTaskDO 的字段
+        PayNotifyTaskDO updateTask = new PayNotifyTaskDO()
+                .setId(task.getId())
+                .setLastExecuteTime(new Date())
+                .setNotifyTimes(task.getNotifyTimes() + 1);
+
+        // 情况一:调用成功
+        if (invokeResult != null && invokeResult.isSuccess()) {
+            updateTask.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
+            return updateTask.getStatus();
+        }
+        // 情况二:调用失败、调用异常
+        // 2.1 超过最大回调次数
+        if (updateTask.getNotifyTimes() >= PayNotifyTaskDO.NOTIFY_FREQUENCY.length) {
+            updateTask.setStatus(PayNotifyStatusEnum.FAILURE.getStatus());
+            return updateTask.getStatus();
+        }
+        // 2.2 未超过最大回调次数
+        updateTask.setNextNotifyTime(DateUtils.addDate(Calendar.SECOND, PayNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()]));
+        updateTask.setStatus(invokeException != null ? PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()
+                : PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
+        return updateTask.getStatus();
+    }
+
+    private void processNotifySuccess(PayNotifyTaskDO task, PayNotifyTaskDO updateTask) {
+        payNotifyTaskCoreMapper.updateById(updateTask);
+    }
+
 }

+ 31 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java

@@ -89,4 +89,35 @@ public class DateUtils {
         return date.getTime() >= System.currentTimeMillis();
     }
 
+    /**
+     * 计算当期时间相差的日期
+     *
+     * @param field  日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
+     * @param amount 相差的数值
+     * @return 计算后的日志
+     */
+    public static Date addDate(int field, int amount) {
+        return addDate(null, field, amount);
+    }
+
+    /**
+     * 计算当期时间相差的日期
+     *
+     * @param date   设置时间
+     * @param field  日历字段 例如说,{@link Calendar#DAY_OF_MONTH} 等
+     * @param amount 相差的数值
+     * @return 计算后的日志
+     */
+    public static Date addDate(Date date, int field, int amount) {
+        if (amount == 0) {
+            return date;
+        }
+        Calendar c = Calendar.getInstance();
+        if (date != null) {
+            c.setTime(date);
+        }
+        c.add(field, amount);
+        return c.getTime();
+    }
+
 }