学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付

数据配置

支付宝开放平台 (alipay.com)

先来看看支付宝沙箱有用的信息

学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付_第1张图片

接口加签方式先选择系统默认密钥,启用下面的公钥模式,然后点击查看

学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付_第2张图片

我们需要获取和配置图上标注的信息,授权回调地址需要利用内网穿透才能进行配置。为什么要用内网穿透呢?当你完成支付的时候,支付宝会给你一个响应,这个响应就会访问我们的授权回调地址,如果不用内网穿透将本地端口暴露在公网上,支付宝是给不了你回调的!!!

(36条消息) NATAPP使用教程(内网穿透)_Willing卡卡的博客-CSDN博客

授权回调地址是你的公网地址+接口地址,类似于下面这种,PS:每次重新启动natapp都会改变地址,所以你要去代码里修改,支付宝沙箱里修改!

http://aaaaa.natappfree.cc   +    /p/medical/alipay/notify

继续往下滑,会有APP支付那一栏,点击查看文档

产品介绍 - 支付宝文档中心 (alipay.com)

文档就不一一介绍了,先看看怎么调用支付宝的支付API吧

如下图点击左侧菜单栏里的app支付接口2.0,进入之后往下滑,会看到一个请求示例,这里我贴我自己写好的代码

学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付_第3张图片

先看看代码包的目录吧,清晰一点

学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付_第4张图片学习记录:关于Uniapp与Java实现支付宝沙箱APP内支付_第5张图片

首先我们先配好我们需要的配置,我全写在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);
            }
        }
    }
}

应该是写完了吧,有什么问题和建议可以留言评论区

你可能感兴趣的:(java,spring,boot,uni-app)