From eb760ab3121cb11331edb808376082f20058ef93 Mon Sep 17 00:00:00 2001
From: YunaiV <>
Date: Thu, 14 Mar 2019 22:17:56 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20RocketMQ=20=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6=20=E6=94=AF=E4=BB=98=E6=88=90=E5=8A=9F=E5=90=8E?=
=?UTF-8?q?=EF=BC=8C=E5=9B=9E=E8=B0=83=E9=80=9A=E7=9F=A5=E4=B8=9A=E5=8A=A1?=
=?UTF-8?q?=E7=BA=BF=E8=AE=A2=E5=8D=95=E6=94=AF=E4=BB=98=E6=88=90=E5=8A=9F?=
=?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E7=AE=80=E5=8D=95=E5=AE=8C?=
=?UTF-8?q?=E6=88=90=E3=80=82=E5=90=8E=E7=BB=AD=EF=BC=8C=E9=9C=80=E8=A6=81?=
=?UTF-8?q?=E5=B0=81=E8=A3=85=E4=B8=8B=EF=BC=8C=E5=AF=B9=E4=B8=8D=E5=90=8C?=
=?UTF-8?q?=E4=B8=9A=E5=8A=A1=E7=BA=BF=E7=9A=84=E5=9B=9E=E8=B0=83=E3=80=82?=
=?UTF-8?q?=E4=BB=A5=E5=8F=8A=EF=BC=8Chttp=20=E5=9B=9E=E8=B0=83=E7=9A=84?=
=?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/common-framework/pom.xml | 4 +
.../common/framework/util/DateUtil.java | 29 +++++
.../common/framework/util/ExceptionUtil.java | 5 +
.../controller/users/PayDemoController.java | 6 +-
.../users/PayTransactionController.java | 4 +-
pay/pay-service-impl/pom.xml | 6 +
.../mall/pay/biz/constant/MQConstant.java | 13 +++
.../biz/convert/PayTransactionConvert.java | 5 +
.../dao/PayTransactionNotifyLogMapper.java | 11 ++
.../dao/PayTransactionNotifyTaskMapper.java | 13 +++
.../dataobject/PayTransactionNotifyLogDO.java | 13 +++
.../PayTransactionNotifyTaskDO.java | 50 +++++++-
.../mq/PayTransactionPaySuccessConsumer.java | 108 ++++++++++++++++++
.../mq/PayTransactionPaySuccessMessage.java | 91 +++++++++++++++
.../iocoder/mall/pay/biz/mq/package-info.java | 1 +
.../pay/biz/scheduler/PayNotifyAppJob.java | 25 ----
.../scheduler/PayTransactionNotifyJob.java | 51 +++++++++
.../pay/biz/service/PayDemoServiceImpl.java | 3 +-
.../mall/pay/biz/service/PayServiceImpl.java | 15 ++-
.../main/resources/config/application.yaml | 9 +-
.../resources/mapper/PayTransactionMapper.xml | 3 +
.../mapper/PayTransactionNotifyLogMapper.xml | 46 ++++++++
.../mapper/PayTransactionNotifyTaskMapper.xml | 29 +++--
23 files changed, 488 insertions(+), 52 deletions(-)
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/constant/MQConstant.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessMessage.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/package-info.java
delete mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayNotifyAppJob.java
create mode 100644 pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java
create mode 100644 pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml
diff --git a/common/common-framework/pom.xml b/common/common-framework/pom.xml
index 52d055f6b..e5ba85817 100644
--- a/common/common-framework/pom.xml
+++ b/common/common-framework/pom.xml
@@ -60,6 +60,10 @@
fastjson
1.2.56
+
+ org.apache.commons
+ commons-lang3
+
diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
index d5736e45e..20f270b72 100644
--- a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
+++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/DateUtil.java
@@ -1,10 +1,39 @@
package cn.iocoder.common.framework.util;
import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.Date;
public class DateUtil {
+ /**
+ * 计算当期时间相差的日期
+ *
+ * @param field 日历字段.
eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,
Calendar.HOUR_OF_DAY等.
+ * @param amount 相差的数值
+ * @return 计算后的日志
+ */
+ public static Date addDate(int field, int amount) {
+ return addDate(null, field, amount);
+ }
+
+ /**
+ * 计算当期时间相差的日期
+ *
+ * @param date 设置时间
+ * @param field 日历字段.
eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,
Calendar.HOUR_OF_DAY等.
+ * @param amount 相差的数值
+ * @return 计算后的日志
+ */
+ public static Date addDate(Date date, int field, int amount) {
+ Calendar c = Calendar.getInstance();
+ if (date != null) {
+ c.setTime(date);
+ }
+ c.add(field, amount);
+ return c.getTime();
+ }
+
/**
* @param date 时间。若为空,则返回空串
* @param pattern 时间格式化
diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java
index 88bab3d7e..35c81c4a5 100644
--- a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java
+++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/ExceptionUtil.java
@@ -1,6 +1,7 @@
package cn.iocoder.common.framework.util;
import cn.iocoder.common.framework.exception.ServiceException;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.InvocationTargetException;
@@ -44,4 +45,8 @@ public class ExceptionUtil {
return null;
}
+ public static String getRootCauseMessage(Throwable th) {
+ return ExceptionUtils.getRootCauseMessage(th);
+ }
+
}
\ No newline at end of file
diff --git a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java
index 71ae866d6..176321c70 100644
--- a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java
+++ b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayDemoController.java
@@ -9,6 +9,7 @@ import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@@ -25,7 +26,8 @@ public class PayDemoController {
private PayTransactionService payTransactionService;
@PostMapping("/create_order")
- public void createOrder(HttpServletRequest request) {
+ public void createOrder(HttpServletRequest request,
+ @RequestParam("orderId") String orderId) {
// 创建业务订单
// ...
@@ -33,7 +35,7 @@ public class PayDemoController {
PayTransactionCreateDTO payTransactionCreateDTO = new PayTransactionCreateDTO()
.setAppId("POd4RC6a")
.setCreateIp(HttpUtil.getIp(request))
- .setOrderId("1")
+ .setOrderId(orderId)
.setOrderSubject("商品名" )
.setOrderDescription("商品描述")
.setOrderMemo("商品备注")
diff --git a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java
index bd3b25e44..eeaa9bad7 100644
--- a/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java
+++ b/pay/pay-application/src/main/java/cn/iocoder/mall/pay/application/controller/users/PayTransactionController.java
@@ -52,8 +52,8 @@ public class PayTransactionController {
// JSONObject bodyObj = JSON.parseObject(sb.toString());
// bodyObj.put("webhookId", bodyObj.remove("id"));
// String body = bodyObj.toString();
- payService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
- return "";
+ CommonResult result = payService.updateTransactionPaySuccess(PayChannelEnum.PINGXX.getId(), sb.toString());
+ return result.isSuccess() ? "success" : "failure";
}
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/pom.xml b/pay/pay-service-impl/pom.xml
index 4b892ecba..012b7ffbc 100644
--- a/pay/pay-service-impl/pom.xml
+++ b/pay/pay-service-impl/pom.xml
@@ -73,6 +73,12 @@
2.0.1
+
+ org.apache.rocketmq
+ rocketmq-spring-boot-starter
+ 2.0.1
+
+
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/constant/MQConstant.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/constant/MQConstant.java
new file mode 100644
index 000000000..57e1b00ae
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/constant/MQConstant.java
@@ -0,0 +1,13 @@
+package cn.iocoder.mall.pay.biz.constant;
+
+/**
+ * MQ 枚举类
+ */
+public class MQConstant {
+
+ /**
+ * Topic - 支付交易单支付成功
+ */
+ public static final String TOPIC_PAY_TRANSACTION_PAY_SUCCESS = "PAY_TRANSACTION_PAY_SUCCESS";
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java
index 10c2a395a..e6688312a 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/convert/PayTransactionConvert.java
@@ -5,6 +5,8 @@ import cn.iocoder.mall.pay.api.dto.PayTransactionCreateDTO;
import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO;
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO;
+import cn.iocoder.mall.pay.biz.mq.PayTransactionPaySuccessMessage;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@@ -23,4 +25,7 @@ public interface PayTransactionConvert {
@Mappings({})
PayTransactionExtensionDO convert(PayTransactionSubmitDTO payTransactionSubmitDTO);
+ @Mappings({})
+ PayTransactionPaySuccessMessage convert(PayTransactionNotifyTaskDO payTransactionNotifyTaskDO);
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java
new file mode 100644
index 000000000..c6dd400da
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyLogMapper.java
@@ -0,0 +1,11 @@
+package cn.iocoder.mall.pay.biz.dao;
+
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyLogDO;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface PayTransactionNotifyLogMapper {
+
+ void insert(PayTransactionNotifyLogDO entity);
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java
index 13cd11036..3c2462e32 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dao/PayTransactionNotifyTaskMapper.java
@@ -3,6 +3,8 @@ package cn.iocoder.mall.pay.biz.dao;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO;
import org.springframework.stereotype.Repository;
+import java.util.List;
+
@Repository
public interface PayTransactionNotifyTaskMapper {
@@ -10,4 +12,15 @@ public interface PayTransactionNotifyTaskMapper {
int update(PayTransactionNotifyTaskDO entity);
+ /**
+ * 获得需要通知的 PayTransactionNotifyTaskDO 记录。需要满足如下条件:
+ *
+ * 1. status 非成功
+ * 2. nextNotifyTime 小于当前时间
+ * 3. lastExecuteTime > nextNotifyTime
+ *
+ * @return PayTransactionNotifyTaskDO 数组
+ */
+ List selectByNotify();
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java
index 99646ecd1..e348c30ce 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyLogDO.java
@@ -13,6 +13,10 @@ public class PayTransactionNotifyLogDO extends BaseDO {
* 日志编号,自增
*/
private Integer id;
+ /**
+ * 通知编号
+ */
+ private Integer notifyId;
/**
* 请求参数
*/
@@ -64,4 +68,13 @@ public class PayTransactionNotifyLogDO extends BaseDO {
return this;
}
+ public Integer getNotifyId() {
+ return notifyId;
+ }
+
+ public PayTransactionNotifyLogDO setNotifyId(Integer notifyId) {
+ this.notifyId = notifyId;
+ return this;
+ }
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java
index f79475239..9aebb9be4 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/dataobject/PayTransactionNotifyTaskDO.java
@@ -1,6 +1,7 @@
package cn.iocoder.mall.pay.biz.dataobject;
import cn.iocoder.common.framework.dataobject.BaseDO;
+import cn.iocoder.mall.pay.biz.service.PayServiceImpl;
import java.util.Date;
@@ -9,6 +10,16 @@ import java.util.Date;
*/
public class PayTransactionNotifyTaskDO extends BaseDO {
+ /**
+ * 通知频率,单位为秒。
+ *
+ * 算上首次的通知,实际是一共 1 + 8 = 9 次。
+ */
+ public static final Integer[] NOTIFY_FREQUENCY = new Integer[]{
+ 15, 15, 30, 180,
+ 1800, 1800, 1800, 3600
+ };
+
/**
* 编号,自增
*/
@@ -40,9 +51,26 @@ public class PayTransactionNotifyTaskDO extends BaseDO {
*/
private Integer status;
/**
- * 最后一次通知时间
+ * 下一次通知时间
*/
- private Date lastNotifyTime;
+ private Date nextNotifyTime;
+ /**
+ * 最后一次执行时间
+ *
+ * 这个字段,需要结合 {@link #nextNotifyTime} 一起使用。
+ *
+ * 1. 初始时,{@link PayServiceImpl#updateTransactionPaySuccess(Integer, String)}
+ * nextNotifyTime 为当前时间 + 15 秒
+ * lastExecuteTime 为空
+ * 并发送给 MQ ,执行执行
+ *
+ * 2. MQ 消费时,更新 lastExecuteTime 为当时时间
+ *
+ * 3. 定时任务,扫描 nextNotifyTime < lastExecuteTime 的任务
+ * nextNotifyTime 为当前时间 + N 秒。具体的 N ,由第几次通知决定
+ * lastExecuteTime 为当前时间
+ */
+ private Date lastExecuteTime;
/**
* 当前通知次数
*/
@@ -92,12 +120,12 @@ public class PayTransactionNotifyTaskDO extends BaseDO {
return this;
}
- public Date getLastNotifyTime() {
- return lastNotifyTime;
+ public Date getNextNotifyTime() {
+ return nextNotifyTime;
}
- public PayTransactionNotifyTaskDO setLastNotifyTime(Date lastNotifyTime) {
- this.lastNotifyTime = lastNotifyTime;
+ public PayTransactionNotifyTaskDO setNextNotifyTime(Date nextNotifyTime) {
+ this.nextNotifyTime = nextNotifyTime;
return this;
}
@@ -145,4 +173,14 @@ public class PayTransactionNotifyTaskDO extends BaseDO {
this.notifyUrl = notifyUrl;
return this;
}
+
+ public Date getLastExecuteTime() {
+ return lastExecuteTime;
+ }
+
+ public PayTransactionNotifyTaskDO setLastExecuteTime(Date lastExecuteTime) {
+ this.lastExecuteTime = lastExecuteTime;
+ return this;
+ }
+
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java
new file mode 100644
index 000000000..6b572e39d
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessConsumer.java
@@ -0,0 +1,108 @@
+package cn.iocoder.mall.pay.biz.mq;
+
+import cn.iocoder.common.framework.util.DateUtil;
+import cn.iocoder.common.framework.util.ExceptionUtil;
+import cn.iocoder.mall.pay.api.constant.PayTransactionNotifyStatusEnum;
+import cn.iocoder.mall.pay.biz.constant.MQConstant;
+import cn.iocoder.mall.pay.biz.dao.PayTransactionMapper;
+import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyLogMapper;
+import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper;
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyLogDO;
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO;
+import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.ReferenceConfig;
+import com.alibaba.dubbo.config.RegistryConfig;
+import com.alibaba.dubbo.rpc.service.GenericService;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Calendar;
+import java.util.Date;
+
+@Service
+@RocketMQMessageListener(
+ topic = MQConstant.TOPIC_PAY_TRANSACTION_PAY_SUCCESS,
+ consumerGroup = "pay-consumer-group-" + MQConstant.TOPIC_PAY_TRANSACTION_PAY_SUCCESS
+)
+public class PayTransactionPaySuccessConsumer implements RocketMQListener {
+
+ @Autowired
+ private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper;
+ @Autowired
+ private PayTransactionNotifyLogMapper payTransactionNotifyLogMapper;
+ @Autowired
+ private PayTransactionMapper payTransactionMapper;
+
+ @Override
+ @Transactional
+ public void onMessage(PayTransactionPaySuccessMessage message) {
+ // TODO 先简单写,后面重构
+
+ ApplicationConfig application = new ApplicationConfig();
+ application.setName("api-generic-consumer");
+
+ RegistryConfig registry = new RegistryConfig();
+ registry.setAddress("zookeeper://127.0.0.1:2181");
+
+ application.setRegistry(registry);
+
+ ReferenceConfig reference = new ReferenceConfig<>();
+ // 弱类型接口名
+ reference.setInterface("cn.iocoder.mall.pay.api.PayDemoService");
+ // 声明为泛化接口
+ reference.setGeneric(true);
+
+ reference.setApplication(application);
+
+ // 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用
+ GenericService genericService = reference.get(); // TODO 芋艿,要缓存,不然重复引用
+
+ String response = null; // RPC / HTTP 调用的响应
+ PayTransactionNotifyTaskDO updateTask = new PayTransactionNotifyTaskDO() // 更新 PayTransactionNotifyTaskDO 对象
+ .setId(message.getId())
+ .setLastExecuteTime(new Date())
+ .setNotifyTimes(message.getNotifyTimes() + 1);
+ try {
+ response = (String) genericService.$invoke("updatePaySuccess", new String[]{String.class.getName()}, new Object[]{message.getOrderId()});
+ if ("success".equals(response)) { // 情况一,请求成功且返回成功
+ // 更新通知成功
+ updateTask.setStatus(PayTransactionNotifyStatusEnum.SUCCESS.getValue());
+ payTransactionNotifyTaskMapper.update(updateTask);
+ // 需要更新支付交易单通知应用成功
+ PayTransactionDO updateTransaction = new PayTransactionDO().setId(message.getTransactionId())
+ .setFinishTime(new Date());
+ payTransactionMapper.update(updateTransaction, null);
+ } else { // 情况二,请求成功且返回失败
+ // 更新通知请求成功,但是结果失败
+ handleFailure(updateTask, PayTransactionNotifyStatusEnum.REQUEST_SUCCESS.getValue());
+ payTransactionNotifyTaskMapper.update(updateTask);
+ }
+ } catch (Throwable e) { // 请求失败
+ // 更新通知请求失败
+ response = ExceptionUtil.getRootCauseMessage(e);
+ handleFailure(updateTask, PayTransactionNotifyStatusEnum.REQUEST_FAILURE.getValue());
+ payTransactionNotifyTaskMapper.update(updateTask);
+ // 抛出异常,回滚事务
+ throw e;
+ } finally {
+ // 插入 PayTransactionNotifyLogDO 日志
+ PayTransactionNotifyLogDO notifyLog = new PayTransactionNotifyLogDO().setNotifyId(message.getId())
+ .setRequest(message.getOrderId()).setResponse(response).setStatus(updateTask.getStatus());
+ payTransactionNotifyLogMapper.insert(notifyLog);
+ }
+ }
+
+ private void handleFailure(PayTransactionNotifyTaskDO updateTask, Integer defaultStatus) {
+ if (updateTask.getNotifyTimes() >= PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY.length) {
+ updateTask.setStatus(PayTransactionNotifyStatusEnum.FAILURE.getValue());
+ } else {
+ updateTask.setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY[updateTask.getNotifyTimes()]));
+ updateTask.setStatus(defaultStatus);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessMessage.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessMessage.java
new file mode 100644
index 000000000..e83cbce9d
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/PayTransactionPaySuccessMessage.java
@@ -0,0 +1,91 @@
+package cn.iocoder.mall.pay.biz.mq;
+
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
+
+/**
+ * {@link cn.iocoder.mall.pay.biz.constant.MQConstant#TOPIC_PAY_TRANSACTION_PAY_SUCCESS} 的消息对象
+ */
+public class PayTransactionPaySuccessMessage {
+
+ /**
+ * 编号,自增
+ */
+ private Integer id;
+ /**
+ * 交易编号
+ *
+ * {@link PayTransactionDO#getId()}
+ */
+ private Integer transactionId;
+ /**
+ * 应用编号
+ */
+ private String appId;
+ /**
+ * 应用订单编号
+ */
+ private String orderId;
+ /**
+ * 当前通知次数
+ */
+ private Integer notifyTimes;
+ /**
+ * 通知地址
+ */
+ private String notifyUrl;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public PayTransactionPaySuccessMessage setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public PayTransactionPaySuccessMessage setAppId(String appId) {
+ this.appId = appId;
+ return this;
+ }
+
+ public String getOrderId() {
+ return orderId;
+ }
+
+ public PayTransactionPaySuccessMessage setOrderId(String orderId) {
+ this.orderId = orderId;
+ return this;
+ }
+
+ public Integer getNotifyTimes() {
+ return notifyTimes;
+ }
+
+ public PayTransactionPaySuccessMessage setNotifyTimes(Integer notifyTimes) {
+ this.notifyTimes = notifyTimes;
+ return this;
+ }
+
+ public String getNotifyUrl() {
+ return notifyUrl;
+ }
+
+ public PayTransactionPaySuccessMessage setNotifyUrl(String notifyUrl) {
+ this.notifyUrl = notifyUrl;
+ return this;
+ }
+
+ public Integer getTransactionId() {
+ return transactionId;
+ }
+
+ public PayTransactionPaySuccessMessage setTransactionId(Integer transactionId) {
+ this.transactionId = transactionId;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/package-info.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/package-info.java
new file mode 100644
index 000000000..a8c2c99b9
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/mq/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.mall.pay.biz.mq;
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayNotifyAppJob.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayNotifyAppJob.java
deleted file mode 100644
index 2d0a98b14..000000000
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayNotifyAppJob.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.iocoder.mall.pay.biz.scheduler;
-
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.handler.IJobHandler;
-import com.xxl.job.core.handler.annotation.JobHandler;
-import org.springframework.stereotype.Component;
-
-/**
- * TODO
- */
-@Component
-@JobHandler(value = "payNotifyAppJob")
-public class PayNotifyAppJob extends IJobHandler {
-
- @Override
- public ReturnT execute(String param) throws Exception {
- System.out.println("1");
- return null;
- }
-
- // TODO 需要考虑下是基于 MQ 还是 Job
- // TODO 通知频率
- // TODO rpc 泛化回调
-
-}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java
new file mode 100644
index 000000000..358ece94a
--- /dev/null
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/scheduler/PayTransactionNotifyJob.java
@@ -0,0 +1,51 @@
+package cn.iocoder.mall.pay.biz.scheduler;
+
+import cn.iocoder.mall.pay.biz.constant.MQConstant;
+import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert;
+import cn.iocoder.mall.pay.biz.dao.PayTransactionNotifyTaskMapper;
+import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.IJobHandler;
+import com.xxl.job.core.handler.annotation.JobHandler;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 支付交易成功通知 Job
+ */
+@Component
+@JobHandler(value = "payTransactionNotifyJob")
+public class PayTransactionNotifyJob extends IJobHandler {
+
+ @Autowired
+ private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper;
+
+ @Resource
+ private RocketMQTemplate rocketMQTemplate;
+
+ @Override
+ public ReturnT execute(String param) {
+ // 获得需要通知的任务
+ List notifyTasks = payTransactionNotifyTaskMapper.selectByNotify();
+ // 循环任务,发送通知
+ for (PayTransactionNotifyTaskDO payTransactionNotifyTask : notifyTasks) {
+ // 发送 MQ
+ rocketMQTemplate.convertAndSend(MQConstant.TOPIC_PAY_TRANSACTION_PAY_SUCCESS,
+ PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask));
+ // 更新最后通知时间
+ // 1. 这样操作,虽然可能会出现 MQ 消费快于下面 PayTransactionNotifyTaskDO 的更新语句。但是,因为更新字段不同,所以不会有问题。
+ // 2. 换个视角,如果先更新 PayTransactionNotifyTaskDO ,再发送 MQ 消息。如果 MQ 消息发送失败,则 PayTransactionNotifyTaskDO 再也不会被轮询到了。
+ // 3. 当然,最最最完美的话,就是做事务消息,不过这样又过于复杂~
+ PayTransactionNotifyTaskDO updateNotifyTask = new PayTransactionNotifyTaskDO()
+ .setId(payTransactionNotifyTask.getId()).setLastExecuteTime(new Date());
+ payTransactionNotifyTaskMapper.update(updateNotifyTask);
+ }
+ return new ReturnT<>("执行通知数:" + notifyTasks.size());
+ }
+
+}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java
index 28957e51b..7a03dc6ca 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayDemoServiceImpl.java
@@ -9,7 +9,8 @@ public class PayDemoServiceImpl implements PayDemoService {
@Override
public String updatePaySuccess(String orderId) {
- return "你好呀";
+// return "你好呀";
+ return "success";
}
}
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java
index 210310240..614aec1d0 100644
--- a/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java
+++ b/pay/pay-service-impl/src/main/java/cn/iocoder/mall/pay/biz/service/PayServiceImpl.java
@@ -15,6 +15,7 @@ import cn.iocoder.mall.pay.api.dto.PayTransactionSubmitDTO;
import cn.iocoder.mall.pay.biz.client.AbstractPaySDK;
import cn.iocoder.mall.pay.biz.client.PaySDKFactory;
import cn.iocoder.mall.pay.biz.client.TransactionPaySuccessBO;
+import cn.iocoder.mall.pay.biz.constant.MQConstant;
import cn.iocoder.mall.pay.biz.convert.PayTransactionConvert;
import cn.iocoder.mall.pay.biz.dao.PayTransactionExtensionMapper;
import cn.iocoder.mall.pay.biz.dao.PayTransactionMapper;
@@ -23,12 +24,15 @@ import cn.iocoder.mall.pay.biz.dataobject.PayAppDO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionDO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionExtensionDO;
import cn.iocoder.mall.pay.biz.dataobject.PayTransactionNotifyTaskDO;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import javax.annotation.Resource;
+import java.util.Calendar;
import java.util.Date;
@Service
@@ -46,6 +50,9 @@ public class PayServiceImpl implements PayTransactionService {
@Autowired
private PayAppServiceImpl payAppService;
+ @Resource
+ private RocketMQTemplate rocketMQTemplate;
+
@Override
@SuppressWarnings("Duplicates")
public CommonResult createTransaction(PayTransactionCreateDTO payTransactionCreateDTO) {
@@ -158,14 +165,18 @@ public class PayServiceImpl implements PayTransactionService {
if (updateCounts == 0) { // 校验状态,必须是待支付 TODO 这种类型,需要思考下。需要返回错误,但是又要保证事务回滚
throw ServiceExceptionUtil.exception(PayErrorCodeEnum.PAY_TRANSACTION_STATUS_IS_NOT_WAITING.getCode());
}
- // 3. 插入
+ // 3.1 插入
PayTransactionNotifyTaskDO payTransactionNotifyTask = new PayTransactionNotifyTaskDO()
.setTransactionId(payTransactionExtension.getTransactionId()).setTransactionExtensionId(payTransactionExtension.getId())
.setAppId(payTransactionDO.getAppId()).setOrderId(payTransactionDO.getOrderId())
.setStatus(PayTransactionNotifyStatusEnum.WAITING.getValue())
- .setNotifyTimes(0).setMaxNotifyTimes(5)
+ .setNotifyTimes(0).setMaxNotifyTimes(PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY.length + 1)
+ .setNextNotifyTime(DateUtil.addDate(Calendar.SECOND, PayTransactionNotifyTaskDO.NOTIFY_FREQUENCY[0]))
.setNotifyUrl(payTransactionDO.getNotifyUrl());
payTransactionNotifyTaskMapper.insert(payTransactionNotifyTask);
+ // 3.2 发送 MQ
+ rocketMQTemplate.convertAndSend(MQConstant.TOPIC_PAY_TRANSACTION_PAY_SUCCESS,
+ PayTransactionConvert.INSTANCE.convert(payTransactionNotifyTask));
// 返回结果
return CommonResult.success(true);
}
diff --git a/pay/pay-service-impl/src/main/resources/config/application.yaml b/pay/pay-service-impl/src/main/resources/config/application.yaml
index 2085220c5..de2fd3e34 100644
--- a/pay/pay-service-impl/src/main/resources/config/application.yaml
+++ b/pay/pay-service-impl/src/main/resources/config/application.yaml
@@ -25,7 +25,6 @@ dubbo:
base-packages: cn.iocoder.mall.pay.biz.service
# xxl-job
-
xxl:
job:
admin:
@@ -36,4 +35,10 @@ xxl:
port: 0
logpath: /Users/yunai/logs/xxl-job/
logretentiondays: 1
- accessToken:
\ No newline at end of file
+ accessToken:
+
+# rocketmq
+rocketmq:
+ name-server: 127.0.0.1:9876
+ producer:
+ group: pay-producer-group
diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml
index 661b8c59b..d280d6de3 100644
--- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml
+++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionMapper.xml
@@ -38,6 +38,9 @@
, payment_time = #{entity.paymentTime}
+
+ , finish_time = #{entity.finishTime}
+
, notify_time = #{entity.notifyTime}
diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml
new file mode 100644
index 000000000..6c09d697c
--- /dev/null
+++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyLogMapper.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO transaction_notify_log (
+ notify_id, request, response, status
+ ) VALUES (
+ #{notifyId}, #{request}, #{response}, #{status}
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml
index aa5518426..656631c0c 100644
--- a/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml
+++ b/pay/pay-service-impl/src/main/resources/mapper/PayTransactionNotifyTaskMapper.xml
@@ -4,16 +4,17 @@
id, transaction_id, transaction_extension_id, app_id, order_id,
- status, last_Notify_time, notify_times, max_notify_times, create_time
+ status, next_notify_time, last_execute_time, notify_times, max_notify_times,
+ create_time
INSERT INTO transaction_notify_task (
transaction_id, transaction_extension_id, app_id, order_id,
- status, last_notify_time, notify_times, max_notify_times
+ status, next_notify_time, notify_times, max_notify_times
) VALUES (
#{transactionId}, #{transactionExtensionId}, #{appId}, #{orderId},
- #{status}, #{lastNotifyTime}, #{notifyTimes}, #{maxNotifyTimes}
+ #{status}, #{nextNotifyTime}, #{notifyTimes}, #{maxNotifyTimes}
)
@@ -23,8 +24,11 @@
, status = #{status}
-
- , last_notify_time = #{lastNotifyTime}
+
+ , next_notify_time = #{nextNotifyTime}
+
+
+ , last_execute_time = #{lastExecuteTime}
, notify_times = #{notifyTimes}
@@ -33,12 +37,13 @@
WHERE id = #{id}
-
-
-
-
-
-
-
+
\ No newline at end of file