1 支付宝开发平台
1.1 百度搜索“支付宝开发平台”
1.2 访问“支付宝开发平台”
1.3 进行注册
1.4 注册完毕之后,支付宝扫描登录
1.4.1 登录之后,选择“控制台”
1.4.2 进入“控制台”之后,下来,找到“沙箱”,点击即可
1.5 沙箱应用,里面会有我们需要的内容
1.5.1 沙箱应用
1.5.2 沙箱账号
2 SpringBoot 整合 沙箱
2.1 创建SpringBoot项目
2.2 添加 支付宝SDK 依赖
<!--支付宝SDK-->
<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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
2.3 application.yml 配置内容
alipay:
#APPID
appId: XXXXXX
#应用私钥
appPrivateKey: XXXXXX
#支付宝公钥
alipayPublicKey: XXXXXX
#回调接口 (使用内网穿透:https://natapp.cn/)
# notifyUrl 内容为:回调地址+controller中自定义的回调请求
notifyUrl: http://bxbunc.natappfree.cc/alipay/notify
server:
port: 8888
2.3.1 appId、appPrivateKey、alipayPublicKey 都是从 “支付宝开放平台”=》控制台,查找的
2.3.2 notifyUrl 回调接口设置
2.3.2.1 当前项目的地址为本地地址,无法实现支付宝沙箱的调用,因此使用内网穿透(如:https://natapp.cn)将当前项目的本地地址转为网络的地址,这样支付宝沙箱就能对本地项目进行回调
备注:内网穿透具体使用,查看“4 补充:Natapp 使用”
2.4 自定义配置类(与yml文件结合)
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class MyAliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
@PostConstruct
public void init() {
// 设置参数(全局只需设置一次)
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipaydev.com";
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.appPrivateKey;
config.alipayPublicKey = this.alipayPublicKey;
config.notifyUrl = this.notifyUrl;
Factory.setOptions(config);
System.out.println("=======支付宝SDK初始化成功=======");
}
}
2.5 支付类
package com.laoma.springbootalypay.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.easysdk.factory.Factory;
import com.laoma.springbootalypay.config.MyAliPayConfig;
import com.laoma.springbootalypay.pojo.AliPay;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/alipay")
public class AliPayController {
//-支付宝网关地址
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;
@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);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(myAliPayConfig.getNotifyUrl());
//-商品的内容可以从系统中传递过来,目前这里是手写的
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);// 直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
@PostMapping("/notify") // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
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));
// System.out.println(name + " = " + request.getParameter(name));
}
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
// (不需要)支付宝验签
//if (Factory.Payment.Common().verifyNotify(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"));
// 更新订单未已支付
// ordersMapper.updateState(tradeNo, "已支付", gmtPayment, alipayTradeNo);
//}
}
return "success";
}
}
3 项目测试
注意:一定先启动 natapp,在启动 Springboot项目,因为启动natapp之后,才能获取到natapp生成的网络地址,然后将地址复制到项目的yml文件中
3.1 启动 Natapp
3.1.1 命令启动
在natapp的跟目录下执行:natapp -authtoken=xxxx
将生成的Forwarding后面的地址,复制到 springboot项目的yml文件中
3.2 启动springboot项目
3.3 访问 http://localhost:8888/alipay/pay 即可,效果如下:
输入沙箱提供的买家账号与密码,在输入支付密码
支付成功之后的效果
通过回调函数的调用,在控制台输出的支付信息,如下
4 补充:Natapp 使用
4.1 访问 Natapp 官网
4.2 注册/登录 并 下载客户端
4.3 登录之后首页面
4.4 选择购买隧道=》免费隧道
可以创建自己的免费隧道
4.5 我的隧道进行配置,配置结束即可
配置本地项目的路径
4.6 下载的客户端配置(window版)
进入 natapp根目录执行:natapp -authtoken=xxxx
注意:authtoken 是 natapp中生成的,如 4.5 中显示的 authtoken中的内容
红色框标注的内容为springboot项目中yml设置的notifyUrl中回调地址。