mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-03 19:16:21 +00:00
feat 微信和支付宝聚合支付处理
This commit is contained in:
@@ -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;
|
@@ -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;
|
@@ -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 = "通过付款码发起支付")
|
||||
|
@@ -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")
|
||||
|
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping
|
||||
public class RedirectH5Controller {
|
||||
public class ForwardH5Controller {
|
||||
/**
|
||||
* 将/h5/*的访问请求代理到/h5/index.html*
|
||||
*/
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model.assist;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 微信Jsapi预支付签名返回信息
|
||||
* @author xxm
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class WxJsapiSignModel extends DaxPayResponseModel {
|
||||
|
||||
/** 公众号ID */
|
||||
private String appId;
|
||||
/** 时间戳(秒) */
|
||||
private String timeStamp;
|
||||
/** 随机串 */
|
||||
private String nonceStr;
|
||||
/** 预支付ID, 已经是 prepay_id=xxx 格式 */
|
||||
private String prePayId;
|
||||
/** 微信签名方式 */
|
||||
private String signType;
|
||||
/** 微信签名 */
|
||||
private String paySign;
|
||||
|
||||
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.assist;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.model.assist.WxJsapiSignModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 微信预付订单再次签名参数
|
||||
* @author xxm
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class WxJsapiSignParam extends DaxPayRequest<WxJsapiSignModel>{
|
||||
|
||||
/** 预付订单ID */
|
||||
private String prepayId;
|
||||
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*
|
||||
* @return 请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/assist/getWxJsapiPrePay";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*
|
||||
* @param json json字符串
|
||||
* @return 反序列后的对象
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<WxJsapiSignModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<WxJsapiSignModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package cn.bootx.platform.daxpay.admin.controller;
|
||||
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* 嵌入式前端项目转发控制器, 不用输入 index.html也可以正常访问
|
||||
* @author xxm
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping
|
||||
public class ForwardFrontController {
|
||||
|
||||
/**
|
||||
* 将/front/*的访问请求代理到/h5/index.html*
|
||||
*/
|
||||
@GetMapping("/front/")
|
||||
public String toH5(){
|
||||
return "forward:/front/index.html";
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.result.assist;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 微信Jsapi预支付信息
|
||||
* @author xxm
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "微信Jsapi预支付信息")
|
||||
public class WxJsapiPrePayResult {
|
||||
|
||||
@Schema(description = "公众号ID")
|
||||
private String appId;
|
||||
@Schema(description = "时间戳(秒)")
|
||||
private String timeStamp;
|
||||
@Schema(description = "随机串")
|
||||
private String nonceStr;
|
||||
@Schema(description = "预支付ID, 已经是 prepay_id=xxx 格式")
|
||||
private String prePayId;
|
||||
@Schema(description = "")
|
||||
private String signType;
|
||||
@Schema(description = "")
|
||||
private String paySign;
|
||||
|
||||
|
||||
}
|
@@ -1,5 +1,8 @@
|
||||
package cn.bootx.platform.daxpay.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.daxpay.service.core.notice.service.PayReturnService;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.alipay.AliPayReturnParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -13,16 +16,19 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
* @author xxm
|
||||
* @since 2024/1/13
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@Tag(name = "支付同步通知控制器")
|
||||
@RestController
|
||||
@RequestMapping("/pay/return")
|
||||
@RequiredArgsConstructor
|
||||
public class PayReturnController {
|
||||
private final PayReturnService payReturnService;
|
||||
|
||||
@Operation(summary = "支付宝同步通知")
|
||||
@GetMapping("/alipay")
|
||||
public ModelAndView alipay(){
|
||||
return null;
|
||||
public ModelAndView alipay(AliPayReturnParam param){
|
||||
String url = payReturnService.alipay(param);
|
||||
return new ModelAndView("redirect:" + url);
|
||||
}
|
||||
|
||||
@Operation(summary = "微信同步通知")
|
||||
|
@@ -1,11 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.gateway.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.timeout.task.PayExpiredTimeTask;
|
||||
import cn.bootx.platform.daxpay.service.core.timeout.task.PayWaitOrderSyncTask;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
@@ -52,5 +50,12 @@ public class TestController {
|
||||
return Res.ok(name);
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "微信回调测试")
|
||||
@GetMapping(value = {"/wxcs/","wxcs"})
|
||||
public String wxcs(){
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -6,11 +6,9 @@ import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.daxpay.param.assist.WxAccessTokenParam;
|
||||
import cn.bootx.platform.daxpay.param.assist.WxAuthUrlParam;
|
||||
import cn.bootx.platform.daxpay.param.assist.WxJsapiPrePayParam;
|
||||
import cn.bootx.platform.daxpay.result.DaxResult;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxAccessTokenResult;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxAuthUrlResult;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxJsapiPrePayResult;
|
||||
import cn.bootx.platform.daxpay.service.annotation.PaymentApi;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.assist.service.UniPayAssistService;
|
||||
import cn.bootx.platform.daxpay.util.DaxRes;
|
||||
@@ -51,13 +49,4 @@ public class UniPayAssistController {
|
||||
return Res.ok(uniPayAssistService.getWxAccessToken(param));
|
||||
}
|
||||
|
||||
@CountTime
|
||||
@PaymentApi("getWxJsapiPrePay")
|
||||
@Operation(summary = "获取微信预支付信息")
|
||||
@PostMapping("/getWxJsapiPrePay")
|
||||
public ResResult<WxJsapiPrePayResult> getWxJsapiPrePay(@RequestBody WxJsapiPrePayParam param){
|
||||
return Res.ok(uniPayAssistService.getWxJsapiPrePay(param));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,21 @@
|
||||
package cn.bootx.platform.daxpay.service.configuration;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 演示模块配置类
|
||||
* @author xxm
|
||||
* @since 2024/2/8
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "dax-pay")
|
||||
public class DaxPayProperties {
|
||||
/** 服务地址 */
|
||||
private String serverUrl;
|
||||
|
||||
/** 前端地址 */
|
||||
private String frontUrl;
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package cn.bootx.platform.daxpay.service.core.notice.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付同步通知类
|
||||
* @author xxm
|
||||
* @since 2024/1/7
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "支付同步通知类")
|
||||
public class PayReturnResult {
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
package cn.bootx.platform.daxpay.service.core.notice.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.configuration.DaxPayProperties;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderExtraManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayOrderQueryService;
|
||||
import cn.bootx.platform.daxpay.service.param.channel.alipay.AliPayReturnParam;
|
||||
import cn.hutool.core.net.URLEncodeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付同步跳转服务类
|
||||
* @author xxm
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayReturnService {
|
||||
private final PayOrderQueryService payOrderQueryService;
|
||||
private final PayOrderExtraManager payOrderExtraManager;
|
||||
|
||||
private final DaxPayProperties properties;
|
||||
|
||||
/**
|
||||
* 支付宝同步回调
|
||||
*/
|
||||
public String alipay(AliPayReturnParam param){
|
||||
PayOrderExtra payOrderExtra = payOrderExtraManager.findById(param.getOut_trade_no()).orElse(null);
|
||||
PayOrder prOrder = payOrderQueryService.findById(param.getOut_trade_no()).orElse(null);
|
||||
if (Objects.isNull(payOrderExtra) || Objects.isNull(prOrder)){
|
||||
return StrUtil.format("{}/result/error?msg={}", properties.getFrontUrl(), URLEncodeUtil.encode("支付订单有问题,请排查"));
|
||||
}
|
||||
|
||||
// 如果不需要同步回调, 跳转到支付成功页面
|
||||
if (payOrderExtra.isNotReturn()){
|
||||
return StrUtil.format("{}/result/success?msg={}", properties.getFrontUrl(), URLEncodeUtil.encode("支付成功..."));
|
||||
}
|
||||
return StrUtil.format("{}?paymentId={}&businessNo={}", payOrderExtra.getReturnUrl(),prOrder.getId(),prOrder.getBusinessNo());
|
||||
}
|
||||
}
|
@@ -76,6 +76,8 @@ public class PayBuilder {
|
||||
.setDescription(payParam.getDescription())
|
||||
.setNotNotify(payParam.isNotNotify())
|
||||
.setNotifyUrl(noticeInfo.getNotifyUrl())
|
||||
.setNotReturn(payParam.isNotReturn())
|
||||
.setReturnUrl(noticeInfo.getReturnUrl())
|
||||
.setSign(payParam.getSign())
|
||||
.setSignType(platform.getSignType())
|
||||
.setAttach(payParam.getAttach())
|
||||
|
@@ -45,6 +45,15 @@ public class PayOrderExtra extends MpBaseEntity implements EntityBaseFunction<Pa
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String notifyUrl;
|
||||
|
||||
/** 是否不需要同步调转通知 */
|
||||
@DbColumn(comment = "是否不需要同步调转通知")
|
||||
private boolean notReturn;
|
||||
|
||||
/** 同步调转地址 */
|
||||
@DbColumn(comment = "同步调转地址,以最后一次为准")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String returnUrl;
|
||||
|
||||
/** 签名类型 */
|
||||
@DbColumn(comment = "签名类型")
|
||||
private String signType;
|
||||
|
@@ -2,16 +2,10 @@ package cn.bootx.platform.daxpay.service.core.payment.assist.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.assist.WxAccessTokenParam;
|
||||
import cn.bootx.platform.daxpay.param.assist.WxAuthUrlParam;
|
||||
import cn.bootx.platform.daxpay.param.assist.WxJsapiPrePayParam;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxAccessTokenResult;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxAuthUrlResult;
|
||||
import cn.bootx.platform.daxpay.result.assist.WxJsapiPrePayResult;
|
||||
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -22,9 +16,6 @@ import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付支撑服务类
|
||||
* @author xxm
|
||||
@@ -58,21 +49,6 @@ public class UniPayAssistService {
|
||||
.setOpenId(accessToken.getOpenId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信预支付信息
|
||||
*/
|
||||
public WxJsapiPrePayResult getWxJsapiPrePay(WxJsapiPrePayParam param){
|
||||
WeChatPayConfig config = weChatPayConfigService.getConfig();
|
||||
String apiKey;
|
||||
if (Objects.equals(config.getApiKeyV2(), WeChatPayCode.API_V3)){
|
||||
apiKey = config.getApiKeyV3();
|
||||
} else {
|
||||
apiKey = config.getApiKeyV2();
|
||||
}
|
||||
Map<String, String> map = WxPayKit.prepayIdCreateSign(param.getPrepayId(), config.getWxAppId(), apiKey, SignType.HMACSHA256);
|
||||
return BeanUtil.toBean(map, WxJsapiPrePayResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信公众号API的Service
|
||||
*/
|
||||
|
@@ -156,10 +156,13 @@ public class PayAssistService {
|
||||
PayOrderExtra payOrderExtra = payOrderExtraManager.findById(paymentId)
|
||||
.orElseThrow(() -> new DataNotExistException("支付订单不存在"));
|
||||
String notifyUrl = PaymentContextLocal.get().getNoticeInfo().getNotifyUrl();
|
||||
String returnUrl = PaymentContextLocal.get().getNoticeInfo().getReturnUrl();
|
||||
payOrderExtra.setReqTime(payParam.getReqTime())
|
||||
.setSign(payParam.getSign())
|
||||
.setNotNotify(payParam.isNotNotify())
|
||||
.setNotifyUrl(notifyUrl)
|
||||
.setNotReturn(payParam.isNotReturn())
|
||||
.setReturnUrl(returnUrl)
|
||||
.setAttach(payParam.getAttach())
|
||||
.setClientIp(payParam.getClientIp());
|
||||
payOrderExtraManager.updateById(payOrderExtra);
|
||||
|
@@ -0,0 +1,92 @@
|
||||
package cn.bootx.platform.daxpay.service.param.channel.alipay;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 微信同步回调参数
|
||||
* @author xxm
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "微信同步回调参数")
|
||||
public class AliPayReturnParam {
|
||||
|
||||
/**
|
||||
* 编码格式,如 utf-8、gbk、gb2312 等。
|
||||
*/
|
||||
@Schema(description = "编码格式")
|
||||
@JsonAlias("charset")
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* 商家网站唯一订单号, 即为系统中的支付订单号
|
||||
*/
|
||||
@Schema(description = "支付订单号")
|
||||
@JsonAlias("out_trade_no")
|
||||
private Long out_trade_no;
|
||||
|
||||
/**
|
||||
* 该交易在支付宝系统中的交易流水号。最长 64 位。
|
||||
* 示例值:2016081121001004630200142207
|
||||
*/
|
||||
@Schema(description = "网关订单号")
|
||||
@JsonAlias("trade_no")
|
||||
private String trade_no;
|
||||
|
||||
@Schema(description = "接口名称")
|
||||
@JsonAlias("method")
|
||||
private String method;
|
||||
|
||||
@Schema(description = "支付金额")
|
||||
@JsonAlias("total_amount")
|
||||
private String total_amount;
|
||||
|
||||
@Schema(description = "签名")
|
||||
@JsonAlias("sign")
|
||||
private String sign;
|
||||
|
||||
@Schema(description = "不确定是什么")
|
||||
@JsonAlias("auth_app_id")
|
||||
private String auth_app_id;
|
||||
|
||||
/**
|
||||
* 支付宝分配给开发者的应用ID。
|
||||
* 示例值:2016040501024706
|
||||
*/
|
||||
@Schema(description = "应用ID")
|
||||
@JsonAlias("app_id")
|
||||
private String app_id;
|
||||
|
||||
/**
|
||||
* 调用的接口版本,固定为:1.0。
|
||||
*/
|
||||
@Schema(description = "调用的接口版本")
|
||||
@JsonAlias("version")
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 签名算法类型,目前支持 RSA2 和 RSA,推荐使用RSA2
|
||||
*/
|
||||
@Schema(description = "签名算法类型")
|
||||
@JsonAlias("sign_type")
|
||||
private String sign_type;
|
||||
|
||||
/**
|
||||
* 收款支付宝账号对应的支付宝唯一用户号。以 2088 开头的纯 16 位数字。
|
||||
* 示例值:2088111111116894
|
||||
*/
|
||||
@Schema(description = "收款支付宝账号对应的支付宝唯一用户号")
|
||||
@JsonAlias("seller_id")
|
||||
private String seller_id;
|
||||
|
||||
/**
|
||||
* 前台回跳的时间,格式:yyyy-MM-dd HH:mm:ss。
|
||||
*/
|
||||
@Schema(description = "前台回跳的时间")
|
||||
@JsonAlias("timestamp")
|
||||
private String timestamp;
|
||||
}
|
@@ -155,11 +155,15 @@ dromara:
|
||||
storage-path: D:/data/files/
|
||||
# 支付系统配置
|
||||
dax-pay:
|
||||
# 网关地址
|
||||
server-url: http://pay1.bootx.cn
|
||||
# 前端地址
|
||||
front-url: http://pay1.bootx.cn/h5/#
|
||||
# 演示模块
|
||||
demo:
|
||||
# 网关地址
|
||||
server-url: http://pay1.bootx.cn
|
||||
# 前端地址
|
||||
front-url: http://pay1.bootx.cn/h5
|
||||
front-url: http://pay1.bootx.cn/h5/#
|
||||
# 签名秘钥
|
||||
sign-secret: 123456
|
||||
|
Reference in New Issue
Block a user