支付宝支付功能接入(SprinBoot-网站支付)

admin2025-12-14 21:25:202165

目录

概述

接入过程

一、前期准备

二、创建应用并配置加签方式

三、应用提交审核

四、签约/开通支付产品

五、支付API代码查看/编写

六、实际开发

测试

支付测试

回调测试

订单查询测试

演示代码地址(Gitee)

概述

本文章介绍如何接入支付宝支付功能。

使用SpringBoot作为后端代码提供示例,前端使用Vue3做表单提交测试。

本文仅演示“电脑网站支付”这一种支付方式,但是其他支付方式如“JSAPI支付”,“手机网站支付”等等接入过程基本一样,看完本文应当可以一通百通。

接入过程

一、前期准备

首先需要注册/登录支付宝的“开放平台”和“商家平台”。

1.开放平台(open.alipay.com):用于创建应用并获取APPID和密钥等信息。

2.商家平台(b.alipay.com):用于设置收款信息和支付产品的签约等操作。

二、创建应用并配置加签方式

1. 我们需要到“开放平台”创建一个应用,点击右上角“控制台”

2. 创建自己需求类型的应用,本文使用网站支付测试,因此选择“网页/移动应用”。

3. 填写应用基本信息

值得注意的是应用名称不要带有"测试"或"test"之类的字样,否则应用提交审核通不过的。

4. 设置“接口加签方式”

进入刚创建的应用中,在“开发设置”里找到“接口加签方式”进行设置。

完成加签方式的设置之后,我们会拿到调用支付接口时的参数“应用私钥”,“支付宝公钥”...

点击设置后,按照表单提示一步步来:

生成应用密钥后自己妥善保管,将“应用公钥”复制回传到刚才的位置。

上传后我们就可以得到参数“支付宝公钥”

至此,我们就已经拿到了调用支付接口时的一些参数“应用的公私钥”,“支付宝公钥”。

三、应用提交审核

在我们设置了接口加签方式之后,就可以先提交审核了。

如果不提交审核可能会导致支付接口调用失败,提示错误"isv.invalid-app-id"。

四、签约/开通支付产品

在应用审核期间,我们可以到“商家平台(b.alipay.com)”去开通我们对应的支付产品。

例如本文演示使用的网站支付,所以我们就应该点击“电脑网站支付”这个产品进行签约开通。

开通信息按要求填写提交申请等待一下基本就审核好了。

如果没有签约开通产品,会提示错误:ISV权限不足....

五、支付API代码查看/编写

在我们的应用审核成功并且支付产品签约开通成功之后,我们就可以进行代码的编写了。

在编写之前,我们需要先了解支付宝支付API的介绍。

我们进入支付产品最下面找到开放文档:

在开发文档中会看到官方提供的开发SDK和API列表。

以Java为例,我们能找到Maven依赖包的描述。

点击“API列表”能看到SDK使用的代码示例和请求和响应参数的说明

六、实际开发

在此仅演示“下单支付”,“订单查询”和“支付成功回调”的代码。

其他功能代码请参考官网“API列表”进行编写。

如下仅贴出关键性代码,完整代码调用链请到最后的"Gitee演示Demo代码"处获取查看。

@RestController

@RequestMapping("/alipay")

@Api("支付")

@CrossOrigin

public class AliPayController {

private static final String GATEWAY_URL = "https://openapi.alipay.com/gateway.do";

@Autowired

private AliPayConfig aliPayConfig;

/**

*

* @param aliPay 支付请求参数

* @param httpResponse ·

* @throws Exception ·

*/

@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxx

public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {

AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),

aliPayConfig.getAppPrivateKey(), FORMAT_JSON, CHARSET_UTF8, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE_RSA2);

AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

request.setNotifyUrl(aliPayConfig.getNotifyUrl());

request.setBizContent("{\"out_trade_no\":\"" + aliPay.getTraceNo() + "\","

+ "\"total_amount\":\"" + aliPay.getTotalAmount() + "\","

+ "\"subject\":\"" + aliPay.getSubject() + "\","

+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

String form = "";

try {

form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单

} catch (AlipayApiException e) {

e.printStackTrace();

}

httpResponse.setContentType("text/html;charset=" + CHARSET_UTF8);

httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面

httpResponse.getWriter().flush();

httpResponse.getWriter().close();

}

/**

* 订单查询

* @param out_trade_no 商户订单号

* @param trade_no 支付宝交易订单号

* @throws AlipayApiException ·

*/

@GetMapping("/queryOrder/{out_trade_no}/{trade_no}")

public void queryOrder(@PathVariable("out_trade_no") String out_trade_no, @PathVariable("trade_no") String trade_no) throws AlipayApiException {

// 初始化SDK

AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),

aliPayConfig.getAppPrivateKey(), FORMAT_JSON, CHARSET_UTF8, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE_RSA2);

// 构造请求参数以调用接口

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

AlipayTradeQueryModel model = new AlipayTradeQueryModel();

// 设置订单支付时传入的商户订单号

model.setOutTradeNo(out_trade_no);

// 设置支付宝交易号

model.setTradeNo(trade_no);

// 设置查询选项

List queryOptions = new ArrayList();

/*

* 交易结算信息: trade_settle_info

* 交易支付使用的资金渠道: fund_bill_list

* 交易支付时使用的所有优惠券信息: voucher_detail_list

* 交易支付使用单品券优惠的商品优惠信息: discount_goods_detail

* 商家优惠金额: mdiscount_amount

* 医保信息: medical_insurance_info

*/

queryOptions.add("trade_settle_info"); // 交易结算信息

model.setQueryOptions(queryOptions);

request.setBizModel(model);

AlipayTradeQueryResponse response = alipayClient.execute(request);

System.out.println("===>订单信息:\n" + response.getBody());

if (response.isSuccess()) {

System.out.println("调用成功");

} else {

System.out.println("调用失败");

// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接

// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);

// System.out.println(diagnosisUrl);

}

}

@PostMapping("/notify") // 注意这里必须是POST接口

public String payNotify(HttpServletRequest request) throws Exception {

if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {

System.out.println("=========支付成功回调========");

Map params = new HashMap<>();

Map requestParams = request.getParameterMap();

for (String name : requestParams.keySet()) {

params.put(name, request.getParameter(name));

// System.out.println(name + " = " + request.getParameter(name));

}

// 支付宝验签

if (Factory.Payment.Common().verifyNotify(params)) {

// 验签通过

System.out.println("交易名称: " + params.get("subject"));

System.out.println("交易状态: " + params.get("trade_status"));

System.out.println("支付宝交易凭证号(trade_no): " + params.get("trade_no"));

System.out.println("商户订单号(out_trade_no): " + params.get("out_trade_no"));

System.out.println("交易金额: " + params.get("total_amount"));

System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));

System.out.println("买家付款时间: " + params.get("gmt_payment"));

System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));

}

}

return "success";

}

}

实际上,如上的所有流程描述皆在官方的文档中,但是为什么还是有许多人“博客文章”优先,以至于出现“收费博文浏览”的博文设定,也许是当下人们丢失了沉稳的耐心。

测试

支付测试

前端测试表单代码: