支付宝开放平台 (alipay.com)
先来看看支付宝沙箱有用的信息
接口加签方式先选择系统默认密钥,启用下面的公钥模式,然后点击查看
我们需要获取和配置图上标注的信息,授权回调地址需要利用内网穿透才能进行配置。为什么要用内网穿透呢?当你完成支付的时候,支付宝会给你一个响应,这个响应就会访问我们的授权回调地址,如果不用内网穿透将本地端口暴露在公网上,支付宝是给不了你回调的!!!
(36条消息) NATAPP使用教程(内网穿透)_Willing卡卡的博客-CSDN博客
授权回调地址是你的公网地址+接口地址,类似于下面这种,PS:每次重新启动natapp都会改变地址,所以你要去代码里修改,支付宝沙箱里修改!
http://aaaaa.natappfree.cc + /p/medical/alipay/notify
继续往下滑,会有APP支付那一栏,点击查看文档
产品介绍 - 支付宝文档中心 (alipay.com)
文档就不一一介绍了,先看看怎么调用支付宝的支付API吧
如下图点击左侧菜单栏里的app支付接口2.0,进入之后往下滑,会看到一个请求示例,这里我贴我自己写好的代码
先看看代码包的目录吧,清晰一点
首先我们先配好我们需要的配置,我全写在AliPay里的,里面的值从上面的application.yml获取
@Repository
public class AliPay {
@Value("${ruoyi.AliPay.APP_ID}")
private static String APP_ID;
@Value("${ruoyi.AliPay.APP_PRIVATEKET}")
private String APP_PRIVATEKET ;
@Value("${ruoyi.AliPay.ALIPAY_PUBLICKEY}")
private String ALIPAY_PUBLICKEY;
@Value("${ruoyi.AliPay.NOTIFY_URL}")
private String NOTIFY_URL; // 测试阶段,内网穿透经常变化!!!
@Value("${ruoyi.AliPay.GATEWAY_URL}")
private String GATEWAY_URL;
@Value("${ruoyi.AliPay.FORMAT}")
private String FORMAT;
@Value("${ruoyi.AliPay.CHARSET}")
private String CHARSET;
//签名方式
@Value("${ruoyi.AliPay.SIGN_TYPE}")
private String SIGN_TYPE;
// 篇幅太长了,没用Lombok这里要去写getter setter!!!我就不贴了
}
Controller不贴了,实现方法全payServiceImpl里面
@Autowired
private AliPay aliPay;
/**
* @description: APP调用支付宝进行支付
* @author: Sunny
* @date: 2023/5/31 14:49
* @param: tBusOrder
* @return: java.lang.String
**/
@Override
public String alipay(TBusOrder tBusOrder) throws AlipayApiException {
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(aliPay.getGATEWAY_URL(), aliPay.getAppId(),
aliPay.getAPP_PRIVATEKET(), aliPay.getFORMAT(), aliPay.getCHARSET(), aliPay.getALIPAY_PUBLICKEY(), aliPay.getSIGN_TYPE());
// 设置商家自身的订单参数,这里的参数名一定要跟app支付接口2.0文档里面的一样!!!每个参数什么意思文档里面都有写!!!
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", tBusOrder.getOrderNo());
bizContent.put("total_amount", BigDecimal.valueOf(tBusOrder.getTotalPrice()).setScale(2).toString());
bizContent.put("subject", "商品"); // 由于一个订单中有多个商品,无法确定商品名字,暂定临时名字“商品”
bizContent.put("product_code", "QUICK_MSECURITY_PAY");
// 2. 创建 Request并设置Request参数
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest (); // 发送请求的 Request类
request.setNotifyUrl(aliPay.getNOTIFY_URL()); // 这里设置我们接收支付宝响应的URL
request.setBizContent(bizContent.toString());
//这里和普通的接口调用不同,使用的是sdkExecute
// 3. 执行请求
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
System.out.println(response.getBody());
//返回生成的字符串
return response.getBody();
}
上面API接口调用后,我们会拿到一个支付宝客户端处理加密过后的字符串,当时自己拿到这个字符串后也是干瞪眼,不知道怎么用,支付宝文档都翻烂了也没找到(可能有但是我自己没找到,欢迎大家指正)。最后无意间脑子一热打开了uniapp的官方文档,链接贴在下面了
开通 | uni-app官网 (dcloud.net.cn)
终于知道那个字符串怎么用了
// 由于测试阶段采用沙箱支付,下面两行代码需要配置!!!!!!!!!!重点!!!
var EnvUtils = plus.android.importClass('com.alipay.sdk.app.EnvUtils');
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
// 业务逻辑
addGoodsOrder(orderData).then(res => {
if (res.code == 200) {
orderData.orderNo = res.orderNo
let orderString = res.orderString //获取后端传过来字符串
let _this = this
//主要看这块
uni.requestPayment({
"provider": "alipay", //这个好像是选择第三方的类型,这里写支付宝的
"orderInfo": orderString, //字符串传进来
success: function(res) {
var rawdata = JSON.parse(res.rawdata);
console.log("支付成功");
// 支付成功则跳转至评价页
_this.gotoReview()
},
fail: function(err) {
console.log('支付失败:' + JSON.stringify(err));
//这里进行取消支付的判断,如果是用户取消订单则跳转至未支付页面,如果是订单问题,根据订单检验规则给用户相应的反馈
//取消支付则跳转至详情页
uni.navigateTo({
url:'/pages/subpages/orderDetail/orderDetail?orderNo='+ orderData.orderNo
})
}
})
}
})
如代码块里写的一样,那个orderInfo就是我们获取的字符串,这里网上说这个字符串在上面的请求中可能会被转义,我没遇到,遇到的可以去搜搜怎么解决转义。
还有个问题,就是uniapp中写了这个可能在浏览器中运行不了,最好是连接手机在手机上模拟支付(这里要提前下好支付宝沙箱app)支付宝开放平台 (alipay.com) 要用你的沙箱账号登录。
最后看看支付宝的响应方法,官方文档有,可以直接扒下来,业务逻辑写在验签通过里面就行了
/**
* @description: APP调用支付宝进行支付异步响应(此处对数据库的订单状态信息进行更新)
* @author: Sunny
* @date: 2023/5/31 14:50
* @param: request
**/
@Override
public void alipayNotify(HttpServletRequest request) throws Exception{
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付宝异步回调========");
Map params = new HashMap<>();
Map requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
String sign = params.get("sign");
String content = AlipaySignature.getSignCheckContentV1(params);
boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPay.getALIPAY_PUBLICKEY(), aliPay.getCHARSET()); // 验证签名
// 支付宝验签
if (checkSignature) {
// 验签通过
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"));
// 查询订单
TBusOrder order = orderMapper.selecOrderByOrderNo(params.get("out_trade_no"));
order.setPayType(3);
// 如果配送方式是快递配送的话将支付状态改为已支付,订单状态改为待发货
if (order.getDistributionMode() == 0) {
order.setPayStatus(1);
order.setOrderStatus(2);
orderMapper.updateTBusOrderBuOrderNo(order);
}
// 如果配送方式是到店自取的话将支付状态改为已支付,订单状态改为待取货
if (order.getDistributionMode() == 1) {
order.setPayStatus(1);
order.setOrderStatus(4);
orderMapper.updateTBusOrderBuOrderNo(order);
}
}
}
}
应该是写完了吧,有什么问题和建议可以留言评论区