添加支付宝支付能力

This commit is contained in:
zk
2026-05-15 11:45:00 +08:00
parent fda9cc17ef
commit 221456681b
11 changed files with 383 additions and 11 deletions
@@ -13,6 +13,9 @@ public class CreateOrderDto {
/** 订单ID,用于轮询状态 */
private Long orderId;
/** 微信支付二维码链接 */
private String codeUrl;
/** 支付渠道 1=微信 2=支付宝 */
private Integer payChannel;
/** 支付数据,微信=二维码URL,支付宝=HTML表单,前端根据payChannel判断渲染方式 */
private String payData;
}
@@ -0,0 +1,77 @@
package org.jiayunet.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jiayunet.alipay.AlipayNotifyMessageAbstract;
import org.jiayunet.mapper.PayAlipayFlowMapper;
import org.jiayunet.pojo.po.PayAlipayFlow;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.Map;
/**
* 支付宝支付回调实现
* <p>依赖:MemberProductService(会员订单处理)、PayAlipayFlowMapper(更新支付流水)</p>
* <p>使用表:bg_pay_alipay_flow(更新流水状态)、bg_member_order(通过MemberProductService处理)</p>
*
* @author zk
*/
@Service
@Primary
@Slf4j
@AllArgsConstructor
public class AlipayNotifyMessageAbstractImpl implements AlipayNotifyMessageAbstract {
private final MemberProductService memberProductService;
private final PayAlipayFlowMapper payAlipayFlowMapper;
/**
* 支付回调
* <p>1. 判断流水状态防重复处理 2. 更新支付宝流水 3. 调用公共订单处理逻辑</p>
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void payMessageHandle(Map<String, String> params) {
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
log.info("支付宝回调 outTradeNo:{} tradeNo:{} tradeStatus:{}", outTradeNo, tradeNo, tradeStatus);
// 只处理支付成功
if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) {
log.info("支付宝回调非成功状态,跳过 outTradeNo:{} tradeStatus:{}", outTradeNo, tradeStatus);
return;
}
// 1. 查流水,已处理则直接返回(防重复回调)
PayAlipayFlow flow = payAlipayFlowMapper.selectOne(
new LambdaQueryWrapper<PayAlipayFlow>().eq(PayAlipayFlow::getOrderNo, outTradeNo)
);
if (flow == null) {
log.warn("支付宝回调流水不存在 outTradeNo:{}", outTradeNo);
return;
}
if (flow.getStatus() != 0) {
log.info("支付宝流水已处理,跳过 outTradeNo:{} status:{}", outTradeNo, flow.getStatus());
return;
}
// 2. 更新支付宝流水
payAlipayFlowMapper.update(null, new LambdaUpdateWrapper<PayAlipayFlow>()
.eq(PayAlipayFlow::getId, flow.getId())
.eq(PayAlipayFlow::getStatus, 0)
.set(PayAlipayFlow::getStatus, 1)
.set(PayAlipayFlow::getTradeNo, tradeNo)
.set(PayAlipayFlow::getSuccessTime, Instant.now())
.set(PayAlipayFlow::getNotifyData, params.toString()));
// 3. 调用公共订单处理(更新订单状态 + 发放权限)
memberProductService.handlePaySuccess(outTradeNo);
}
}
@@ -13,6 +13,7 @@ import org.jiayunet.pojo.dto.memberProduct.OrderDetailDto;
import org.jiayunet.pojo.po.*;
import org.jiayunet.tool.UserSecurityTool;
import org.jiayunet.wxPay.WxNativePayAbility;
import org.jiayunet.alipay.AlipayPagePayAbility;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -61,6 +62,12 @@ public class MemberProductService {
@Autowired
private WxNativePayAbility wxNativePayAbility;
@Autowired
private AlipayPagePayAbility alipayPagePayAbility;
@Autowired
private PayAlipayFlowMapper payAlipayFlowMapper;
@Value("${wx_pay.merchant_id:}")
private String merchantId;
@@ -109,19 +116,19 @@ public class MemberProductService {
.eq(MemberOrder::getId, order.getId())
.set(MemberOrder::getOrderNo, orderNo));
// 4. 调支付渠道下单,拿二维码URL
String codeUrl;
// 4. 调支付渠道下单
String payData;
if (payChannel == 1) {
codeUrl = prepayWechat(orderNo, product);
payData = prepayWechat(orderNo, product);
} else {
// TODO 支付宝当面付
codeUrl = prepayAlipay(orderNo, product);
payData = prepayAlipay(orderNo, product);
}
// 5. 返回
CreateOrderDto dto = new CreateOrderDto();
dto.setOrderId(order.getId());
dto.setCodeUrl(codeUrl);
dto.setPayChannel(payChannel);
dto.setPayData(payData);
return dto;
}
@@ -218,11 +225,22 @@ public class MemberProductService {
}
/**
* 支付宝当面付下单
* TODO 接入支付宝当面付SDK,返回二维码URL
* 支付宝电脑网站支付下单
*/
private String prepayAlipay(String orderNo, MemberProduct product) {
throw new BusinessException(BusinessExpCodeEnum.UNKNOWN_ERROR, "支付宝支付暂未开放");
// 创建支付宝流水
PayAlipayFlow flow = new PayAlipayFlow();
flow.setOrderType("member");
flow.setOrderNo(orderNo);
flow.setTotal(product.getPrice());
flow.setStatus(0);
payAlipayFlowMapper.insert(flow);
// 金额转元(分→元)
String totalAmount = String.format("%.2f", product.getPrice() / 100.0);
// 调支付宝下单,返回HTML表单
return alipayPagePayAbility.prepay(orderNo, totalAmount, product.getProductName());
}
/**
@@ -33,6 +33,15 @@ wx_pay:
#回调域名地址
notify_domain: ${API_NOTIFY_DOMAIN:http://127.0.0.1:8080/api/}
# 支付宝支付
alipay:
# status close:关闭 open:打开
status: close
app_id: ${ALIPAY_APP_ID:your_app_id}
private_key: ${ALIPAY_PRIVATE_KEY:your_private_key}
alipay_public_key: ${ALIPAY_PUBLIC_KEY:your_alipay_public_key}
notify_domain: ${API_NOTIFY_DOMAIN:http://127.0.0.1:8080/api/}
app:
# 加密秘钥配置
secret: