后端:增加支付成功后,回调支付模块

This commit is contained in:
YunaiV 2019-04-21 15:22:03 +08:00
parent 914de3f2cb
commit 3eca1823ee
8 changed files with 151 additions and 40 deletions

View File

@ -138,8 +138,21 @@ public interface OrderService {
* *
* mq 更新 payStatus * mq 更新 payStatus
*/ */
@Deprecated
CommonResult listenerPayment(); CommonResult listenerPayment();
/**
* 更新订单支付成功
*
* 如果成功则返回 success
* 如果失败则返回具体原因
*
* @param orderId 订单编号
* @param payAmount 支付的订单金额
* @return 支付结果
*/
String updatePaySuccess(String orderId, Integer payAmount);
/** /**
* 监听确认收货 * 监听确认收货
* *

View File

@ -25,6 +25,8 @@ public enum OrderErrorCodeEnum {
ORDER_NOT_USER_ORDER(1008000011, "不是该用户的订单!"), ORDER_NOT_USER_ORDER(1008000011, "不是该用户的订单!"),
ORDER_UNABLE_CONFIRM_ORDER(1008000012, "状态不对不能确认订单!"), ORDER_UNABLE_CONFIRM_ORDER(1008000012, "状态不对不能确认订单!"),
ORDER_CREATE_CART_IS_EMPTY(1008000013, "购物车无选中的商品,无法创建订单"), ORDER_CREATE_CART_IS_EMPTY(1008000013, "购物车无选中的商品,无法创建订单"),
ORDER_STATUS_NOT_WAITING_PAYMENT(1008000014, "订单不处于等待支付状态"),
ORDER_PAY_AMOUNT_ERROR(1008000015, "订单金额不正确"),
// order item // order item
ORDER_ITEM_ONLY_ONE(1008000200, "订单Item只有一个!"), ORDER_ITEM_ONLY_ONE(1008000200, "订单Item只有一个!"),

View File

@ -31,6 +31,10 @@ public interface OrderMapper {
*/ */
int updateById(OrderDO orderDO); int updateById(OrderDO orderDO);
int updateByIdAndStatus(@Param("id") Integer id,
@Param("status") Integer status,
@Param("updateObj") OrderDO updateObj);
/** /**
* 查询 - 根据id 查询 * 查询 - 根据id 查询
* *

View File

@ -598,6 +598,29 @@ public class OrderServiceImpl implements OrderService {
return null; return null;
} }
@Override
public String updatePaySuccess(String orderId, Integer payAmount) {
OrderDO order = orderMapper.selectById(Integer.valueOf(orderId));
if (order == null) { // 订单不存在
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_NOT_EXISTENT.getCode()).getMessage();
}
if (!order.getStatus().equals(OrderStatusEnum.WAITING_PAYMENT.getValue())) { // 状态不处于等待支付
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage();
}
if (!order.getPresentPrice().equals(payAmount)) { // 支付金额不正确
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_PAY_AMOUNT_ERROR.getCode()).getMessage();
}
OrderDO updateOrderObj = new OrderDO()
.setStatus(OrderStatusEnum.ALREADY_SHIPMENT.getValue())
.setPayAmount(payAmount)
.setPaymentTime(new Date());
int updateCount = orderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
if (updateCount <= 0) {
return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_STATUS_NOT_WAITING_PAYMENT.getCode()).getMessage();
}
return "success";
}
@Override @Override
public CommonResult listenerConfirmGoods() { public CommonResult listenerConfirmGoods() {
return null; return null;

View File

@ -34,22 +34,30 @@
<if test="orderNo != null"> <if test="orderNo != null">
, order_no = #{orderNo} , order_no = #{orderNo}
</if> </if>
<!-- <if test="price != null">--> <!-- TODO 后面要改下 --> <if test="buyPrice != null">
<!-- , price = #{price}--> , buy_price = #{buyPrice}
<!-- </if>--> </if>
<!-- <if test="payAmount != null">--> <if test="discountPrice != null">
<!-- , pay_amount = #{payAmount}--> , discount_price = #{discountPrice}
<!-- </if>--> </if>
<!-- <if test="logisticsPrice != null">--> <if test="logisticsPrice != null">
<!-- , logistics_price = #{logisticsPrice}--> , logistics_price = #{logisticsPrice}
<!-- </if>--> </if>
<if test="logisticsPrice != null">
<if test="paymentTime != null"> , logistics_price = #{logisticsPrice}
, payment_time = #{paymentTime} </if>
<if test="presentPrice != null">
, present_price = #{presentPrice}
</if>
<if test="payAmount != null">
, pay_amount = #{payAmount}
</if> </if>
<if test="deliveryTime != null"> <if test="deliveryTime != null">
, delivery_time = #{deliveryTime} , delivery_time = #{deliveryTime}
</if> </if>
<if test="paymentTime != null">
, payment_time = #{paymentTime}
</if>
<if test="receiverTime != null"> <if test="receiverTime != null">
, receiver_time = #{receiverTime} , receiver_time = #{receiverTime}
</if> </if>
@ -87,6 +95,23 @@
WHERE id = #{id} WHERE id = #{id}
</update> </update>
<update id="updateByIdAndStatus">
UPDATE `order`
<set>
<if test="updateObj.payAmount != null">
, pay_amount = #{updateObj.payAmount}
</if>
<if test="updateObj.paymentTime != null">
, payment_time = #{updateObj.paymentTime}
</if>
<if test="updateObj.status != null">
, status = #{updateObj.status}
</if>
</set>
WHERE id = #{id}
AND status = #{status}
</update>
<!-- <!--
查询 - 根据id 查询 查询 - 根据id 查询
--> -->

View File

@ -16,7 +16,7 @@ public class DubboGenericInvokerTest {
ReferenceConfig<GenericService> reference = new ReferenceConfig<>(); ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
// 弱类型接口名 // 弱类型接口名
reference.setInterface("cn.iocoder.mall.pay.api.PayDemoService"); reference.setInterface("cn.iocoder.mall.order.api.OrderService");
// 声明为泛化接口 // 声明为泛化接口
reference.setGeneric(true); reference.setGeneric(true);

View File

@ -15,6 +15,6 @@ public interface PayTransactionMapper {
PayTransactionDO selectByAppIdAndOrderId(@Param("appId") String appId, PayTransactionDO selectByAppIdAndOrderId(@Param("appId") String appId,
@Param("orderId") String orderId); @Param("orderId") String orderId);
PayTransactionDO selectById(@Param("id") Integer appId); PayTransactionDO selectById(@Param("id") Integer id);
} }

View File

@ -14,11 +14,17 @@ import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig; import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService; import com.alibaba.dubbo.rpc.service.GenericService;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.Data;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -30,6 +36,26 @@ import java.util.Date;
) )
public class PayTransactionPaySuccessConsumer implements RocketMQListener<PayTransactionPaySuccessMessage> { public class PayTransactionPaySuccessConsumer implements RocketMQListener<PayTransactionPaySuccessMessage> {
@Data
private class ReferenceMeta {
private final ReferenceConfig config; // TODO 芋艿后续需要做销毁
private final GenericService service;
private final String methodName;
private ReferenceMeta(ReferenceConfig config, GenericService service, String methodName) {
this.config = config;
this.service = service;
this.methodName = methodName;
}
}
@Value("${dubbo.registry.address}")
private String dubboRegistryAddress;
@Value("${dubbo.application.name}")
private String dubboApplicationName;
@Autowired @Autowired
private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper; private PayTransactionNotifyTaskMapper payTransactionNotifyTaskMapper;
@Autowired @Autowired
@ -37,37 +63,55 @@ public class PayTransactionPaySuccessConsumer implements RocketMQListener<PayTra
@Autowired @Autowired
private PayTransactionMapper payTransactionMapper; private PayTransactionMapper payTransactionMapper;
private LoadingCache<String, ReferenceMeta> referenceMetaCache = CacheBuilder.newBuilder()
.build(new CacheLoader<String, ReferenceMeta>() {
@Override
public ReferenceMeta load(String notifyUrl) {
return createGenericService(notifyUrl);
}
});
private ReferenceMeta createGenericService(String notifyUrl) {
String[] notifyUrlParts = notifyUrl.split("#");
// 创建 ApplicationConfig 对象
ApplicationConfig application = new ApplicationConfig();
application.setName(dubboApplicationName);
// 创建 RegistryConfig 对象
RegistryConfig registry = new RegistryConfig();
// registry.setAddress("zookeeper://127.0.0.1:2181");
registry.setAddress(dubboRegistryAddress);
application.setRegistry(registry);
// 创建 ReferenceConfig 对象
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
reference.setInterface(notifyUrlParts[0]); // 弱类型接口名
reference.setGeneric(true); // 声明为泛化接口
reference.setApplication(application);
// 获得 GenericService 对象
GenericService genericService = reference.get();
// 构建最终的 ReferenceMeta 对象
return new ReferenceMeta(reference, genericService, notifyUrlParts[1]);
}
@Override @Override
@Transactional @Transactional
public void onMessage(PayTransactionPaySuccessMessage message) { public void onMessage(PayTransactionPaySuccessMessage message) {
// TODO 先简单写后面重构 // 获得 ReferenceMeta 对象
ReferenceMeta referenceMeta = referenceMetaCache.getUnchecked(message.getNotifyUrl());
ApplicationConfig application = new ApplicationConfig(); Assert.notNull(referenceMeta, String.format("notifyUrl(%s) 不存在对应的 ReferenceMeta 对象", message.getNotifyUrl()));
application.setName("api-generic-consumer"); GenericService genericService = referenceMeta.getService();
String methodName = referenceMeta.getMethodName();
RegistryConfig registry = new RegistryConfig(); // 查询支付交易
registry.setAddress("zookeeper://127.0.0.1:2181"); PayTransactionDO transaction = payTransactionMapper.selectById(message.getTransactionId());
Assert.notNull(transaction, String.format("回调消息(%s) 订单交易不能为空", message.toString()));
application.setRegistry(registry); // 发起调用
ReferenceConfig<GenericService> 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 调用的响应 String response = null; // RPC / HTTP 调用的响应
PayTransactionNotifyTaskDO updateTask = new PayTransactionNotifyTaskDO() // 更新 PayTransactionNotifyTaskDO 对象 PayTransactionNotifyTaskDO updateTask = new PayTransactionNotifyTaskDO() // 更新 PayTransactionNotifyTaskDO 对象
.setId(message.getId()) .setId(message.getId())
.setLastExecuteTime(new Date()) .setLastExecuteTime(new Date())
.setNotifyTimes(message.getNotifyTimes() + 1); .setNotifyTimes(message.getNotifyTimes() + 1);
try { try {
response = (String) genericService.$invoke("updatePaySuccess", new String[]{String.class.getName()}, new Object[]{message.getOrderId()}); response = (String) genericService.$invoke(methodName, new String[]{String.class.getName(), Integer.class.getName()},
new Object[]{message.getOrderId(), transaction.getPrice()});
if ("success".equals(response)) { // 情况一请求成功且返回成功 if ("success".equals(response)) { // 情况一请求成功且返回成功
// 更新通知成功 // 更新通知成功
updateTask.setStatus(PayTransactionNotifyStatusEnum.SUCCESS.getValue()); updateTask.setStatus(PayTransactionNotifyStatusEnum.SUCCESS.getValue());
@ -87,7 +131,7 @@ public class PayTransactionPaySuccessConsumer implements RocketMQListener<PayTra
handleFailure(updateTask, PayTransactionNotifyStatusEnum.REQUEST_FAILURE.getValue()); handleFailure(updateTask, PayTransactionNotifyStatusEnum.REQUEST_FAILURE.getValue());
payTransactionNotifyTaskMapper.update(updateTask); payTransactionNotifyTaskMapper.update(updateTask);
// 抛出异常回滚事务 // 抛出异常回滚事务
throw e; throw e; // TODO 芋艿此处不能抛出异常因为会导致 MQ + 定时任务多重试此处的目标是事务回滚 + 吃掉事务另外最后的 finally 的日志要插入成功
} finally { } finally {
// 插入 PayTransactionNotifyLogDO 日志 // 插入 PayTransactionNotifyLogDO 日志
PayTransactionNotifyLogDO notifyLog = new PayTransactionNotifyLogDO().setNotifyId(message.getId()) PayTransactionNotifyLogDO notifyLog = new PayTransactionNotifyLogDO().setNotifyId(message.getId())