> 技术文档 > 一文讲透Java调用支付宝沙箱支付_支付宝沙盒

一文讲透Java调用支付宝沙箱支付_支付宝沙盒


支付宝沙箱支付

一、支付宝环境配置

1.支付宝环境配置平台支付宝开放平台 (alipay.com)

2.创建账号,补全基础信息,登录平台

登录

3.选择控制台

4.拉到最下方,点击沙箱支付

5.沙箱基本信息和注意事项介绍

6.沙箱支付配置重要参数

6.1支付的APPID

APPID:

6.2支付宝的公钥和秘钥:公钥和秘钥有两种获取方式,一种是系统默认秘钥,另一种是自定义秘钥,最好选择自定义秘钥,获取自定义秘钥需要下载秘钥工具,下载地址:小程序文档 - 支付宝文档中心

自定义秘钥:

1.下载秘钥工具

注意:安装路径不要含有空格

下载好后双击安装:

安装完成后获取秘钥:

生成应用公钥和应用私钥:注意保存到txt文件备份

配置接口加签方式:

点击设置并查看,将刚才生成的应用公钥复制进去,点击保存

点击保存,现在已经介入支付宝开放平台

此时,接口加签方式已经启用

二、设置内网穿透环境——NATAPP内网穿透工具

NATAPP官网:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具

1.创建隧道

1.1注册账户

1.2登录后,创建免费隧道

1.3购买完成后,在我的隧道里面会有刚才的购买记录,这里的Autotoken是重要参数,后面会用到

1.4点击配置修改主机本地地址和项目的端口号,更改完成后点击修改

2.下载NATAPP客户端

2.1下载

选择对应的系统下载即可:

2.2解压

3.运行Natapp

3.1注意运行方式:不要直接双击运行,需要在目录上输入cmd

3.2在命令行中输入以下命令

natapp.exe -authtoken=你的免费隧道authtoken

启动成功如下图:

三、诺依框架实际后端开发

1.引入依赖

    com.alipay.sdk    alipay-sdk-java    4.9.28.ALL

2.在application.yml创建沙箱支付配置文件

注意:每次使用都要在notapp重新生成和确认notifyUrl

# 支付通知的回调地址,支付宝会在支付完成后通知这个地址 异步通知
notifyUrl: http://内网穿透映射地址//alipay/notify
其中alipay为controller的RequestMapping

alipay: # 应用ID,标识你的应用 appId: # 应用私钥,用于签名请求 appPrivateKey: # 应用公钥,用于验证支付宝的响应 alipayPublicKey: # 支付通知的回调地址,支付宝会在支付完成后通知这个地址 notifyUrl: http://内网穿透映射地址//alipay/notify # 页面跳转地址,支付完成后跳转到此URL returnUrl: https://www.baidu.com/s?ie=UTF-8&wd=%E5%8C%97%E4%BA%AC%E6%97%B6%E9%97%B4 # 签名类型,通常为RSA2 signType: RSA2 # 字符编码,通常为utf-8 charset: utf-8 # 支付宝网关地址,用于发送请求 gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do

注意:一旦换ip就要重新配置映射地址

3.项目结构创建

3.1创建commom包,在commom包下创建支付配置类AliPayConfig.java,进行支付属性映射

3.2创建controller包,在controller包下创建支付接口类AliPayController.java,调用支付接口

添加支付宝沙箱网关地址:

// ⽀付宝沙箱⽹关地址 private static final String GATEWAY_URL = \"https://openapi-sandbox.dl.alipaydev.com/gateway.do\";

发起支付请求代码:

package com.ruoyi.controller;import com.alibaba.fastjson.JSON;import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import com.alipay.api.request.AlipayTradePagePayRequest;import com.ruoyi.commom.AliPayConfig;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;import java.util.Map;import java.util.UUID;@Slf4j@RestController@RequestMapping(\"/pay\")public class AliPayController { // ⽀付宝沙箱⽹关地址 private static final String GATEWAY_URL = \"https://openapi-sandbox.dl.alipaydev.com/gateway.do\"; @Autowired private AliPayConfig aliPayConfig; /** * 发起⽀付请求 * @param amount ⽀付⾦额 * @param ⽤户ID */ @GetMapping(\"/create\") public String pay(@RequestParam String amount, @RequestParam String userId) throws AlipayApiException { // 1. 创建⽀付宝客户端 AlipayClient alipayClient = new DefaultAlipayClient( GATEWAY_URL, aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), \"JSON\", \"UTF-8\", aliPayConfig.getAlipayPublicKey(), \"RSA2\" ); // 2. 创建⽀付请求 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); request.setNotifyUrl(aliPayConfig.getNotifyUrl()); // 异步通知地址 request.setReturnUrl(aliPayConfig.getReturnUrl()); // 同步返回地址 // 3. 组装⽀付参数 Map bizContent = new HashMap(); bizContent.put(\"out_trade_no\", UUID.randomUUID().toString().replace(\"-\", \"\")); // 订单号 bizContent.put(\"total_amount\", amount); // ⽀付⾦额 bizContent.put(\"subject\", \"商品购买\"); // 订单标题 bizContent.put(\"product_code\", \"FAST_INSTANT_TRADE_PAY\"); // 产码 bizContent.put(\"passback_params\", userId); // 传递⽤户ID⽤于回调 request.setBizContent(JSON.toJSONString(bizContent)); // 4. 发起⽀付请求 return alipayClient.pageExecute(request).getBody(); } }

3.3支付宝异步通知接口创建

 /** * ⽀付宝异步通知处理 */ @PostMapping(\"/notify\") public String notify(HttpServletRequest request) throws AlipayApiException { // 1. 获取⽀付宝回调参数 Map params = new HashMap(); Map requestParams = request.getParameterMap(); for (String name : requestParams.keySet()) { params.put(name, requestParams.get(name)[0]); } // 2. 验证签名 boolean signVerified = AlipaySignature.rsaCheckV1( params, aliPayConfig.getAlipayPublicKey(), \"UTF-8\", \"RSA2\"); if (signVerified) { // 3. 验证⽀付状态 String tradeStatus = params.get(\"trade_status\"); if (\"TRADE_SUCCESS\".equals(tradeStatus)) { String amount = params.get(\"total_amount\"); // ⽀付⾦额 String userId = params.get(\"passback_params\"); // 获取⽤户ID // 4. 处理业务逻辑(如更新订单状态、⽤户余额等) handlePaymentSuccess(userId, new BigDecimal(amount)); return \"success\"; } } return \"fail\"; } private void handlePaymentSuccess(String userId, BigDecimal amount) { // 处理⽀付成功的业务逻辑 log.info(\"⽤户{}⽀付成功,⾦额:{}\", userId, amount); }

综上,Controller类完整代码:

package com.ruoyi.controller;import com.alibaba.fastjson.JSON;import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import com.alipay.api.internal.util.AlipaySignature;import com.alipay.api.request.AlipayTradePagePayRequest;import com.ruoyi.commom.AliPayConfig;import io.lettuce.core.output.ScanOutput;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;import java.math.BigDecimal;import java.util.HashMap;import java.util.Map;import java.util.UUID;@CrossOrigin@Slf4j@RestController@RequestMapping(\"/pay\")public class AliPayController { // ⽀付宝沙箱⽹关地址 private static final String GATEWAY_URL = \"https://openapi-sandbox.dl.alipaydev.com/gateway.do\"; @Autowired private AliPayConfig aliPayConfig; /** * 发起⽀付请求 * @param amount ⽀付⾦额 * @param ⽤户ID */ @GetMapping(\"/create\") public String pay(@RequestParam String amount, @RequestParam String userId) throws AlipayApiException { System.out.println(\"创建支付宝客户端\"); // 1. 创建⽀付宝客户端 AlipayClient alipayClient = new DefaultAlipayClient( GATEWAY_URL, aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), \"JSON\", \"UTF-8\", aliPayConfig.getAlipayPublicKey(), \"RSA2\" ); // 2. 创建⽀付请求 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); request.setNotifyUrl(aliPayConfig.getNotifyUrl()); // 异步通知地址 request.setReturnUrl(aliPayConfig.getReturnUrl()); // 同步返回地址 // 3. 组装⽀付参数 Map bizContent = new HashMap(); bizContent.put(\"out_trade_no\", UUID.randomUUID().toString().replace(\"-\", \"\")); // 订单号 bizContent.put(\"total_amount\", amount); // ⽀付⾦额 bizContent.put(\"subject\", \"商品购买\"); // 订单标题 bizContent.put(\"product_code\", \"FAST_INSTANT_TRADE_PAY\"); // 产码 bizContent.put(\"passback_params\", userId); // 传递⽤户ID⽤于回调 System.out.println(\"封装的数据:\"+bizContent); request.setBizContent(JSON.toJSONString(bizContent)); // 4. 发起⽀付请求 return alipayClient.pageExecute(request).getBody(); } /** * ⽀付宝异步通知处理 */ @PostMapping(\"/notify\") public String notify(HttpServletRequest request) throws AlipayApiException { // 1. 获取⽀付宝回调参数 Map params = new HashMap(); Map requestParams = request.getParameterMap(); for (String name : requestParams.keySet()) { params.put(name, requestParams.get(name)[0]); } // 2. 验证签名 boolean signVerified = AlipaySignature.rsaCheckV1( params, aliPayConfig.getAlipayPublicKey(), \"UTF-8\", \"RSA2\"); if (signVerified) { // 3. 验证⽀付状态 String tradeStatus = params.get(\"trade_status\"); if (\"TRADE_SUCCESS\".equals(tradeStatus)) { String amount = params.get(\"total_amount\"); // ⽀付⾦额 String userId = params.get(\"passback_params\"); // 获取⽤户ID // 4. 处理业务逻辑(如更新订单状态、⽤户余额等) handlePaymentSuccess(userId, new BigDecimal(amount)); return \"success\"; } } return \"fail\"; } private void handlePaymentSuccess(String userId, BigDecimal amount) { // 处理⽀付成功的业务逻辑 log.info(\"⽤户{}⽀付成功,⾦额:{}\", userId, amount); }}

3.4SecurityConfig.java开放验证权限(框架有的话接口访问权限要放开)

3.5Vue前端设置(结合elementUI):请求支付=>后端响应=>前端判断返回参数,打开新的支付页面

 
{{ item }}元
立即支付
import { createPayment } from \'@/api/alipay/pay\' export default { name: \'Pay\', data() { return { amount: 300, // 支付金额 loading: false, dialogVisible: false, payForm: \'\', // ⽀付宝返回的表单 quickAmounts: [50, 100, 200, 500], // 快速选择金额 userId: \'123\' // 实际项目中国应该从用户状态获取 } }, methods: { // 快速选择金额 selectAmount(amount) { this.amount = amount }, // 发起异步支付 async handlePay() { console.log(\"发起立即支付\"); if (!this.amount) { this.$message.warning(\'请输入充值金额\') return } try { this.loading = true const res = await createPayment({ amount: this.amount, userId: this.userId }) console.log(res.status); //返回请求状态 console.log(\"后端支付返回值:\" + JSON.stringify(res)); console.log(\"amount\"+res.config.params.amount); //返回值amount console.log(\"uuserId\"+res.config.params.userId);// 返回userId //打开支付页面 if(res.status == 200){ window.open(`http://localhost:8080/pay/create?amount=${res.config.params.amount}&userId=${res.config.params.userId}`) this.$message.success(\'付款成功\') this.load(); } } catch (error) { this.$message.error(\'创建支付订单失败\') } finally { this.loading = false } } } }

3.6支付接口测试,地址栏输入

http://localhost:8080/pay/create?amount=500&userId=123

3.7android手机扫码下载支付宝客户端沙箱版

3.8在沙箱账号中找到买家信息的账号、密码、支付密码,打开支付宝APP沙箱版进行登录

支付成功,返回

# 页面跳转地址,支付完成后跳转到此URL 同步通知
returnUrl: https://www.baidu.com/s?ie=UTF-8&wd=%E5%8C%97%E4%BA%AC%E6%97%B6%E9%97%B4

对比下商家和用户余额,付款成功: