这一篇紧接着上面支付的那篇。
参考文档:
申请退款
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.官方文档里面的有一个方法的字符集有问题,导致返回的信息乱码,无法快速的定位到问题点,上述示例代码已更正
上述两篇关于微信支付的实现,只是最基础的功能实现,欢迎大家一起讨论和纠正。