微信小程序开发微信支付

微信小程序使用微信支付JSAPI开发支付功能

官方文档:小程序支付

准备

流程

  1. 前端向后端发送支付请求


  2. 后端首先生成本地订单记录,然后向微信服务器发送下单请求并携带小程序ID、商户号、本地订单号、商品描述、金额、回调地址、用户openId等信息

    String appId; // 微信小程序appId
    String mchId; // 商户ID
    String payerOpenId; // 支付者的openId
    
    PrepayRequest request = new PrepayRequest(); // 支付请求
    Amount amount = new Amount(); // 金额
    Payer payer = new Payer(); // 用户
    
    amount.setTotal( (int)(dto.getPayMoney() * 100) ); // 单位:分
    payer.setOpenid(payerOpenId); // 付款者的openId
    request.setAmount(amount);
    request.setPayer(payer);
    request.setAppid(appId);
    request.setMchid(mchId);
    request.setOutTradeNo(ownOrderNum); // 平台订单号
    request.setDescription("商品描述");
    request.setNotifyUrl("https://example.com/callBack"); // 用户支付成功后,微信官方会调用这个地址
    

  3. 微信官方正确响应后,会返回预支付ID prepay_id,后端将prepay_id进行签名再返回给前端

    // prepayWithRequestPayment() 会对预支付ID签名并返回 PrepayWithRequestPaymentResponse
    PrepayWithRequestPaymentResponse response = wechatService.prepayWithRequestPayment(request);
    return response; // 返回给前端
    

  4. 前端页面根据签名数据调用wx.requestPayment向微信服务器发送支付请求,微信官方给予正确响应后,前端页面会弹出支付界面

    响应结果包含以下数据:

    参数名 解释 描述
    timeStamp 时间戳
    nonceStr 随机字符串 最多32个字符
    package 扩展字符串 格式: “prepay_id=wx201410272009395522657a690389285100”
    signType 签名方式 RSA
    paySign 签名
    // response.data 为响应结果
    wx.requestPayment({
        timeStamp: response.data.timeStamp,
        nonceStr: response.data.nonceStr,
        package: response.data.packageVal,
        signType: response.data.signType,
        paySign: response.data.paySign,
        success: (result) => {},
        fail: () => { console.log("支付失败...") }
    });
    

  5. 用户支付完成后,微信会根据回调地址调用平台的POST[https]接口向平台返回支付结果

    接收到微信发送的支付结果后,应该给微信返回状态码,否则微信会认为回调未成功,进而重复请求。考虑微信有重复调用的可能,该接口应当对同一条订单的信息做加锁处理,保证幂等性。

    @PostMapping("callBackPayComplete")
    public void callBackPayComplete(HttpServletRequest request, HttpServletResponse response, @RequestBody String param) {
        String signature = request.getHeader("Wechatpay-Signature");
        String signatureType = request.getHeader("Wechatpay-Signature-Type");
        String serialNumber = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        boolean bool = consultService.handlePayResult(signature, signatureType, serialNumber, nonce, timestamp, param);
        response.setStatus(bool ? 200 : 500);
    }
    

    注意:使用 org.springframework.web.bind.annotation 的 @Header 或 @Headers 注解获取请求头时,请求头的 key 会变成小写。这里使用HttpServletRequest.getHeader()获取