完成小程序支付和保存支付通知內容以後,接下來就是退款啦php
官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4java
注意:web
調用API時須要使用證書,因此咱們須要下載證書,並放在服務器裏某個位置小程序
/*
* 密鑰證書文件的存放路徑
*/
public static final String KEY_PATH = "/wwwroot/web/wechat/apiclient_cert.p12";api
代碼以下:服務器
----SpringBoot 的Controller /** * 申請退款 * @return */ @RequestMapping(value = "/refund", method = RequestMethod.GET) @Transactional public @ResponseBody Map<String, Object> refund(String id,String user) { Map<String,Object> result = new HashMap<String,Object>(); String currTime = PayUtils.getCurrTime(); String strTime = currTime.substring(8, currTime.length()); String strRandom = PayUtils.buildRandom(4) + ""; String nonceStr = strTime + strRandom; String outRefundNo = "wx@re@"+PayUtils.getTimeStamp(); String outTradeNo = ""; ProfPayLog payLog = wxappOrderService.findByPayLogId(Long.valueOf(id)); DecimalFormat df = new DecimalFormat("######0"); String fee = String.valueOf(df.format((Double.valueOf(payLog.getTotalFee())*100))); SortedMap<String, String> packageParams = new TreeMap<String, String>(); packageParams.put("appid", appId); packageParams.put("mch_id", mchId);//微信支付分配的商戶號 packageParams.put("nonce_str", nonceStr);//隨機字符串,不長於32位 packageParams.put("op_user_id", mchId);//操做員賬號, 默認爲商戶號 //out_refund_no只能含有數字、字母和字符_-|*@ packageParams.put("out_refund_no", outRefundNo);//商戶系統內部的退款單號,商戶系統內部惟一,同一退款單號屢次請求只退一筆 packageParams.put("out_trade_no", outTradeNo);//商戶側傳給微信的訂單號32位 packageParams.put("refund_fee", fee); packageParams.put("total_fee", fee); packageParams.put("transaction_id", payLog.getTransactionId());//微信生成的訂單號,在支付通知中有返回 String sign = PayUtils.createSign(packageParams,key); String refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund"; String xmlParam="<xml>"+ "<appid>"+appId+"</appid>"+ "<mch_id>"+mchId+"</mch_id>"+ "<nonce_str>"+nonceStr+"</nonce_str>"+ "<op_user_id>"+mchId+"</op_user_id>"+ "<out_refund_no>"+outRefundNo+"</out_refund_no>"+ "<out_trade_no>"+outTradeNo+"</out_trade_no>"+ "<refund_fee>"+fee+"</refund_fee>"+ "<total_fee>"+fee+"</total_fee>"+ "<transaction_id>"+payLog.getTransactionId()+"</transaction_id>"+ "<sign>"+sign+"</sign>"+ "</xml>"; String resultStr = PayUtils.post(refundUrl, xmlParam); //解析結果 try { Map map = PayUtils.doXMLParse(resultStr); String returnCode = map.get("return_code").toString(); if(returnCode.equals("SUCCESS")){ String resultCode = map.get("result_code").toString(); if(resultCode.equals("SUCCESS")){ ProfPayLog profPayLog = new ProfPayLog(); profPayLog.setCreatedAt(new Date()); profPayLog.setSource(payLog.getSource()); profPayLog.setTotalFee(payLog.getTotalFee()); profPayLog.setTradeNo(payLog.getTradeNo()); profPayLog.setTransactionId(map.get("refund_id").toString()); profPayLog.setUserId(user); profPayLog.setType(ProfPayLog.Type.Refund); profPayLog = wxappOrderService.save(profPayLog); result.put("status", "success"); }else{ result.put("status", "fail"); } }else{ result.put("status", "fail"); } } catch (Exception e) { e.printStackTrace(); result.put("status", "fail"); } return result; }
----PayUtils public static String post(String url, String xmlParam){ StringBuilder sb = new StringBuilder(); try { KeyStore keyStore = KeyStore.getInstance("PKCS12"); FileInputStream instream = new FileInputStream(new File(KEY_PATH)); try { keyStore.load(instream, "商戶id".toCharArray()); } finally { instream.close(); } // 證書 SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, "商戶id".toCharArray()) .build(); // 只容許TLSv1協議 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); //建立基於證書的httpClient,後面要用到 CloseableHttpClient client = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); HttpPost httpPost = new HttpPost(url);//退款接口 StringEntity reqEntity = new StringEntity(xmlParam); // 設置類型 reqEntity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(reqEntity); CloseableHttpResponse response = client.execute(httpPost); try { HttpEntity entity = response.getEntity(); System.out.println(response.getStatusLine()); if (entity != null) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8")); String text=""; while ((text = bufferedReader.readLine()) != null) { sb.append(text); } } EntityUtils.consume(entity); } catch(Exception e){ e.printStackTrace(); }finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); }
注意:商戶id那個地方填前面用到的mch_id,由於證書是微信認證過的商戶獨有的。微信