微信公眾號支付之退款
阿新 • • 發佈:2018-12-31
這一篇緊接著上面支付的那篇。
參考文件:
申請退款
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 = newTreeMap<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.官方文件裡面的有一個方法的字符集有問題,導致返回的資訊亂碼,無法快速的定位到問題點,上述示例程式碼已更正
上述兩篇關於微信支付的實現,只是最基礎的功能實現,歡迎大家一起討論和糾正。