Commit c89accbf060d4828601be1fba35a3594ef078ab2

Authored by YunaiV
1 parent 2df46a7c

完成支付通知的逻辑

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 3 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 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 9 * 商户支付、退款等的通知 Log
... ... @@ -16,7 +14,9 @@ import lombok.experimental.Accessors;
16 14 @TableName("pay_notify_log")
17 15 @Data
18 16 @EqualsAndHashCode(callSuper = true)
19   -@Accessors(chain = true)
  17 +@Builder
  18 +@NoArgsConstructor
  19 +@AllArgsConstructor
20 20 public class PayNotifyLogDO extends BaseDO {
21 21  
22 22 /**
... ... @@ -24,13 +24,15 @@ public class PayNotifyLogDO extends BaseDO {
24 24 */
25 25 private Long id;
26 26 /**
27   - * 通知编号
  27 + * 通知任务编号
28 28 *
29 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 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 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.http.HttpUtil;
  5 +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyLogDO;
5 6 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.notify.PayNotifyTaskDO;
6 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 9 import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.notify.PayNotifyTaskCoreMapper;
8 10 import cn.iocoder.yudao.coreservice.modules.pay.dal.redis.notify.PayNotifyLockCoreRedisDAO;
9 11 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyStatusEnum;
... ... @@ -25,12 +27,14 @@ import org.springframework.transaction.annotation.Transactional;
25 27  
26 28 import javax.annotation.Resource;
27 29 import javax.validation.Valid;
  30 +import java.util.Calendar;
28 31 import java.util.Date;
29 32 import java.util.List;
30 33 import java.util.Objects;
31 34 import java.util.concurrent.CountDownLatch;
32 35 import java.util.concurrent.TimeUnit;
33 36  
  37 +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
34 38 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.SECOND_MILLIS;
35 39 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
36 40  
... ... @@ -59,6 +63,8 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
59 63  
60 64 @Resource
61 65 private PayNotifyTaskCoreMapper payNotifyTaskCoreMapper;
  66 + @Resource
  67 + private PayNotifyLogCoreMapper payNotifyLogCoreMapper;
62 68  
63 69 @Resource
64 70 private ThreadPoolTaskExecutor threadPoolTaskExecutor; // TODO 芋艿:未来提供独立的线程池
... ... @@ -105,7 +111,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
105 111 CountDownLatch latch = new CountDownLatch(tasks.size());
106 112 tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
107 113 try {
108   - executeNotify(task);
  114 + executeNotifySync(task);
109 115 } finally {
110 116 latch.countDown();
111 117 }
... ... @@ -141,7 +147,7 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
141 147 */
142 148 @Async
143 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 155 *
150 156 * @param task 通知任务
151 157 */
152   - public void executeNotify(PayNotifyTaskDO task) {
  158 + public void executeNotifySync(PayNotifyTaskDO task) {
153 159 // 分布式锁,避免并发问题
154 160 payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
155 161 // 校验,当前任务是否已经被通知过
... ... @@ -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 174 @Transactional
169   - public void executeNotify0(PayNotifyTaskDO task) {
  175 + public void executeNotify(PayNotifyTaskDO task) {
170 176 // 发起回调
171 177 CommonResult<?> invokeResult = null;
172 178 Throwable invokeException = null;
... ... @@ -176,19 +182,13 @@ public class PayNotifyCoreServiceImpl implements PayNotifyCoreService {
176 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 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 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 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 }
... ...