支付宝支付前后端流程:SpringBoot整合支付宝支付流程及解决ISV权限不足问题

434 阅读3分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第12篇文章,点击查看活动详情

具体流程可以看支付宝支付文档,之前做过微信支付整个流程,所以大体还是比较类似的,支付宝支付更容易一些。支付宝网页支付返回的是一个form表单,将表单承接,并点击提交即可进入支付宝提供的web支付页面。

官方文档:电脑网站支付:https://opendocs.alipay.com/open/270/105898

前端方面

1、通过接口请求支付宝支付 - 返回的是一个 form表单

async getAliPay() {
  let _params = {
        orderId: this.apply.id,
        amount: this.apply.price,
        name: this.apply.examName
  }
  let { data } = await paymentAlipayApi(_params)
  this.alipayData = data
}

2、定义一个div用于承接支付宝返回的 form 表单内容

<div v-html="alipayData" id="alipay"></div>

3、给一个按钮点击支付

<a-button v-if="apply.status === 'apply'" type="danger" size="large" class="w100" @click="aliPay">去支付</a-button>

aliPay () {
    document.querySelector('form[name="punchout_form"]').submit()
},

后端方面

1、导入依赖

<!--aliPay-->
<dependency>
  <groupId>com.alipay.sdk</groupId>
  <artifactId>alipay-sdk-java</artifactId>
  <version>3.3.49.ALL</version>
</dependency>

2、controller层声明接口及业务处理

@ApiOperation("支付宝发起订单")
@GetMapping(value = "/aliPay", produces = "text/html; charset=utf-8")
public String aliPay(@RequestParam Integer orderId,
                     @RequestParam BigDecimal amount,
                     @RequestParam String name) {
    try {
        return alipayService.pay(orderId, amount, name, "");
    } catch (AlipayApiException e) {
        log.error(LogUtil.getStack(e));
        return null;
    }
}

AlipayService

@Service
public class AlipayService {
    public String pay(Integer orderId, BigDecimal amount, String service, String desc) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(
                AlipayConfig.gateway_url,
                AlipayConfig.app_id,
                AlipayConfig.merchant_private_key,
                AlipayConfig.format,
                AlipayConfig.charset,
                AlipayConfig.alipay_public_key,
                AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url + orderId);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

        /* out_trade_no 商户订单号,商户网站订单系统中唯一订单号,必填
           total_amount 付款金额,必填
           subject 订单名称,必填
           body 商品描述,可空 */

        alipayRequest.setBizContent("{"out_trade_no":""+ orderId +"","
                + ""total_amount":""+ amount +"","
                + ""subject":""+ service +"","
                + ""body":""+ desc +"","
                + ""product_code":"FAST_INSTANT_TRADE_PAY"}");

        //请求
        String result = alipayClient.pageExecute(alipayRequest).getBody();
        int index = result.indexOf("<form");
        result = "<form target="_blank" " + result.substring(index + 6);
        return result;
    }
}

AlipayConfig 就是一些密钥之类的配置,具体不一样,这里面主要的就是记录上面需要的配置,具体可看文档,比如:

// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String app_id = "***"; // 网页支付
// 商户私钥,您的PKCS8格式RSA2私钥
public static String merchant_private_key1 = "***";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String alipay_public_key1 = "***";// 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "https://***/api/alipayNotify";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url = "https://***/signup";
// ......
// 支付宝网关
public static String gateway_url = "https://openapi.alipay.com/gateway.do";

(1)其中 notify_url 就是支付成功之后,支付宝会给你这个接口发送通知,你可以在这里面去做一些支付成功之后的校验和一些业务处理。

需要注意的是这个接口需要在 SpringSecurity 里允许公开访问。

(2)其中 return_url 就是支付成功之后会跳转到你给的这个路由。

(3)其中支付宝公钥,比较好获取

(4)其中商户私钥,获取方法看官方指导:接口加签方式配置说明:opendocs.alipay.com/mini/introd…

3、异步回调接口处理

@ApiOperation("支付宝回调")
@PostMapping("/alipayNotify")
public Map alipayNotify(@RequestParam Map<String, String> params) {
    Map<String, Object> result = new HashMap<>();
    result.put("success", false);
    try {
        //调用SDK验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(
                params,
                AlipayConfig.alipay_public_key,
                AlipayConfig.charset,
                AlipayConfig.sign_type);

        /* 实际验证过程建议商户务必添加以下校验:
        1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
        2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
        3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
        4、验证app_id是否为该商户本身。
        */
        if (signVerified) {//验证成功
            // 应用业务
        } else {// 验证失败
            log.error("Alipay signature check fail: " + params);
        }
    } catch (Exception e) {
        log.error(LogUtil.getStack(e));
    }
    return result;
}

这个异步回调通知就是支付成功之后支付宝给你设置的回调地址发送的。从里面可以拿到支付的订单的信息,然后通过签名校验,如果校验成功,就可以去做一些我们自己的业务处理。

其中该接口需要返回上述代码 reslult 格式的给支付宝(具体格式见官方文档),支付宝收到之后就不会再发生通知,如果没收到或格式不对,就是会继续发通知的。

支付宝支付大体这样,总体流程比微信支付简单一些。

ISV 权限不足常见问题

图片.png

其实上面有提示解决办法链接。

其他接口提示 ISV 权限不足的原因,详见“ISV权限不足自查方案”。

通常都是未签约未开通能力导致的。

图片.png

添加能力,比如:APP支付、手机网站支付、当面付、电脑网站支付。

使用对应能力,得添加该能力,并签约生效才可以。我刚开始电脑网站支付未签约,导致报这个错,签约之后就可以了。