扣款接口实现
/** * @param :out_trade_no-订单号;total_fee-订单总金额;contract_id-签约成功后,微信返回的委托代扣协议id * @Author : lilong * @Description :微信支付扣款 * @Date : 11:16 2018/5/4 **/ public void wxDeductMoney(String out_trade_no, Integer total_fee, String contract_id) throws Exception { //扣款请求的参数集合 Map<String, String> map = new HashMap<>(); //签名所需要的参数 //生成随机数 String nonce_str = getNonce(); String body = "HH"; String detail = "HH"; String attach = "666"; String fee_type = "CNY"; String spbill_create_ip = "192.168.1.1"; String goods_tag = "WXG"; String notify_url = "http://www.sz.cn/mvc/wechat/callbackDeductMoney";//回调 //交易类型---微信委托代扣支付 String trade_type = "PAP"; map.put("appid", appid); map.put("mch_id", mch_id); map.put("nonce_str", nonce_str); map.put("body", body); map.put("detail", detail); map.put("attach", attach); map.put("out_trade_no", out_trade_no); map.put("total_fee", total_fee.toString()); map.put("fee_type", fee_type); map.put("spbill_create_ip", spbill_create_ip); map.put("goods_tag", goods_tag); map.put("notify_url", notify_url); map.put("trade_type", trade_type); map.put("contract_id", contract_id); String sign = createSign(map); map.put("sign", sign); //map 转 xml String xmlParams = mapToXml(map); String url = "https://api.mch.weixin.qq.com/pay/pappayapply"; HttpPost post = new HttpPost(url); //设置请求头 设置参数格式 post.setHeader("Content-type", "text/xml; charset=utf-8"); //表明请求身份----模拟浏览器 post.setHeader("User-Agent", "Firefox/6.0.2"); HttpClient client = HttpClients.createDefault(); post.setEntity(new StringEntity(xmlParams, "UTF-8")); HttpResponse response = client.execute(post); HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity, "UTF-8"); System.err.println(扣款返回结果:" + result); }
支付成功之后返回一下结果
扣款测试:<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx05c902527492c474]]></appid>
<mch_id><![CDATA[1484707102]]></mch_id>
<nonce_str><![CDATA[mZj50pMP5ucB2F8z]]></nonce_str>
<sign><![CDATA[E95D4DDC08E67351C1C91D3719F1B8A1]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
</xml>
将map转化为xml
/** * @Author : lilong * @Description :map 转 xml * @Date : 15:45 2018/5/4 **/ public String mapToXml(Map<String, String> map) throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); org.w3c.dom.Document document = documentBuilder.newDocument(); org.w3c.dom.Element element = document.createElement("xml"); document.appendChild(element); for (String key : map.keySet()) { String value = map.get(key); if (value == null) { value = ""; } value = value.trim(); org.w3c.dom.Element filed = document.createElement(key); filed.appendChild(document.createTextNode(value)); element.appendChild(filed); } TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); DOMSource source = new DOMSource(document); transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StringWriter write = new StringWriter(); StreamResult result = new StreamResult(write); transformer.transform(source, result); String output = write.getBuffer().toString();////.replaceAll("\n|\r", ""); try { write.close(); } catch (Exception e) { } return output; }
退款---退款是需要下载证书并处理
/** * @param :out_trade_no:商户订单号 out_refund_no:商户退款单号 total_fee:订单金额 refund_fee:退款金额 * @Author : lilong * @Description :微信退款 * @Date : 14:44 2018/6/11 **/ public void weChatRefund(String out_trade_no, String out_refund_no, Integer total_fee, Integer refund_fee) throws Exception { //扣款请求的参数集合 Map<String, String> map = new HashMap<>(); //签名所需要的参数 //生成随机数 String nonce_str = getNonce(); map.put("appid", appid); map.put("mch_id", mch_id); map.put("nonce_str", nonce_str); //商户订单号 map.put("out_trade_no", out_trade_no); //商户退款单号 map.put("out_refund_no", out_refund_no); map.put("total_fee", total_fee.toString()); map.put("refund_fee", refund_fee.toString()); String sign = createSign(map); map.put("sign", sign); //map 转 xml String xmlParams = mapToXml(map); //证书 KeyStore keyStore = KeyStore.getInstance("PKCS12"); FileInputStream instream = new FileInputStream(new File("D:/cert/apiclient_cert.p12"));//退款证书的路径 try { keyStore.load(instream, mch_id.toCharArray()); } finally { instream.close(); } SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build(); SSLConnectionSocketFactory sslf = new SSLConnectionSocketFactory(sslcontext); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslf).build(); try { HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");//退款接口 System.out.println("executing request" + httpPost.getRequestLine()); StringEntity reqEntity = new StringEntity(xmlParams); // 设置类型 reqEntity.setContentType("application/x-www-form-urlencoded"); httpPost.setEntity(reqEntity); CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); if (entity != null) { System.out.println("Response content length: " + entity.getContentLength()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); String line; String xmlParam = ""; while ((line = bufferedReader.readLine()) != null) { xmlParam += line; } Map<String, String> returnMap = xmlToMap(xmlParam); //判断退款状态修改订单状态 if ("SUCCESS".equals(returnMap.get("return_code"))) { if ("SUCCESS".equals(returnMap.get("result_code"))) { String orderid = returnMap.get("out_trade_no"); HahaCounterOrder hahaCounterOrder = hahaCountMng.getHahaCounterOrdersById(orderid); hahaCounterOrder.setPaymentStatus("ReFund"); hahaCountMng.updateOrderCounter(hahaCounterOrder); } } } EntityUtils.consume(entity); } finally { response.close(); } } finally { httpclient.close(); } }
退款之后的返回结果如下,拿到结果之后处理相关逻辑即可。<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx05c902527492c474]]></appid>
<mch_id><![CDATA[1484707102]]></mch_id>
<nonce_str><![CDATA[7EvqWpL2hrRB0c4P]]></nonce_str>
<sign><![CDATA[2F25E9F1DD8268358E1A158C267715D6]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<transaction_id><![CDATA[4200000110201806087283568184]]></transaction_id>
<out_trade_no><![CDATA[201806075802722891]]></out_trade_no>
<out_refund_no><![CDATA[201806075802722891]]></out_refund_no>
<refund_id><![CDATA[50000006902018061205029257575]]></refund_id>
<refund_channel><![CDATA[]]></refund_channel>
<refund_fee>1</refund_fee>
<coupon_refund_fee>0</coupon_refund_fee>
<total_fee>1</total_fee>
<cash_fee>1</cash_fee>
<coupon_refund_count>0</coupon_refund_count>
<cash_refund_fee>1</cash_refund_fee>
</xml>
值得注意的是:退款缺少证书是会报以下异常-->
wx sendpost exception
org.apache.http.NoHttpResponseException: api.mch.weixin.qq.com:443 failed to respond