SpringBoot實現微信小程序支付

本文給你們講解微信小程序支付全流程,以及相關功能源代碼,項目不開放,帶來不便盡請諒解。小程序支付主要
包含以下幾步驟,1.預下單-調用微信統一下單接口進行預下單。2.小程序拿到支付參數喚醒支付。3.支付成功後發起退
款申請。

        本文使用okHttpUtil進行接口交互 使用goole的gson與阿里的fastJson進行解析JsonObect,使用封裝的http工具類進行攜
帶證書進行接口交互、使用封裝的工具類實現map轉xml等。

php

下面是正文:前端

微信支付文檔:  https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1


一.獲取微信用戶的openId:
    用戶登陸小程序 經過受權獲得微信code,而後將微信code、祕鑰、密文傳遞後端,後端進行解密後 獲得微信openId
(前端也能夠進行解密,但建議放後端)下面是獲取openId的代碼(java)

java

//獲取微信openId接口url 
https://api.weixin.qq.com/sns/jscode2session
 
/**
     * 解析小程序登陸數據獲取參數
     * @param code  ---微信code
     * @param encryptedData --- 加密參數
     * @param iv --- 祕鑰
     * @return
     */
    public Result<?> getAuthByApplet(String code, String encryptedData,
                                     String iv) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            log.debug("=========小程序獲取unionId=============: "+ code);
            //封裝參數
            Map<String, String> params = new HashMap<String, String>();
            //獲取小程序的openId
            params.put("appid", appletId);
            //微信祕鑰
            params.put("secret", appletSecret);
            params.put("js_code", code);
            params.put("grant_type", "authorization_code");
            //調用接口進行讀取參數
            JsonObject retJson =  OkHttpUtils.doGetRetJson(appletOpenIdUrl, params);
            log.debug(retJson.toString());
            //若是獲取到了openId
            if(retJson.get("openid") != null) {
                //獲取會話密鑰(session_key)
                String session_key = retJson.get("session_key").getAsString();
                resultMap.put("session_key", session_key);
                resultMap.put("openId", retJson.get("openid").getAsString());
            }else{
                throw new Exception("code已失效,請從新獲取");
            }
            return Result.ok(resultMap);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

 

獲得openId後要進行業務保存,由於小程序不少接口都依賴openId,並且同一小程序下,每一個微信號的openId是同樣
的。


小程序

二:統一下單與小程序支付
        經過業務系統的封裝參數,獲得支付的商品信息,價格,業務訂單後,封裝參數,進行加密獲得sign簽名,而後
調用統一下單接口進行下單,成功後返回小程序支付參數。
(須要注意的是 微信預下單請求參數要求是xml格式,全String類型)後端

//微信預下單接口url
https://api.mch.weixin.qq.com/pay/unifiedorder
/**
     * 微信支付-統一下單
     * @param body --- 商品描述
     * @param outTradeNo --- 業務系統訂單號
     * @param totalFee --- 支付金額
     * @param spBillCreateIP ---支付人所在
     * @param openId --- 支付人的微信openId
     * @return
     */
    @Override
    public Map<String, String> toPay(String body,  String outTradeNo,
                                     String totalFee, String spBillCreateIP, String openId) {
        try{
            Map<String, String> map = new HashMap<>();
            //封裝支付必須參數
            SortedMap<Object,Object> params = new TreeMap<Object,Object>();
            //支付類型      String tradeType = "JSAPI";
            //支付後回調地址
            String notifyUrl = "";
            String nonceStr = RandomUtil.randomString(16);
            //小程序id
            params.put("appid", appletId);
            //商戶平臺id
            params.put("mch_id", mchId);
            //隨機字符串
            params.put("nonce_str", nonceStr);
            //商品描述
            params.put("body", body);
            //商品訂單號
            params.put("out_trade_no", outTradeNo);
            //價格的單位爲分
            params.put("total_fee", totalFee);
            //支付ip
            params.put("spbill_create_ip", spBillCreateIP);
            //異步回調api
            params.put("notify_url", notifyUrl);
            //JSAPI、h5調用
            params.put("trade_type", tradeType);
            //支付用戶openid
            params.put("openid", openId);
            String sign = WxPaySignatureUtils.createSign(params, key);
            params.put("sign", sign);
            String requestXML = WxPaySignatureUtils.getRequestXml(params);
            log.info("發送給微信的報文:" + requestXML);
            log.info("加密後的的簽名字符串:" + sign);
            //調用微信接口
            String result = OkHttpUtils.postXml(unifiedorder, requestXML);
            log.info("-------------------請求返回結果------------------");
            log.info(result);
            map = WXPayUtil.xmlToMap(result);
            //若是返回有數據
            if(map != null){
                //而且返回有sign
                if(map.get("sign") != null){
                    return map;
                }
            }
            return map;
        }catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

接口請求成功後,微信返回也是xml格式的報文,須要將xml轉爲map或其餘,本文使用map接收參數,預下單後,
微信會返回預付訂單標識,標識用於進支付。微信小程序

//預付訂單標識
String prepayId = resultMap.get("prepay_id");

而後封裝小程序支付 所需參數api

//簽名類型,默認爲MD5
String signType = "MD5";
SortedMap<Object,Object> params = new TreeMap<Object,Object>();
params.put("appId", appletId);
params.put("timeStamp", timestamp + "");
params.put("timeStamp", timestamp + "");
params.put("nonceStr", nonceStr);
params.put("package", "prepay_id=" + prepayId);
params.put("signType", signType);
//生成簽名
String sign = WxPaySignatureUtils.createSign(params, key);
params.put("paySign", sign);

將支付參數返回給小程序,小程序經過組件 requestPayment 喚醒支付
小程序支付代碼以下:微信

wx.requestPayment({

      timeStamp:param.result.timeStamp,

      nonceStr: param.result.nonceStr,

      package: param.result.package,

      signType:param.result.signType,

      paySign: param.result.paySign,

      success: function(res){

        console.log(res);

        wx.showToast({

          title: '支付成功',

          icon: 'success',

          duration: 2000

          });          

      },

      fail: function(res) {

        wx.showModal({

          title:'支付失敗',

          content:'<text>',

          showCancel: false

        })

      }

    })

 

三: 退款
    小程序支付成功後,能夠經過支付訂單號進行退款操做,須要注意的是,退款須要http攜帶商戶證書進行支
付,這裏圖圖已經封裝好工具類只須要修改下證書的url就能夠愉快使用了。

session

//微信退款使用的url
https://api.mch.weixin.qq.com/secapi/pay/refund
/**
     * 微信支付-退款
     * @param transaction_id   ---微信支付訂單
     * @param out_refund_no --- 系統退款單號
     * @param total_fee  --- 訂單總金額
     * @param refund_fee  --- 退款金額
     * @return
     */
    @Override
    public Map<String, String> refundToPay(String transaction_id, String out_refund_no, String out_trade_no, int total_fee, int refund_fee) {
        //定義返回參數
        Map<String, String> map = new HashMap<>();
        try{
            SortedMap<Object,Object> params = new TreeMap<Object,Object>();
            String notifyUrl = "https://baidu.com";
            String nonceStr = RandomUtil.randomString(16);
            //小程序id
            params.put("appid", appletId);
            //商戶平臺id
            params.put("mch_id", mchId);
            //隨機字符串
            params.put("nonce_str", nonceStr);
            //系統訂單號
            params.put("out_trade_no", out_trade_no);
            //微信訂單號
            params.put("transaction_id", transaction_id);
            //系統退款單號
            params.put("out_refund_no", out_refund_no);
            //訂單金額
            params.put("total_fee", total_fee);
            //退款金額
            params.put("refund_fee", refund_fee);
            //簽名
            String sign = WxPaySignatureUtils.createSign(params, key);
            params.put("sign", sign);
            //封裝請求報文
            String requestXML = WxPaySignatureUtils.getRequestXml(params);
            log.info("發送給微信的報文:" + requestXML);
            log.info("加密後的的簽名字符串:" + sign);
            //調用微信接口
            String result = WXPayUtil.doRefundRequest(mchId, refund, requestXML, certificateUrl);
            log.info("-------------------請求返回結果------------------");
            log.info(result);
            if(StrUtil.isNotEmpty(result)){
                map = WXPayUtil.xmlToMap(result);
                //若是返回有數據
                if(map != null){
                    //而且返回有sign
                    if(map.get("sign") != null){
                        return map;
                    }
                }
            }else{
                log.info("-------------------請求返回空結果------------------");
            }
            return map;
        }catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException();
        }
    }

 

本文中所使用到的工具類,圖圖已經幫你們打包好了,在百度網盤。app

百度網盤下載連接

連接:https://pan.baidu.com/s/1YbMrvO3qK1rdmyYyET2xzw

提取碼:ljv6

 

本文先總結到此,後面繼續更新技術一些文章。你們一塊兒加油鴨!

相關文章
相關標籤/搜索