目录
特别注意:每次切换时秘钥都是会变得,如果从自定义切换为默认,记得重新改配置
4.创件配置类(使用@Value注解将配置文件中的属性值映射到对应的属性中)
一、什么是支付宝沙箱
支付宝沙箱是一个模拟环境,专门为开发者提供,用于在不影响真实交易的情况下进行支付宝相关功能的测试和调试。 支付宝沙箱(AlipaySandbox)允许开发者在隔离的测试环境中模拟真实的支付流程和接口,从而验证其支付功能是否正常工作。这种环境不会对真实数据产生影响,因为它完全隔离于真实支付宝环境。支付宝沙箱为开发者提供了一套模拟的支付流程和接口,包括扫码支付、APP支付、H5支付等场景,以及相关的调试工具和接口文档,帮助开发者更方便地进行测试和开发。使用支付宝沙箱环境,开发者可以在开发和测试阶段及时发现和解决问题,确保支付功能的稳定和安全。一旦在沙箱环境中完成了测试和调试,开发者就可以将代码和配置切换到真实的支付宝环境中进行生产部署12。
沙箱环境的创建和使用过程包括注册入驻支付宝开放平台、配置沙箱环境、以及在SpringBoot等开发环境中实现支付宝支付功能。这个过程涉及到了解沙箱环境的特性、如何利用沙箱进行支付功能的开发和测试,以及最终如何将经过测试的代码部署到真实环境中4。
总的来说,支付宝沙箱是一个重要的工具,它为开发者提供了一个安全、有效的途径来测试支付宝支付功能,从而加速了应用的开发和测试过程,减少了因使用真实资金进行测试而带来的风险12。
二、支付环境申请
A、配置沙箱应用环境
1、进入沙箱
(1)进入支付宝开放平台
进入之后显示
(2)进行登录
没有支付宝账户的话需要先注册
手机支付宝扫码登录
手机号密码登录
(3)进入控制台
(4)进入沙箱
(5)进入之后可以查看APPID和支付宝网关地址和密钥
(6)查询账号信息
2、秘钥的申请
可以直接使用默认的秘钥
注:秘钥挺长的
可以使用自定义秘钥(需要下载秘钥工具生成)
(1)下载秘钥工具
下载秘钥工具地址:小程序文档 - 支付宝文档中心支付宝文档中心https://opendocs.alipay.com/common/02kipk?pathHash=0d20b438
下载完成后是这个
(2)安装秘钥工具
a.双击打开选择用户
b.选择安装位置
c.点击安装完成
安装成功运行
(3)生成秘钥
a.选择加签方式为秘钥,加密算法为RSA2
b.生成后会出现公钥和私钥
c.点击打开文件位置,就是秘钥保存位置
(4)自定义秘钥配置
a.选择自定义秘钥
b.将生成的公钥复制进去,点击保存
c.点击确定
出现已启用就完成了
B、设置内网穿透环境
1、为什么使用内网穿透
支付宝沙箱需要设置内网穿透,主要是因为支付宝沙箱在完成支付后需要进行异步回调,修改数据中的内容。支付宝的程序需要向开发者自己的接口发送请求,而这个请求需要通过内网穿透技术实现,确保外部网络能够访问到内部的服务器,从而完成支付结果的通知和数据的更新。简单来说,内网穿透技术允许外部网络访问到内部网络的服务,这对于实现支付宝沙箱的异步回调功能是必要的1。
内网穿透技术的基本原理是通过特定的技术手段,使得内部网络的服务可以被外部网络访问。这在开发环境中尤其重要,因为它允许开发者在测试阶段模拟真实的支付场景,通过外部请求触发内部的支付结果回调,从而验证系统的正确性和稳定性。通过配置内网穿透,开发者可以确保支付宝沙箱能够正确地与其后端服务进行通信,进而完成支付流程的模拟和测试2。
此外,内网穿透的使用还涉及到一些技术上的配置,如安装特定的软件、设置映射等,以确保外部网络能够正确地访问到内部的服务器。这个过程虽然增加了技术实施的复杂性,但对于确保支付宝沙箱功能的正确实现和测试是不可或缺的2。
2、使用NATAPP
(1)进入官网
(2)注册和登录
a.登录
b.注册
获取验证码
因为我已注册过,无法在注册了,后面过程就不展示了,直接验证就行了
(3)购买免费渠道
注:购买前需要实名认证,我已实名就不展示了,点击购买会弹出实名认证界面,跟着一步步进行就行
a.点击免费渠道,进入以下页面
b.更改端口
注:填错端口也不要怕,购买之后还可以改
c.点击免费购买
注:一个账户只可以购买两个免费渠道
(4)购买后更改端口
a.找到自己购买的隧道
b.点击配置
c.更改端口
别忘了点击修改
3、下载客户端
(1)点击之后选择版本
(2)解压缩
(3)运行
a.黑窗口运行
输入命令
natapp.exe -authtoken=你的authtoken
authtoken所在
出现以下就算启动成功
b.bat文件启动
每次启动都要打开cmd并输入命令是不是很麻烦,传建一个bat文件直接双击就行
i.创建一个txt文件
ii.将命令输入到文件中
iii.保存退出,并将文件格式改为bat
iiii.改完之后就可直接双击运行了
三、实际SpringBoot后端代码
1.在项目xml文件中加入依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.2.0</version>
</dependency>
注:依赖说明
alipay-sdk-java
作用:这是支付宝的核心SDK,允许你调用支付宝的API来进行支付处理。
版本:4.22.110.ALL 是这个SDK的版本号。
alipay-easysdk
作用:这是一个更简化的接口,便于开发者使用支付宝的API,降低了集成的复杂度。
版本:2.2.0 是这个易用SDK的版本号。
2.加入配置
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:
注释说明
appId: 唯一标识你的应用,在支付宝平台注册时获得。
appPrivateKey: 你的应用生成的私钥,用于对请求进行签名,保证数据的安全性。
alipayPublicKey: 支付宝提供的公钥,用于验证支付宝返回的数据是否真实有效。
notifyUrl: 当交易状态发生变化时(如支付成功),支付宝会向这个地址发送通知,通常需要一个可以公网访问的地址。
returnUrl: 用户支付完成后,支付宝会将用户重定向到这个地址,通常用于展示支付结果。
signType: 签名算法类型,RSA2 是一种安全的签名方式。
charset: 请求和响应的字符编码,通常使用 utf-8。
gatewayUrl: 支付宝的API网关地址,用于发送支付请求。
注意点
(1)当使用的是默认密钥时
点击查看
应用私钥为:
应用公钥为:
特别注意:每次切换时秘钥都是会变得,如果从自定义切换为默认,记得重新改配置
(2)当使用的是自定义秘钥时
点击查看
应用公钥为:
a.直接点击配置赋值
b.找到生成文件,进入文件复制
应用私钥为:
因为自定义秘钥设置时只,配置了公钥,所以只能找到对应文件复制,所以生成之后的文件秘钥要保存好
特别注意:
1.自定义秘钥使用时,公钥和私钥必须是配套的
可以使用生成秘钥工具检查秘钥是否配套
2.每次自定义秘钥都是需要从新输入的
比如:当你从自定义秘钥改为默认秘钥之后,又想使用自定义秘钥这时就需要从新输入
3.订单实体类
/**
* 订单表
*/
@TableName(value ="order")
@Data
public class Order implements Serializable {
/**
* 订单Id
*/
@TableId(type = IdType.ASSIGN_UUID)
private Long id;
/**
* 用户Id
*/
private Long userId;
/**
* 接口Id
*/
private Long interfaceInfoId;
/**
* 支付金额
*/
private Double money;
/**
* 支付方式
*/
private String paymentMethod;
/**
* 0 - 未支付 1 - 已支付
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 是否删除
*/
private Integer isDelete;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
4.创件配置类(使用@Value注解将配置文件中的属性值映射到对应的属性中)
/**
* 支付宝配置类
*/
@Data
@Component
public class AlipayTemplate {
/**
* APPID
*/
@Value("${alipay.appId}")
private String appId;
/**
* 应用私钥,就是工具生成的应用私钥
*/
@Value("${alipay.appPrivateKey}")
public String merchantPrivateKey;
/**
* 支付宝公钥,对应APPID下的支付宝公钥
*/
@Value("${alipay.alipayPublicKey}")
public String alipayPublicKey;
/**
* 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
*/
@Value("${alipay.notifyUrl}")
public String notifyUrl;
/**
* 同步通知,支付成功,一般跳转到成功页
*/
@Value("${alipay.returnUrl}")
public String returnUrl;
/**
* 签名方式
*/
@Value("${alipay.signType}")
private String signType;
/**
* 字符编码格式
*/
@Value("${alipay.charset}")
private String charset;
/**
* 订单超时时间
*/
private String timeout = "1m";
/**
* 支付宝网关;https://openapi-sandbox.dl.alipaydev.com/gateway.do
*/
@Value("${alipay.gatewayUrl}")
public String gatewayUrl;
public String pay(Order order) throws AlipayApiException {
System.out.println("APPID:" + appId);
System.out.println("应用私钥:" + merchantPrivateKey);
System.out.println("支付宝公钥:" + alipayPublicKey);
System.out.println("支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息:" + notifyUrl);
System.out.println("同步通知,支付成功,一般跳转到成功页:" + returnUrl);
System.out.println("签名方式:" + signType);
System.out.println("字符编码格式:" + charset);
System.out.println("订单超时时间:" + timeout);
System.out.println("支付宝网关:" + gatewayUrl);
// 1. 根据支付宝的配置生成一个支付客户端
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl, // 支付宝网关地址
appId, // 应用ID
merchantPrivateKey, // 商户私钥
"json", // 请求数据格式
charset, // 字符编码格式
alipayPublicKey, // 支付宝公钥
signType // 签名方式
);
//2、创建一个支付请求,并设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(returnUrl);// 设置支付成功后的返回地址
alipayRequest.setNotifyUrl(notifyUrl);// 设置支付结果通知地址
Long id = order.getId(); // 获取订单ID
Long interfaceInfoId = order.getInterfaceInfoId(); // 获取接口信息ID
Double money = order.getMoney(); // 获取支付金额
String paymentMethod = order.getPaymentMethod(); // 获取支付方式
// 设置业务内容,包含必要的支付参数
alipayRequest.setBizContent(
"{" +
"\"out_trade_no\":\"" + id + "\"," +
"\"total_amount\":\"" + money + "\"," +
"\"subject\":\"" + interfaceInfoId + "\"," +
"\"body\":\"" + paymentMethod + "\"," +
"\"timeout_express\":\"" + timeout + "\"," +
"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"" +
"}"
);
// 执行支付请求并获取支付宝的响应
String result = alipayClient.pageExecute(alipayRequest).getBody();
//会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面
System.out.println("支付宝的响应:" + result);
//返回支付宝响应的结果
return result;
}
}
5.创建调用接口
/**
* 支付宝接口
*/
@RestController
@RequestMapping("/alipay")
public class AliPayController {
@Resource
AlipayTemplate alipayTemplate;
@GetMapping(value = "/pay", produces = "text/html")
@ResponseBody
public String pay(@RequestParam long id) throws AlipayApiException {
// 创建订单对象并设置属性
Order order = createOrder(id);
// 调用支付宝支付模板进行支付
return alipayTemplate.pay(order);
}
/**
* 创建订单的方法
* 因为是测试并没有创建数据库表,所以直接new了一个对象出来
* @param id
* @return
*/
private Order createOrder(long id) {
Order order = new Order();
order.setId(id); // 使用传入的id
order.setUserId(1111111L); // 假设用户ID固定,这里可以根据实际情况调整
order.setInterfaceInfoId(294389472934L); // 接口信息ID
order.setMoney(1000.0); // 订单金额
order.setPaymentMethod("支付宝"); // 支付方式
return order;
}
@PostMapping("/notify") // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
// 检查交易状态是否为成功
if (!"TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
return "failure"; // 如果状态不是成功,则返回失败
}
System.out.println("=========支付宝异步回调========");
// 创建一个存储请求参数的Map
Map<String, String> params = getRequestParams(request);
// 提取支付信息
String tradeNo = params.get("out_trade_no"); // 商户订单号
String gmtPayment = params.get("gmt_payment"); // 付款时间
String alipayTradeNo = params.get("trade_no"); // 支付宝交易号
// 验证支付宝返回的签名
if (verifySignature(params)) {
logTransactionDetails(params); // 记录交易详情
// 更新订单状态的逻辑可以在这里添加
}
return "success"; // 返回成功响应给支付宝
}
/**
* 提取请求参数的方法
* @param request
* @return
*/
private Map<String, String> getRequestParams(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
return params;
}
/**
* 验证签名的方法
* @param params
* @return
* @throws Exception
*/
private boolean verifySignature(Map<String, String> params) throws Exception {
return Factory.Payment.Common().verifyNotify(params);
}
/**
* 记录交易详情的方法
* @param params
*/
private void logTransactionDetails(Map<String, String> params) {
System.out.println("交易名称: " + params.get("subject"));
System.out.println("交易状态: " + params.get("trade_status"));
System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
System.out.println("商户订单号: " + 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"));
}
}
四、测试
1.项目启动无报错,浏览器访问地址(id传参)
http://localhost:9004/alipay/pay?id=123456
注:支付后id需要改变,不然会提示该订单已支付
出现这个就成功了
2.填写账户名,支付密码(别输成商家信息了)
3.输入之后还会让输入一遍支付密码
4.出现这个就支付成功了
5.等待一会,会出现以下页面,等待跳转就可以了
因为是测试所以没有创建别的接口,直接使用百度搜北京时间的地址了,所以直接跳以下页面
到这就结束了