上一次做支付宝小程序开发还是三四年前,主要也是做写前后端业务逻辑的内容,但是商户号的创建、小程序、JSAPI的申请都没有做过,而且这些年过去,版本变了,我原来用的代码也行不通了,所以这次我做一回备忘录,记录一下大致的步骤,省的又忘记了,不记录的太详细是因为过几年支付宝可能又会改动
1、注册商家(我注册的是企业,而非个人)
小程序 - 支付宝开放平台
然后按照流程一步一步走下去即可(会涉及到登录密码和支付的设置,需要记录好,以免忘记)
备案后,会收到验证短信通知,短信验证码有效期1天,需要注意验证码和手机号的输入
2、申请成功后,进入工作台,创建小程序 登录 - 支付宝
按照流程一步一步走下去,注册申请有不明白的看这里,官方 小程序文档 - 支付宝文档中心
3、申请好了之后将小程序绑定到企业号中
4、我做的小程序涉及到支付功能,详细流程看 JSAPI 支付 文档 小程序文档 - 支付宝文档中心
需要获取到登录人的openid,之前用的userid已经不在支持了,还有一堆的公钥、私钥
5、配置密钥 小程序文档 - 支付宝文档中心
点击设置
下载密钥生成工具(我之前用的还是1.0.几的版本,老掉牙了)
下载后点击生成密钥,生成好了再上传到平台上
赋值公钥上传
保存私钥
使用密钥的案例 小程序文档 - 支付宝文档中心
不支持userID的文档说明在这里 小程序文档 - 支付宝文档中心
6、获取到openid后,参考这个文档,开通JSAPI支付,发起支付 登录 - 支付宝
选择类目、APPID然后验证,就能提交
7、去支付业务的文档中查看相关的代码接口 小程序文档 - 支付宝文档中心
8、我的代码如下 - 获取小程序的oepnid
maven:
<!-- 支付宝官方SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.39.218.ALL</version>
<!-- <version>4.35.37.ALL</version>-->
</dependency>
前端:
my.getAuthCode({
scopes: 'auth_user',
success: (res) => {
console.log('res.authCode:',res.authCode);
this.getUserId(res.authCode);
},
});
// 获取支付宝ID
getUserId(code){
this.sendRequest({
url: this.api()+'deviceInfo/AliPay/getUserId',
method: 'GET',
data: {code:code}
}).then(response => {
console.log("获取支付宝ID结果:",response)
if(response.code == 200){
const key = 'openid';
const data = response.openid;
my.setStorage({ key, data });
}else{
alert('信息获取失败')
}
}).catch(error => {
alert('信息获取失败')
});
},
后端:
public static Map<String, Object> getUserId(String authCode){
Map<String, Object> map = new HashMap<>();
// 配置支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(
server_url,
appid,
private_key,
"json",
"UTF-8",
alipay_public_key,
sign_type
);
try {
// 1. 换取访问令牌
AlipaySystemOauthTokenRequest tokenRequest = new AlipaySystemOauthTokenRequest();
tokenRequest.setGrantType("authorization_code");
tokenRequest.setCode(authCode);
// 2. 执行请求
AlipaySystemOauthTokenResponse tokenResponse = alipayClient.execute(tokenRequest);
// 3. 直接获取 user_id(auth_user 场景需确认是否返回)
if (tokenResponse.isSuccess()) {
map.put("msg", tokenResponse);
map.put("openid", tokenResponse.getOpenId());
map.put("code", 200);
return map; // 部分情况下直接返回 user_id:ml-citation{ref="3,4" data="citationList"}
}
}catch (Exception e){
e.printStackTrace();
map.put("msg", e.getMessage());
map.put("code", 505);
}
return map;
}
9、发起支付以及查询支付结果
前端:
注意:NO必须为大写,否则无法成功发起
this.sendRequest({
url: this.api()+'deviceInfo/AliPay/tradeCreate',
method: 'GET',
data: feeRecords
}).then(response => {
console.log('支付信息: ', response);
if(response.code == 200){
this.requestPayment(response.tradeNo);
}else{
this.showModal("支付异常"+response.msg);
}
}).catch(error => {
this.setData({
isPaying:false
})
console.error('Request Failed:', error);
});
/**
* 发起支付,并开启循环,查询订单是否成功
* 因为requestPayment中的success只有在点击结束后页面的【完成】按钮,才能被触发
* 所以这里我只能通过查询的方式来实现支付结果的监听
* @param data
*/
requestPayment(tradeNo){
console.log("支付订单号:",tradeNo)
my.tradePay({
tradeNO: tradeNo, // 这里参数绝对要注意,NO要全部大写
success: (res) => {
console.log("res.resultCode:",res.resultCode)
// if (res.resultCode === '9000') {
// // 支付成功逻辑
// }
},
fail: (res) => {
// 支付失败处理
console.log("fail:",res)
this.stopOrderQueryInterval();
my.exitMiniProgram();
this.setData({
isPaying:false
})
}
});
this.startOrderQueryInterval(tradeNo);
},
/**
* 发起支付结果查询
*/
startOrderQueryInterval(data) {
const interval_order = setInterval(() => {
this.queryOrder(data);
}, 3000); // 3秒 = 3000毫秒
this.setData({
intervalOrder: interval_order
});
},
/**
* 停止订单查询定时器
*/
stopOrderQueryInterval() {
if (this.data.intervalOrder) {
console.log("停止订单查询定时器")
clearInterval(this.data.intervalOrder);
this.setData({
cycles:0,
intervalOrder: null
});
}
},
后端:
/**
* 生成支付订单
* @param totalAmount
* @return
*/
public static Map<String,Object> tradeCreate(String totalAmount, String userId) {
// 配置支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(
server_url,
appid,
private_key,
"json",
"UTF-8",
alipay_public_key,
sign_type
);
Map<String,Object> map = new HashMap();
// 构造请求参数以调用接口
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
AlipayTradeCreateModel model = new AlipayTradeCreateModel();
// 设置商户订单号
String outTradeNo = "tradeCreate" + System.currentTimeMillis() + (long) (Math.random() * 10000000L);
System.out.println("商户订单号:"+outTradeNo);
model.setOutTradeNo(outTradeNo);
// 设置订单总金额-单位是元,和微信不一样
model.setTotalAmount(totalAmount);
// 设置订单标题
model.setSubject("IJ");
// 设置产品码
model.setProductCode("JSAPI_PAY");
// 设置小程序支付中
model.setOpAppId(appid);
// 设置订单附加信息
//model.setBody("缴费金额:"+totalAmount+"元");
// 设置买家支付宝用户唯一标识
model.setBuyerOpenId(userId);
request.setBizModel(model);
// 支付结束后,触发的回调方法
//request.setNotifyUrl("https://xxxx/AliPay/notifyUrl");
try {
AlipayTradeCreateResponse response = alipayClient.execute(request);
System.out.println(JSON.toJSONString(response));
if (response.isSuccess()) {
String tradeNo = response.getTradeNo(); // 支付宝交易号:ml-citation{ref="2" data="citationList"}
System.out.println("订单创建成功,交易号:" + tradeNo);
map.put("msg", response);
map.put("tradeNo", tradeNo);
map.put("code", 200);
aliPayQuery(outTradeNo);
} else {
System.err.println("错误码:" + response.getCode() + ",错误信息:" + response.getMsg());
map.put("msg", response.getMsg());
map.put("code", response.getCode());
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
System.out.println(diagnosisUrl);
}
} catch (AlipayApiException e) {
map.put("msg", e.getMessage());
map.put("code", 505);
e.printStackTrace();
}
return map;
}
//订单查询
public static Map<String,Object> aliPayQuery(String outTradeNo){
Map<String,Object> m = new HashMap<>();
try {
// 1. 创建AlipayClient实例
AlipayClient alipayClient = new DefaultAlipayClient(server_url, appid, private_key, "json", "UTF-8", alipay_public_key, sign_type);
// 2. 构建请求对象
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{"
+ "\"out_trade_no\":\"" + outTradeNo + "\","
+ "\"query_options\":[\"trade_settle_info\"]" // 可选查询选项
+ "}");
// 3. 执行API调用
AlipayTradeQueryResponse response = alipayClient.execute(request);
// 4. 处理响应结果
if (response.isSuccess()) {
System.out.println("订单状态查询成功");
System.out.println("支付宝交易号: " + response.getTradeNo());
System.out.println("订单金额: " + response.getTotalAmount());
m.put("msg",response);
m.put("status",response.getTradeStatus());
m.put("code",200);
// 判断支付状态(2025年最新状态码)
switch(response.getTradeStatus()) {
case "TRADE_SUCCESS":
System.out.println("支付已完成");
break;
case "TRADE_FINISHED":
System.out.println("交易完结(不可退款)");
break;
case "WAIT_BUYER_PAY":
System.out.println("等待用户付款");
break;
case "TRADE_CLOSED":
System.out.println("交易已关闭");
break;
default:
System.out.println("未知状态: " + response.getTradeStatus());
}
} else {
System.out.println("查询失败,错误码: " + response.getSubCode());
System.out.println("错误描述: " + response.getSubMsg());
m.put("msg",response.getSubMsg());
m.put("code",response.getSubCode());
}
} catch (Exception e) {
System.err.println("API调用异常: " + e.getMessage());
m.put("msg",e.getMessage());
m.put("code",505);
e.printStackTrace();
}
return m;
}
注意:回调地址,NotifyUrl不是必填的,但是如果有需要,可以参考这个
/**
*
* 查询支付宝小程序订单支付回调函数
* @return
*/
@GetMapping(value = "/AliPay/notifyUrl")
public void notifyUrl(HttpServletRequest request, HttpServletResponse response){
//循环获取到支付宝发送过来的信息
Map<String,String[]>requestParams =request.getParameterMap();
for(String str:requestParams.keySet()){
String name =str;
String[] values = requestParams.get(name);
String valuestr = "";
for (int i=0;i< values.length;i++){
System.out.println("name:"+name+" <====> valuestr:"+valuestr);
}
}
}
如果支付出现莫名其妙的问题可以在社区里直接问人工客服
支付如果出现问题,可以在支付宝提供的诊断工具上进行调试
诊断工具