SpringBoot 微信退款功能的示例代碼
一:微信支付證書配置
二:證書讀取以及讀取后的使用
package com.zhx.guides.assistant.config.wechatpay; import org.apache.commons.io.IOUtils;import org.apache.http.HttpEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.ssl.SSLContexts;import org.apache.http.util.EntityUtils;import org.springframework.core.io.ClassPathResource; import javax.net.ssl.SSLContext;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.security.KeyStore; /** * @Class WeChatConfigUtil * @Version 1.0 * @Date 創建時間:2020-06-15 16:19 * @Copyright Copyright by * @Direction 類說明 */public class WeChatConfigUtil { private static byte[] certData; /**** * @throws Exception */ static { try { //從微信商戶平臺下載的安全證書存放的目錄 //String certPath = 'D:configapiclient_cert.p12'; //File file = new File(certPath); //InputStream certStream = new FileInputStream(file); //使用springboot配置文件內讀取的方式 ClassPathResource classPathResource = new ClassPathResource('user_keyapiclient_cert.p12'); InputStream certStream = classPathResource.getInputStream(); WeChatConfigUtil.certData = IOUtils.toByteArray(certStream); certStream.read(WeChatConfigUtil.certData); certStream.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 開始退款操作 * * @param mchId 商戶ID * @param url 請求URL * @param data 退款參數 * @return * @throws Exception */ public static String doRefund(String mchId, String url, String data) throws Exception { /** * 注意PKCS12證書 是從微信商戶平臺-》賬戶設置-》 API安全 中下載的 */ KeyStore keyStore = KeyStore.getInstance('PKCS12'); //這里自行實現我是使用數據庫配置將證書上傳到了服務器可以使用 FileInputStream讀取本地文件 //ByteArrayInputStream inputStream = FileUtil.getInputStream('https://############################.p12'); ByteArrayInputStream inputStream = new ByteArrayInputStream(WeChatConfigUtil.certData); try { //這里寫密碼..默認是你的MCHID keyStore.load(inputStream, mchId.toCharArray()); } finally { inputStream.close(); } SSLContext sslcontext = SSLContexts.custom()//這里也是寫密碼的.loadKeyMaterial(keyStore, mchId.toCharArray()).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,SSLConnectionSocketFactory.getDefaultHostnameVerifier()); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { HttpPost httpost = new HttpPost(url); httpost.setEntity(new StringEntity(data, 'UTF-8')); CloseableHttpResponse response = httpclient.execute(httpost); try {HttpEntity entity = response.getEntity();//接受到返回信息String jsonStr = EntityUtils.toString(response.getEntity(), 'UTF-8');EntityUtils.consume(entity);return jsonStr; } finally {response.close(); } } finally { httpclient.close(); } } }
三:發起訂單退款操作
/** * 封裝查詢請求數據 * @param tradeRefund 退款訂單請求信息 * @param path數據訪問PATH * @return */private static SortedMap<String, Object> refundData( TradeRefund tradeRefund , String path ) throws Exception {//構建參數Map<String, String> dataMap = new HashMap<>();dataMap.put('appid','wx#################');dataMap.put('mch_id','137#############');//自行實現該隨機串dataMap.put('nonce_str',Core.MD5('12344'));dataMap.put('out_trade_no','P190808170038402889c5318502');dataMap.put('out_refund_no','P190808170038402889c5318502');dataMap.put('total_fee','1');dataMap.put('refund_fee','1');dataMap.put('refund_desc','退款');//生成簽名String sign = PayToolUtil.createSign('UTF-8', dataMap , WeichatPayConfigure.API_KEY );//WXPayUtil.generateSignature(dataMap, 'rv4###################');dataMap.put('sign', sign);//map數據轉xmlString requestXML = getRequestXml( dataMap );logger.info( '訂單退款請求參數:n' + requestXML );//發起退款String responseXml = WeChatConfigUtil.doRefund( WeichatPayConfigure.MCH_ID , 'https://api.mch.weixin.qq.com/secapi/pay/refund', requestXML );} /** * @author * @date 2016-4-22 * @Description:將請求參數轉換為xml格式的string * @param parameters * 請求參數 * @return */ public static String getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append('<xml>'); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if ('attach'.equalsIgnoreCase(k) || 'body'.equalsIgnoreCase(k) || 'sign'.equalsIgnoreCase(k)) { sb.append('<' + k + '>' + '<![CDATA[' + v + ']]></' + k + '>'); } else { sb.append('<' + k + '>' + v + '</' + k + '>'); } } sb.append('</xml>'); return sb.toString(); }
/** * @author * @date 2016-4-22 * @Description:sign簽名 * @param characterEncoding * 編碼格式 * @param packageParams * 請求參數 * @return */ public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) { StringBuffer sb = new StringBuffer(); Set es = packageParams.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if (null != v && !''.equals(v) && !'sign'.equals(k) && !'key'.equals(k)) { sb.append(k + '=' + v + '&'); } } sb.append('key=' + API_KEY); String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; }
package com.zhx.guides.assistant.interfaces.pay.wechatpay.util; import java.security.MessageDigest; public class MD5Util { private static String byteArrayToHexString(byte b[]) { StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++) resultSb.append(byteToHexString(b[i])); return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] + hexDigits[d2]; } public static String MD5Encode(String origin, String charsetname) { String resultString = null; try { resultString = new String(origin); MessageDigest md = MessageDigest.getInstance('MD5'); if (charsetname == null || ''.equals(charsetname)) resultString = byteArrayToHexString(md.digest(resultString .getBytes())); else resultString = byteArrayToHexString(md.digest(resultString .getBytes(charsetname))); } catch (Exception exception) { } return resultString; } /*** * 簡化版本 * @param s * @return */ public final static String MD5(String s) {char hexDigits[] = { ’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’, ’A’, ’B’, ’C’, ’D’, ’E’, ’F’ };try {byte[] btInput = s.getBytes('utf-8');// 獲得MD5摘要算法的 MessageDigest 對象MessageDigest mdInst = MessageDigest.getInstance('MD5');// 使用指定的字節更新摘要mdInst.update(btInput);// 獲得密文byte[] md = mdInst.digest();// 把密文轉換成十六進制的字符串形式int j = md.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];str[k++] = hexDigits[byte0 >>> 4 & 0xf];str[k++] = hexDigits[byte0 & 0xf];}return new String(str);} catch (Exception e) {e.printStackTrace();return null;}} private static final String hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; }
/** * @author * @date 2016-4-22 * @Description:將請求參數轉換為xml格式的string * @param parameters * 請求參數 * @return */ public static String getRequestXml(SortedMap<Object, Object> parameters) { StringBuffer sb = new StringBuffer(); sb.append('<xml>'); Set es = parameters.entrySet(); Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if ('attach'.equalsIgnoreCase(k) || 'body'.equalsIgnoreCase(k) || 'sign'.equalsIgnoreCase(k)) { sb.append('<' + k + '>' + '<![CDATA[' + v + ']]></' + k + '>'); } else { sb.append('<' + k + '>' + v + '</' + k + '>'); } } sb.append('</xml>'); return sb.toString(); }
四:請求XML示例
<xml> <appid>wx2421b1c4370ec43b</appid> <mch_id>10000100</mch_id> <nonce_str>6cefdb308e1e2e8aabd48cf79e546a02</nonce_str> <out_refund_no>1415701182</out_refund_no> <out_trade_no>1415757673</out_trade_no> <refund_fee>1</refund_fee> <total_fee>1</total_fee> <transaction_id></transaction_id> <sign>FE56DD4AA85C0EECA82C35595A69E153</sign></xml>
五:官方信息
官方地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
需注意這兩個參數我使用的是out_trade_no
總結
到此這篇關于SpringBoot 微信退款功能的示例代碼的文章就介紹到這了,更多相關SpringBoot 微信退款內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!
相關文章:
