1. 程式人生 > >微信公眾號支付之退款

微信公眾號支付之退款

這一篇緊接著上面支付的那篇。

參考文件:

申請退款

https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_4&index=4 

 

退款結果通知

https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_16&index=10

 

 

1.退款的時候需要配置認證的證書如圖

 

2.申請退款介面

                FileInputStream instream = null;
                CloseableHttpClient httpclient 
= null; try { StringBuffer xml = new StringBuffer(); String data = null; String nonceStr = WXPayUtil.generateNonceStr(); xml.append("</xml>"); SortedMap<String,String> parameters = new
TreeMap<String,String>(); parameters.put("appid", weixinConfig.getWeiXinPayAppId()); parameters.put("mch_id", weixinConfig.getMchId()); parameters.put("sign_type","MD5"); parameters.put("nonce_str", nonceStr); parameters.put(
"out_refund_no", or.getCart().getId()); parameters.put("out_trade_no", orderNo); parameters.put("refund_fee", WXPayUtil.getMoney(or.getPrice().setScale(2, BigDecimal.ROUND_DOWN).toString())); parameters.put("total_fee", WXPayUtil.getMoney(orderPayment.getTotalPrice().setScale(2, BigDecimal.ROUND_DOWN).toString())); parameters.put("fee_type", "CNY"); parameters.put("op_user_id", weixinConfig.getMchId()); parameters.put("notify_url", weixinConfig.getWeiXinRefundNotifyUrl()); parameters.put("transaction_id", orderPayment.getBusinessOrderNo()); String createSign1 = WXPayUtil.createSign(parameters, weixinConfig.getWeiXinPayAppSecret()); parameters.put("sign", createSign1); data =WXPayUtil.SortedMaptoXml(parameters); logger.info("微信申請退款請求資料資訊:"+data); KeyStore keyStore = KeyStore.getInstance("PKCS12"); instream = new FileInputStream(new File(weixinConfig.getWeiXinPayKey())); try { keyStore.load(instream, weixinConfig.getMchId().toCharArray()); } catch (Exception e) { e.printStackTrace(); }finally{ instream.close(); } SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, weixinConfig.getMchId().toCharArray()) .build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); httpclient = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund"); StringEntity entitys = new StringEntity(data, "UTF-8"); httppost.setEntity(entitys); CloseableHttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); StringBuilder sb2 = new StringBuilder(); String xmlStr2 = null;//讀入響應流中字串的引用 if (entity != null) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); while ((xmlStr2 = bufferedReader.readLine()) != null) { sb2.append(xmlStr2); } } //關閉流物件 EntityUtils.consume(entity); logger.info("微信申請退款響應資料資訊:"+sb2.toString()); //處理返回的結果XML Map<String, String> refundOrderMap = WXPayUtil.xmlToMap(sb2.toString()); if(refundOrderMap.size()>0){ if(refundOrderMap.get("return_code").equals("SUCCESS") && refundOrderMap.get("result_code").equals("SUCCESS")){ //退款申請請求傳送成功 處理自己專案的業務邏輯 TODO }else{
                 //處理自己專案的業務邏輯 TODO
} }else{ //TODO } } catch(Exception e){ //TODO }finally { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } }

 

3.微信退款結果通知

/**
     * 退款成功非同步回撥介面
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/refundNotice", produces = "text/html;charset=utf-8")
    @ResponseBody
    public String weiXinRefundNotice(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ServletInputStream instream = request.getInputStream();
        StringBuffer sb = new StringBuffer();
        int len = -1;
        byte[] buffer = new byte[1024];
        while ((len = instream.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, len));
        }
        instream.close();
        log.info("退款通知資訊:" + sb.toString());
        Map<String, String> map = WXPayUtil.xmlToMap(sb.toString());// 接受微信的回撥的通知引數
        Map<String, String> return_data = new HashMap<String, String>();
        // 判斷returnCode狀態
        if (map.get("return_code").toString().equals("FAIL")) {
            return_data.put("return_code", "FAIL");
            return_data.put("return_msg", map.get("return_msg"));
        } else if (map.get("return_code").toString().equals("SUCCESS")) {
            String reqInfo = map.get("req_info");
            byte[] decode = Base64.decodeBase64(reqInfo);
            String key = MD5Util.MD5(weixinConfig.getWeiXinPayAppSecret()).toLowerCase();
            String decryptData = WXPayUtil.getRefundDecrypt(decode,key);
            log.info("退款通知資訊解密資料:"+decryptData);
            Map<String, String> mm = WXPayUtil.xmlToMap(decryptData);
            if (mm.get("refund_status").equals("SUCCESS")){//退款成功
                  //處理自己的業務邏輯  TODO
              }else if (map.get("refund_status").equals("CHANGE")) {//退款異常
              
              }else if (map.get("refund_status").equals("REFUNDCLOSE")) {//退款關閉
              
              }
             
        }
        String xml = WXPayUtil.GetMapToXML(return_data);
        log.info("退款通知回撥結果:" + xml);
        return xml;
    }

 

 

總結:

1.官方文件給的傳值引數一定要注意看

2.官方文件裡面的有一個方法的字符集有問題,導致返回的資訊亂碼,無法快速的定位到問題點,上述示例程式碼已更正

 

上述兩篇關於微信支付的實現,只是最基礎的功能實現,歡迎大家一起討論和糾正。