feat 微信和支付宝聚合支付处理

This commit is contained in:
bootx
2024-02-11 21:47:02 +08:00
parent 7d65add2ca
commit 48e7a6cc5f
24 changed files with 329 additions and 270 deletions

View File

@@ -1,4 +1,4 @@
package cn.bootx.platform.daxpay.demo.config;
package cn.bootx.platform.daxpay.demo.configuration;
import cn.bootx.platform.daxpay.sdk.code.SignTypeEnum;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package cn.bootx.platform.daxpay.demo.config;
package cn.bootx.platform.daxpay.demo.configuration;
import cn.bootx.platform.daxpay.sdk.net.DaxPayConfig;
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;

View File

@@ -6,6 +6,7 @@ import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.daxpay.demo.domain.AggregatePayInfo;
import cn.bootx.platform.daxpay.demo.param.AggregateSimplePayParam;
import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
import cn.bootx.platform.daxpay.demo.result.WxJsapiSignResult;
import cn.bootx.platform.daxpay.demo.service.AggregateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -47,10 +48,22 @@ public class AggregateController {
return new ModelAndView("redirect:" + url);
}
@Operation(summary = "通过聚合支付码发起支付")
@PostMapping("/qrPay")
public ResResult<PayOrderResult> qrPa(String code){
return Res.ok(aggregateService.aliQrPay(code));
@Operation(summary = "支付宝通过聚合支付码发起支付")
@PostMapping("/aliH5Pay")
public ResResult<PayOrderResult> aliH5Pay(String code){
return Res.ok(aggregateService.aliH5Pay(code));
}
@Operation(summary = "微信授权回调页面")
@GetMapping("/wxAuthCallback")
public ModelAndView wxAuthCallback(@RequestParam("state") String aggregateCode, @RequestParam("code") String authCode){
return new ModelAndView("redirect:" + aggregateService.wxAuthCallback(aggregateCode, authCode));
}
@Operation(summary = "获取微信支付调起Jsapi支付的信息")
@PostMapping("/getWxJsapiPay")
public ResResult<WxJsapiSignResult> getWxJsapiPay(String aggregateCode, String openId){
return Res.ok(aggregateService.wxJsapiPrePay(aggregateCode, openId));
}
@Operation(summary = "通过付款码发起支付")

View File

@@ -6,7 +6,7 @@ import cn.bootx.platform.common.core.rest.ResResult;
import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.bootx.platform.daxpay.demo.param.CashierSimplePayParam;
import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
import cn.bootx.platform.daxpay.demo.service.DaxPayCashierService;
import cn.bootx.platform.daxpay.demo.service.CashierService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
@@ -24,7 +24,7 @@ import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
public class CashierController {
private final DaxPayCashierService cashierService;
private final CashierService cashierService;
@Operation(summary = "创建支付订单并发起")
@PostMapping("/simplePayCashier")

View File

@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
*/
@Controller
@RequestMapping
public class RedirectH5Controller {
public class ForwardH5Controller {
/**
* /h5/*的访问请求代理到/h5/index.html*
*/

View File

@@ -1,5 +1,6 @@
package cn.bootx.platform.daxpay.demo.result;
import cn.hutool.core.annotation.Alias;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -13,17 +14,17 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
@Schema(title = "微信Jsapi预支付签名返回信息")
public class WxJsapiSignResult {
/** 公众号ID */
@Schema(description = "公众号ID")
private String appId;
/** 时间戳(秒) */
@Schema(description = "时间戳(秒)")
private String timeStamp;
/** 随机串 */
@Schema(description = "随机串")
private String nonceStr;
/** 预支付ID, 已经是 prepay_id=xxx 格式 */
@Alias("package")
@Schema(description = "预支付ID, 已经是 prepay_id=xxx 格式")
private String prePayId;
/** 微信签名方式 */
@Schema(description = "签名类型")
private String signType;
/** 微信签名 */
@Schema(description = "签名方式")
private String paySign;
}

View File

@@ -3,7 +3,7 @@ package cn.bootx.platform.daxpay.demo.service;
import cn.bootx.platform.common.core.exception.BizException;
import cn.bootx.platform.common.redis.RedisClient;
import cn.bootx.platform.common.spring.util.WebServletUtil;
import cn.bootx.platform.daxpay.demo.config.DaxPayDemoProperties;
import cn.bootx.platform.daxpay.demo.configuration.DaxPayDemoProperties;
import cn.bootx.platform.daxpay.demo.domain.AggregatePayInfo;
import cn.bootx.platform.daxpay.demo.param.AggregateSimplePayParam;
import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
@@ -13,16 +13,15 @@ import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAccessTokenModel;
import cn.bootx.platform.daxpay.sdk.model.assist.WxAuthUrlModel;
import cn.bootx.platform.daxpay.sdk.model.assist.WxJsapiSignModel;
import cn.bootx.platform.daxpay.sdk.model.pay.PayOrderModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
import cn.bootx.platform.daxpay.sdk.param.assist.WxAccessTokenParam;
import cn.bootx.platform.daxpay.sdk.param.assist.WxAuthUrlParam;
import cn.bootx.platform.daxpay.sdk.param.assist.WxJsapiSignParam;
import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
import cn.bootx.platform.daxpay.sdk.param.pay.SimplePayParam;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
@@ -71,7 +70,7 @@ public class AggregateService {
*/
public AggregatePayInfo getInfo(String key) {
String jsonStr = Optional.ofNullable(redisClient.get(PREFIX_KEY + key))
.orElseThrow(() -> new BizException("支付超时"));
.orElseThrow(() -> new BizException("聚合支付码已过期..."));
return JSONUtil.toBean(jsonStr, AggregatePayInfo.class);
}
@@ -83,12 +82,12 @@ public class AggregateService {
boolean exists = redisClient.exists(PREFIX_KEY + code);
if (!exists){
// 跳转到过期页面
return null;
return StrUtil.format("{}/result/error?msg={}", daxPayDemoProperties.getFrontUrl(), URLEncodeUtil.encode("聚合支付码已过期..."));
}
// 根据UA判断是什么环境
if (ua.contains(AggregatePayEnum.UA_ALI_PAY.getCode())) {
// 跳转支付宝中间页
return StrUtil.format("{}/#/cashier/alipay", daxPayDemoProperties.getFrontUrl());
return StrUtil.format("{}/aggregate/alipay?code={}", daxPayDemoProperties.getFrontUrl(),code);
}
else if (ua.contains(AggregatePayEnum.UA_WECHAT_PAY.getCode())) {
// 微信重定向到中间页, 因为微信需要授权后才能发起支付
@@ -96,59 +95,99 @@ public class AggregateService {
}
else {
// 跳转到异常页
return null;
return StrUtil.format("{}/result/error?msg={}", daxPayDemoProperties.getFrontUrl(), URLEncodeUtil.encode("请使用微信或支付宝扫码支付"));
}
}
/**
* 微信Jsapi发起支付, 返回预支付信息, 从页面调起支付, 分为下面三个步骤:
* 1. 获取微信OpenId
* 2. 调用支付接口拿到预支付ID
* 3. 对预支付ID签名, 拿到页面调起支付参数并返回
* 微信jsapi支付 - 跳转到授权页面
*/
public WxJsapiSignResult wxJsapiPau(String aggregateCode, String authCode) {
private String wxJsapiAuth(String code) {
// 回调地址为 结算台微信jsapi支付的回调地址
WxAuthUrlParam wxAuthUrlParam = new WxAuthUrlParam();
wxAuthUrlParam.setState(code);
// 1. 获取微信OpenId
String openId = this.getOpenId(authCode);
// 2. 发起预支付
PayOrderModel payOrderModel = this.wxJsapiPrePay(aggregateCode, openId);
// 3. 预付订单再次签名, 调用起页面的支付弹窗
WxJsapiSignParam wxJsapiSignParam = new WxJsapiSignParam();
wxJsapiSignParam.setPrepayId(payOrderModel.getPayBody());
DaxPayResult<WxJsapiSignModel> execute = DaxPayKit.execute(wxJsapiSignParam);
// 判断是否支付成功
String url = StrUtil.format("{}/demo/aggregate/wxAuthCallback", daxPayDemoProperties.getServerUrl());
wxAuthUrlParam.setUrl(url);
wxAuthUrlParam.setState(code);
DaxPayResult<WxAuthUrlModel> execute = DaxPayKit.execute(wxAuthUrlParam);
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
// 微信授权页面链接
return execute.getData().getUrl();
}
WxJsapiSignResult wxJsapiSignResult = new WxJsapiSignResult();
BeanUtil.copyProperties(execute.getData(), wxJsapiSignResult);
return wxJsapiSignResult;
/**
* 微信授权回调页面, 然后重定向到前端页面中, 携带openid
*/
public String wxAuthCallback(String aggregateCode, String authCode) {
// 获取微信OpenId
String openId = this.getOpenId(authCode);
return StrUtil.format("{}/aggregate/wechatPay?aggregateCode={}&openId={}",
daxPayDemoProperties.getFrontUrl(),
aggregateCode,
openId);
}
/**
* 支付宝发起支付
* 调用微信支付, 返回jsapi信息, 从页面调起支付
*/
public PayOrderResult aliQrPay(String code) {
AggregatePayInfo aggregatePayInfo = getInfo(code);
public WxJsapiSignResult wxJsapiPrePay(String aggregateCode, String openId) {
AggregatePayInfo aggregatePayInfo = getInfo(aggregateCode);
// 拼装支付发起参数
SimplePayParam simplePayParam = new SimplePayParam();
simplePayParam.setBusinessNo(aggregatePayInfo.getBusinessNo());
simplePayParam.setTitle(aggregatePayInfo.getTitle());
simplePayParam.setAmount(aggregatePayInfo.getAmount());
simplePayParam.setChannel(PayChannelEnum.ALI.getCode());
simplePayParam.setPayWay(PayWayEnum.QRCODE.getCode());
simplePayParam.setChannel(PayChannelEnum.WECHAT.getCode());
simplePayParam.setPayWay(PayWayEnum.JSAPI.getCode());
// 设置微信专属请求参数
WeChatPayParam weChatPayParam = new WeChatPayParam();
weChatPayParam.setOpenId(openId);
simplePayParam.setChannelParam(weChatPayParam);
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("127.0.0.1");
simplePayParam.setClientIp(ip);
// 异步回调地址
simplePayParam.setNotifyUrl("http://localhost:9000");
// 同步回调地址
simplePayParam.setReturnUrl("http://localhost:9000");
simplePayParam.setNotNotify(true);
// 同步回调地址 无效
simplePayParam.setReturnUrl(StrUtil.format("{}/result/success", daxPayDemoProperties.getFrontUrl()));
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(simplePayParam);
// 判断是否支付成功
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
return JSONUtil.toBean(execute.getData().getPayBody(), WxJsapiSignResult.class);
}
/**
* 支付宝发起支付 使用 wep 支付调起支付
*/
public PayOrderResult aliH5Pay(String code) {
AggregatePayInfo aggregatePayInfo = getInfo(code);
SimplePayParam simplePayParam = new SimplePayParam();
simplePayParam.setBusinessNo(aggregatePayInfo.getBusinessNo());
simplePayParam.setTitle(aggregatePayInfo.getTitle());
simplePayParam.setAmount(aggregatePayInfo.getAmount());
simplePayParam.setChannel(PayChannelEnum.ALI.getCode());
simplePayParam.setPayWay(PayWayEnum.WAP.getCode());
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("127.0.0.1");
simplePayParam.setClientIp(ip);
// 异步回调地址
simplePayParam.setNotNotify(true);
// 支付成功同步回调地址
simplePayParam.setReturnUrl(StrUtil.format("{}/result/success", daxPayDemoProperties.getFrontUrl()));
// 中途退出 目前经测试不生效
simplePayParam.setQuitUrl(String.format("{}/result/error", daxPayDemoProperties.getFrontUrl()));
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(simplePayParam);
@@ -184,24 +223,6 @@ public class AggregateService {
}
}
/**
* 微信jsapi支付 - 跳转到授权页面
*/
private String wxJsapiAuth(String code) {
// 回调地址为 结算台微信jsapi支付的回调地址
WxAuthUrlParam wxAuthUrlParam = new WxAuthUrlParam();
wxAuthUrlParam.setState(code);
String url = StrUtil.format("{}/#/cashier/wxJsapiPay", daxPayDemoProperties.getFrontUrl());
wxAuthUrlParam.setUrl(url);
DaxPayResult<WxAuthUrlModel> execute = DaxPayKit.execute(wxAuthUrlParam);
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
return execute.getData().getUrl();
}
/**
* 获取微信OpenId
@@ -219,40 +240,4 @@ public class AggregateService {
return result.getData().getOpenId();
}
/**
* 调用微信支付, 拿到预支付ID
*/
private PayOrderModel wxJsapiPrePay(String aggregateCode, String openId) {
AggregatePayInfo aggregatePayInfo = getInfo(aggregateCode);
// 拼装支付发起参数
SimplePayParam simplePayParam = new SimplePayParam();
simplePayParam.setBusinessNo(aggregatePayInfo.getBusinessNo());
simplePayParam.setTitle(aggregatePayInfo.getTitle());
simplePayParam.setAmount(aggregatePayInfo.getAmount());
simplePayParam.setChannel(PayChannelEnum.ALI.getCode());
simplePayParam.setPayWay(PayWayEnum.QRCODE.getCode());
// 设置微信专属请求参数
WeChatPayParam weChatPayParam = new WeChatPayParam();
weChatPayParam.setOpenId(openId);
simplePayParam.setChannelParam(weChatPayParam);
String ip = Optional.ofNullable(WebServletUtil.getRequest())
.map(ServletUtil::getClientIP)
.orElse("127.0.0.1");
simplePayParam.setClientIp(ip);
// 异步回调地址
simplePayParam.setNotifyUrl("http://localhost:9000");
// 同步回调地址
simplePayParam.setReturnUrl("http://localhost:9000");
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(simplePayParam);
// 判断是否支付成功
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}
return execute.getData();
}
}

View File

@@ -35,7 +35,7 @@ import java.util.Optional;
@Slf4j
@Service
@RequiredArgsConstructor
public class DaxPayCashierService {
public class CashierService {
/**
* 结算台简单支付, 创建支付订单并拉起支付
@@ -111,6 +111,11 @@ public class DaxPayCashierService {
QueryPayOrderParam queryPayOrderParam = new QueryPayOrderParam();
queryPayOrderParam.setBusinessNo(businessNo);
DaxPayResult<QueryPayOrderModel> execute = DaxPayKit.execute(queryPayOrderParam);
// 未查询到订单
if (execute.getCode() == 10010){
return false;
}
if (execute.getCode() != 0){
throw new BizException(execute.getMsg());
}