目录
2.等待下载安装完成之后,打开支付宝开放平台开发助手生成密钥
1.访问Natapp官网:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 登录或注册
12.进入命令窗口输入以下命令 注意:authtoken 是 natapp中生成的
13.获取内网穿透地址 (注: 免费隧道每次生成的内网穿透地址都会有所改变,注意查看)
1.启动项目,访问 http://localhost:8080/alipay/pay 进入支付页面
一.什么是沙箱支付
支付宝沙箱支付(Alipay Sandbox Payment)是支付宝提供的一个模拟支付环境,用于开发和测试支付宝支付功能的开发者工具。在真实的支付宝环境中进行支付开发和测试可能涉及真实资金和真实用户账户,而沙箱环境则提供了一个安全、隔离的环境,使开发者能够模拟支付过程,测试支付功能,而不会使用真实资金。
使用支付宝沙箱支付环境,开发者可以模拟各种支付场景,包括交易创建、支付请求、支付回调等,以验证支付功能的正确性和稳定性。沙箱环境中的所有交易和数据都是虚拟的,不会产生真实的交易或资金流动。
支付宝沙箱支付提供了开发者工具和接口,使开发者能够在模拟环境下进行支付流程的调试和测试。开发者可以在沙箱环境中创建测试账户、配置模拟的交易金额和状态,使用沙箱环境中的接口进行支付操作,并模拟支付回调接口接收支付结果。
通过使用支付宝沙箱支付,开发者可以更安全、更有效地进行支付功能的开发和测试,避免了对真实环境的影响和风险。一旦支付功能在沙箱环境中验证通过,开发者可以将其部署到真实的支付宝生产环境中,与真实用户进行交互和支付。
二.为什么要使用沙箱支付
使用沙箱环境(Sandbox)进行支付测试是开发过程中非常重要的一步,主要有以下几个原因:
1. 安全性和隔离性
- 避免真实交易:在沙箱环境中,所有的交易都是模拟的,不会涉及真实的资金流动,从而避免了在开发和测试阶段发生的真实交易风险。
- 隔离开发环境:沙箱环境与生产环境完全隔离,开发人员可以在不影响真实用户的情况下进行各种测试和调试。
2. 成本效益
- 节省费用:使用沙箱环境进行测试不需要实际支付任何费用,可以大大降低开发和测试的成本。
- 快速迭代:沙箱环境允许开发人员快速进行多次测试和调整,而无需担心每次测试的费用问题。
3. 灵活性和可控性
- 模拟多种场景:沙箱环境可以模拟各种支付场景,包括成功支付、失败支付、退款等,帮助开发人员全面测试系统的各种情况。
- 自定义测试数据:开发人员可以自定义测试数据,包括用户信息、订单信息等,以便更精确地测试特定的业务逻辑。
4. 便于调试和问题定位
- 详细的日志和错误信息:沙箱环境通常提供详细的日志和错误信息,帮助开发人员快速定位和解决问题。
- 实时反馈:沙箱环境可以提供实时的反馈,帮助开发人员及时发现和修复问题。
5. 合规性和法律要求
- 遵守法规:在某些国家和地区,法律法规要求在正式上线前必须进行充分的测试,以确保系统的安全性和可靠性。
- 保护用户隐私:沙箱环境使用虚拟的数据,避免了使用真实用户的敏感信息,从而保护了用户隐私。
6. 提高开发效率
- 减少部署时间:通过在沙箱环境中进行充分的测试,可以减少正式环境中的问题,加快部署速度。
- 团队协作:多个开发人员可以同时在沙箱环境中进行测试,提高团队的协作效率。
示例:支付宝沙箱环境
支付宝提供了一个沙箱环境,开发人员可以在这个环境中测试支付宝的各种支付功能,包括但不限于:
- 支付接口:测试支付请求的生成和处理。
- 退款接口:测试退款请求的生成和处理。
- 查询接口:测试交易状态的查询。
- 回调接口:测试异步通知和同步返回的功能。
通过使用沙箱环境,开发人员可以确保系统在正式上线前已经经过了充分的测试和验证,从而提高系统的稳定性和可靠性。
三.配置沙箱
1.登录支付宝开放平台,点击登录/注册按钮
2.使用支付宝扫码登录
3.登录成功点击控制台
4.划到最底下找到沙箱
5.打开沙箱应用,记录以下信息
6.打开沙箱账号,记录信息
四.生成密钥
1.打开支付宝文档中心,下载安装支付宝开放平台开发助手
2.等待下载安装完成之后,打开支付宝开放平台开发助手生成密钥
3.生成的密钥会自动保存,也可以打开文件位置进行查看
4.找到刚才的沙箱应用,配置密钥(建议选择自定义密钥)
5.配置密钥: 复制完成之后点击保存
6.保存成功之后信息如下 点击确定
五.配置内网穿透
1.访问Natapp官网:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 登录或注册
2.以下是登录后的首页页面
3.选择购买隧道=>免费隧道
4.购买自己的隧道
5.购买完之后选择我的隧道=>配置
6.配置自己项目的IP + 端口
7.配置完成点击修改即可
8.修改成功之后下载NATAPP客户端
9.进入下载页面,选择自己需要的类型版本即可
10.下载完解压即可(注: 建议不要有中文或空格的路径)
11.在该目录输入cmd进入命令窗口
12.进入命令窗口输入以下命令 注意:authtoken 是 natapp中生成的
natapp -authtoken=xxxx
13.获取内网穿透地址 (注: 免费隧道每次生成的内网穿透地址都会有所改变,注意查看)
六.代码实现
1.检查项目是否拥有以下依赖,没有则添加
(spring-boot-starter-web的版本需要根据自己的spring版本添加或省略)
<!-- Spring Boot Web Starter,它包含了构建Web应用所需的所有依赖,包括Tomcat服务器和Spring MVC框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok库,用于简化Java代码,减少样板代码的编写,如getter、setter、toString等方法。设置为可选(optional=true),表示该项目直接依赖不会传递此依赖给其他项目 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.添加依赖 (根据自己需求选择对应版本)
<!-- 支付宝SDK核心包,用于接入支付宝的各种服务,如支付、退款等。请根据实际需求选择最新版本 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.20.0.ALL</version> <!-- 版本号应根据官方提供的最新版本进行更新 -->
</dependency>
<!-- 支付宝易扩展SDK,提供了更简洁的API接口,简化了开发流程 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.2.3</version>
</dependency>
<!-- Alibaba FastJSON库,一个Java语言编写的高性能功能完备的JSON库,常用于JSON数据的解析和生成 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83_noneautotype</version> <!-- 注意此版本可能包含特定的安全或功能改动,请查阅文档确认 -->
</dependency>
3.添加配置信息,以下是两种格式的配置
(注: 内网穿透服务地址每次都会改变,注意保持一致,访问路径对应表现层路径即可)
yml:
alipay:
# APPID:在支付宝开放平台注册的应用ID
appId: XXXXXX
# 应用私钥:在支付宝开放平台生成的应用私钥
appPrivateKey: XXXXXX
# 支付宝公钥:在支付宝开放平台获取的支付宝公钥
alipayPublicKey: XXXXXX
# 异步通知接口:支付宝调用该URL通知交易状态变化(如支付成功)
# 使用内网穿透服务(如 https://natapp.cn/)以确保可以从外部网络访问
notifyUrl: http://esjdvh.natappfree.cc/alipay/notify
# 同步返回接口:用户完成支付后,支付宝会重定向到该URL
returnUrl: http://esjdvh.natappfree.cc/alipay/return
server:
# 服务端口:应用程序运行的端口号
port: 8080
properties:
# 支付宝配置
# APPID:在支付宝开放平台注册的应用ID
alipay.appId=XXXXXX
# 应用私钥:在支付宝开放平台生成的应用私钥
alipay.appPrivateKey=XXXXXX
# 支付宝公钥:在支付宝开放平台获取的支付宝公钥
alipay.alipayPublicKey=XXXXXX
# 异步通知接口:支付宝调用该URL通知交易状态变化(如支付成功)
# 使用内网穿透服务(如 https://natapp.cn/)以确保可以从外部网络访问
alipay.notifyUrl=http://esjdvh.natappfree.cc/alipay/notify
# 同步返回接口:用户完成支付后,支付宝会重定向到该URL
alipay.returnUrl=http://esjdvh.natappfree.cc/alipay/return
# 服务器配置
# 服务端口:应用程序运行的端口号
server.port=8080
配置信息对应位置信息
APPID:
应用公钥/私钥位置:打开支付宝开放平台密钥工具
生成的密钥和私钥对应属性
4.编写配置类
/**
* 配置支付宝相关的信息,使用Spring Boot的@ConfigurationProperties自动绑定配置文件中的属性。
* 此配置类用于加载支付宝支付所需的配置信息,并在应用启动时初始化支付宝SDK。
*/
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class MyAliPayConfig {
/**
* 应用ID,开发者在支付宝开放平台创建应用后获得。
*/
private String appId;
/**
* 应用私钥,开发者生成并保存在服务器端,用于对请求签名。
*/
private String appPrivateKey;
/**
* 支付宝公钥,用于验证支付宝返回的数据签名。
*/
private String alipayPublicKey;
/**
* 异步通知地址,当交易状态发生变化时,支付宝会向该地址发送通知。
*/
private String notifyUrl;
/**
* 同步返回地址,用户在支付宝支付完成后会跳转到该地址。
*/
private String returnUrl;
/**
* 初始化支付宝SDK配置的方法。
* 该方法使用了@PostConstruct注解,确保它在依赖注入完成后执行。
* 它将配置信息设置到AlipayConfig对象中,并调用Factory.setOptions方法来设置全局选项。
*/
@PostConstruct
public void init() {
// 创建配置对象
Config config = new Config();
// 设置协议类型,默认为https
config.protocol = "https";
// 设置网关主机地址,这里使用的是沙箱环境的地址
config.gatewayHost = "openapi.alipaydev.com";
// 设置签名类型,使用RSA2
config.signType = "RSA2";
// 设置应用ID,从配置文件中读取
config.appId = this.appId;
// 设置应用私钥,从配置文件中读取
config.merchantPrivateKey = this.appPrivateKey;
// 设置支付宝公钥,从配置文件中读取
config.alipayPublicKey = this.alipayPublicKey;
// 设置异步通知地址,从配置文件中读取
config.notifyUrl = this.notifyUrl;
// 将配置对象设置到Factory中,以便在整个应用中使用
Factory.setOptions(config);
// 输出初始化成功的消息
System.out.println("=======支付宝SDK初始化成功=======");
}
}
5.表现层(Controller)
@Controller
@RequestMapping("/alipay")
public class AliPayController {
// 支付宝开放平台API的网关地址
private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
// 数据格式
private static final String FORMAT_JSON = "JSON";
// 字符集编码
private static final String CHARSET_UTF8 = "UTF-8";
// 签名方式
private static final String SIGN_TYPE_RSA2 = "RSA2";
// 自定义配置类,用于读取支付宝相关配置信息
@Autowired
private MyAliPayConfig myAliPayConfig;
/**
* 发起支付请求的接口
*
* @param aliPay 包含支付信息的对象
* @param httpResponse HTTP响应对象,用于返回支付表单
* @throws Exception 可能抛出的异常
*/
@GetMapping("/pay")
public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {
// 创建默认的支付宝客户端实例
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, myAliPayConfig.getAppId(),
myAliPayConfig.getAppPrivateKey(), FORMAT_JSON, CHARSET_UTF8, myAliPayConfig.getAlipayPublicKey(), SIGN_TYPE_RSA2);
// 创建API对应的request
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 设置异步通知地址
request.setNotifyUrl(myAliPayConfig.getNotifyUrl());
request.setReturnUrl(myAliPayConfig.getReturnUrl());
// 设置请求参数
// 这里可以动态设置,例如从数据库或前端传入
aliPay.setTraceNo(UUID.randomUUID().toString().replaceAll("-", ""));
aliPay.setTotalAmount("100");
aliPay.setSubject("笔记本华硕");
// 构造业务请求参数
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);
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
/**
* 处理支付宝异步通知的接口
*
* @param request HTTP请求对象,包含支付宝返回的通知信息
* @return 返回给支付宝的确认信息
*/
@PostMapping("/notify")
@ResponseBody
public String payNotify(HttpServletRequest request) {
// 检查交易状态是否为成功
if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
System.out.println("=========支付宝异步回调========");
// 存储所有请求参数
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
// 获取交易信息
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
// 打印交易信息
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"));
// 在这里可以更新数据库中的订单状态等信息
// 示例:ordersMapper.updateState(tradeNo, "已支付", gmtPayment, alipayTradeNo);
}
// 告诉支付宝,异步通知已经收到
return "success";
}
@GetMapping("return")
public void returnPay(HttpServletResponse response) throws Exception {
// 设置响应的字符编码为UTF-8,防止中文乱码
response.setCharacterEncoding("UTF-8");
// 设置响应的内容类型为HTML,并指定字符编码为UTF-8
response.setContentType("text/html; charset=UTF-8");
// 重定向到指定的HTML页面(index.html)
response.sendRedirect("/index.html");
}
}
6.实体类
/**
* 支付宝支付实体类
*/
@Data
public class AliPay {
/**
* 追踪号:用于唯一标识一次支付请求,可以是订单号或其他业务相关的唯一标识
*/
private String traceNo;
/**
* 总金额:支付的总金额,单位为元
*/
private String totalAmount;
/**
* 订单标题:支付时显示的订单名称或描述
*/
private String subject;
}
7.创建支付成功跳转页面
添加配置
yml:
spring:
resources:
static-locations: classpath:/static/
properties:
# Spring资源配置
# 静态资源的位置,用于指定静态文件(如HTML、CSS、JavaScript等)的存放路径
spring.resources.static-locations=classpath:/static/