java-微信支付-微信退款

編程語言 Java 微信 XML 專注JavaWeb開發 專注JavaWeb開發 2017-09-13

1、前面的申請微信支付流程我在這裡就不介紹了,今天主要講的是微信退款這一塊。主要是我會把退款的所有代碼貢獻出來給大家,方便大家可以直接copy到自己工程中就可以使用,不用再去自己寫!

2、微信退款 首選需要一個商戶證書,可以百度“微信商戶平臺”,點擊api安全去下載這個證書,證書名字是“apiclient_cert.p12”

3、隨後就是代碼片段

這些代碼copy下來的確是可以跑起來,小編不像有些人,貼代碼的時候不貼import的jar和pom文件,導致別人copy下來一堆jar找不到(請叫我良心小編)...大家在手機端看的時候可能代碼過於長,大家可以主要看核心代碼部分,生成簽名,生成訂單,這類代碼!有什麼疑問隨時私我。下面有好東西哦!

ClientCustomSSL類代碼如下

package com.mobilepay.wxpay.utils;import com.alibaba.fastjson.JSONObject;import com.mobilepay.wxpay.constants.WXPayConstants;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.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.SAXReader;import javax.net.ssl.SSLContext;import java.io.File;import java.io.FileInputStream;import java.security.KeyStore;/*** @Author: HONGLINCHEN* @Description: 微信退款* @Date: 2017-9-12 13:15*/public class ClientCustomSSL {/** * @Author: HONGLINCHEN * @Description:微信退款方法封裝 注意::微信金額的單位是分 所以這裡要X100 轉成int是因為 退款的時候不能有小數點* @param merchantNumber 商戶這邊的訂單號* @param wxTransactionNumber 微信那邊的交易單號* @param totalFee 訂單的金額* @Date: 2017-9-12 11:18 */public static Object setUrl(String merchantNumber,String wxTransactionNumber,double totalFee) {try{KeyStore keyStore = KeyStore.getInstance("PKCS12");FileInputStream instream = new FileInputStream(new File("D:\\微信商戶平臺支付證書\\apiclient_cert.p12"));try {keyStore.load(instream, WXPayConstants.MCH_ID.toCharArray());}finally {instream.close();}// Trust own CA and all self-signed certsSSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()).build();// Allow TLSv1 protocol onlySSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");String xml = com.mobilepay.wxpay.wxpayutils.WXPayUtil.wxPayRefund(merchantNumber,wxTransactionNumber,String.valueOf((int)(totalFee*100)));try {StringEntity se = new StringEntity(xml);httppost.setEntity(se);System.out.println("executing request" + httppost.getRequestLine());CloseableHttpResponse responseEntry = httpclient.execute(httppost);try {HttpEntity entity = responseEntry.getEntity();System.out.println(responseEntry.getStatusLine());if (entity != null) {System.out.println("Response content length: "+ entity.getContentLength());SAXReader saxReader = new SAXReader();Document document = saxReader.read(entity.getContent());Element rootElt = document.getRootElement();System.out.println("根節點:" + rootElt.getName());System.out.println("==="+rootElt.elementText("result_code"));System.out.println("==="+rootElt.elementText("return_msg"));String resultCode = rootElt.elementText("result_code");JSONObject result = new JSONObject();Document documentXml = DocumentHelper.parseText(xml);Element rootEltXml = documentXml.getRootElement();if(resultCode.equals("SUCCESS")){System.out.println("=================prepay_id===================="+ rootElt.elementText("prepay_id"));System.out.println("=================sign===================="+ rootEltXml.elementText("sign"));result.put("weixinPayUrl", rootElt.elementText("code_url"));result.put("prepayId", rootElt.elementText("prepay_id"));result.put("status","success");result.put("msg","success");}else{result.put("status","false");result.put("msg",rootElt.elementText("err_code_des"));}return result;}EntityUtils.consume(entity);}finally {responseEntry.close();}}finally {httpclient.close();}return null;}catch(Exception e){e.printStackTrace();JSONObject result = new JSONObject();result.put("status","error");result.put("msg",e.getMessage());return result;}}}

WXPayUtil類代碼如下

package com.mobilepay.wxpay.wxpayutils;import com.mobilepay.wxpay.constants.WXPayConstants;import com.mobilepay.wxpay.utils.MD5Util;import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.methods.PostMethod;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.conn.ssl.SSLContexts;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import javax.net.ssl.SSLContext;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.io.*;import java.security.KeyStore;import java.security.MessageDigest;import java.util.*;/*** @Author: HONGLINCHEN* @Description:微信支付* @Date: 2017-9-7 17:14*/public class WXPayUtil {public static String PostRequest(String url, String data) throws IOException {HttpClient client = new HttpClient();PostMethod post=new PostMethod(url);String result = "";post.addRequestHeader("Content-Type", "text/html; charset=utf-8");post.addRequestHeader("content", "text/html; charset=utf-8");post.setRequestBody(data);try {int status=client.executeMethod(post);result = post.getResponseBodyAsString();result = new String(result.getBytes(post.getResponseCharSet()), "utf-8");} catch (IOException e){// TODO Auto-generated catch blocke.printStackTrace();}return result;}/** * 創建md5摘要,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。*/public static String createSign(SortedMap<String, String> packageParams, String AppKey) {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=" + AppKey);String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();return sign;}/** * @Author: HONGLINCHEN * @Description:微信支付 統一下單* @param out_trade_no* @param body* @param detail* @param total_fee* @param ip_address* @Date: 2017-9-11 14:35 * @return:*/public static String unifiedOrder(String out_trade_no, String body, String detail, int total_fee,String ip_address) {StringBuffer xml = new StringBuffer();String data = null;try{xml.append("</xml>");if (body.length() > 32) {body = body.substring(0, 32);}SortedMap<String, String> parameters = new TreeMap();parameters.put("appid", WXPayConstants.APP_ID);parameters.put("body", body);parameters.put("detail", detail);parameters.put("mch_id", WXPayConstants.MCH_ID);parameters.put("nonce_str", genNonceStr());parameters.put("notify_url", "http://www.aidongsports.com/wx");parameters.put("out_trade_no", out_trade_no);parameters.put("fee_type", "CNY");parameters.put("spbill_create_ip", ip_address);parameters.put("total_fee", String.valueOf(total_fee));parameters.put("trade_type", "APP");parameters.put("sign", createSign(parameters, WXPayConstants.API_KEY));data = PostRequest("https://api.mch.weixin.qq.com/pay/unifiedorder",SortedMaptoXml(parameters));}catch (Exception e){e.printStackTrace();}return data;}/** * @Author: HONGLINCHEN * @Description:微信支付 退款* @param out_trade_no* @param total_fee* @Date: 2017-9-11 14:35 * @return:*/public static String wxPayRefund(String out_trade_no, String transaction_id,String total_fee) {StringBuffer xml = new StringBuffer();String data = null;try {String nonceStr = genNonceStr();xml.append("</xml>");SortedMap<String,String> parameters = new TreeMap<String,String>();parameters.put("appid", WXPayConstants.APP_ID);parameters.put("mch_id", WXPayConstants.MCH_ID);parameters.put("nonce_str", nonceStr);parameters.put("out_trade_no", out_trade_no);parameters.put("transaction_id", transaction_id);parameters.put("out_refund_no", nonceStr);parameters.put("fee_type", "CNY");parameters.put("total_fee", total_fee);parameters.put("refund_fee", total_fee);parameters.put("op_user_id", WXPayConstants.MCH_ID);parameters.put("sign", createSign(parameters, WXPayConstants.API_KEY));data =SortedMaptoXml(parameters);} catch (Exception e) {System.err.println(e.getMessage());return null;}return data;}/*** 證書使用* 微信退款*/public static String wxPayBack(String url, String data) throws Exception {KeyStore keyStore = KeyStore.getInstance("PKCS12");FileInputStream instream = new FileInputStream(new File("D:\\微信商戶平臺支付證書\\apiclient_cert.p12"));String result="";try {keyStore.load(instream, WXPayConstants.MCH_ID.toCharArray());} finally {instream.close();}// Trust own CA and all self-signed certsSSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()).build();// Allow TLSv1 protocol onlySSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,new String[] { "TLSv1" },null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();try {HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");StringEntity entitys = new StringEntity(data);httppost.setEntity((HttpEntity) entitys);CloseableHttpResponse response = httpclient.execute(httppost);try {HttpEntity entity = response.getEntity();if (entity != null) {BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));String text="";String t="";while ((text=bufferedReader.readLine()) != null) {t+=text;}byte[] temp=t.getBytes("gbk");//這裡寫原編碼方式String newStr=new String(temp,"utf-8");//這裡寫轉換後的編碼方式result=newStr;}EntityUtils.consume(entity);} finally {response.close();}} finally {httpclient.close();}return result;}/** * XML格式字符串轉換為Map * 微信支付 解析xml xml轉map 獲取prepay_id * @param strXML XML字符串* @return XML數據轉換後的Map * @throws Exception */public static Map<String, String> xmlToMap(String strXML) throws Exception {try {Map<String, String> data = new HashMap<String, String>();DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));org.w3c.dom.Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}try {stream.close();} catch (Exception ex) {// do nothing}return data;} catch (Exception ex) {WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);throw ex;}}/** * 獲取隨機字符串 Nonce Str * * @return String 隨機字符串*/public static String generateNonceStr() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}/** * 生成 MD5 * * @param data 待處理數據* @return MD5結果*/public static String MD5(String data) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");byte[] array = md.digest(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();}/** * 生成 HMACSHA256 * @param data 待處理數據* @param key 密鑰* @return 加密結果* @throws Exception */public static String HMACSHA256(String data, String key) throws Exception {Mac sha256_HMAC = Mac.getInstance("HmacSHA256");SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");sha256_HMAC.init(secret_key);byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString().toUpperCase();}/** * @Author: HONGLINCHEN * @Description:通過prepay_id 生成微信支付參數* @param prepay_id* @Date: 2017-9-8 10:17 */public static SortedMap<Object,Object> genPayRequest(String prepay_id) {SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();parameters.put("appid", WXPayConstants.APP_ID);parameters.put("noncestr", genNonceStr());parameters.put("package", "Sign=WXPay");parameters.put("partnerid", WXPayConstants.MCH_ID);parameters.put("prepayid", prepay_id);parameters.put("timestamp",getCurrentTimestamp());parameters.put("sign", MD5.createSign("utf-8", parameters).toUpperCase());return parameters;}/** * @Author: HONGLINCHEN * @Description:請求值轉換為xml格式 SortedMap轉xml * @param params* @Date: 2017-9-7 17:18 */private static String SortedMaptoXml(SortedMap<String,String> params) {StringBuilder sb = new StringBuilder();Set es = params.entrySet();Iterator it = es.iterator();sb.append("<xml>\n");while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();Object v = entry.getValue();sb.append("<"+k+">");sb.append(v);sb.append("</"+k+">\n");}sb.append("</xml>");return sb.toString();}/** * 日誌* @return*/public static Logger getLogger() {Logger logger = LoggerFactory.getLogger("wxpay java sdk");return logger;}/** * 生成32位隨機數字*/private static String genNonceStr() {Random random = new Random();return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}/** * 獲取當前時間戳,單位秒* @return*/public static long getCurrentTimestamp() {return System.currentTimeMillis()/1000;}/** * 生成 uuid, 即用來標識一筆單,也用做 nonce_str * @return*/public static String generateUUID() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);}}

MD5Util類代碼如下

package com.mobilepay.wxpay.utils;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()));elseresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));} catch (Exception exception) {}return resultString;}private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5","6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };}

WeiXinPayController類代碼如下

package com.mobilepay.wxpay.controller;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.mobilepay.wxpay.constants.WXPayConstants;import com.mobilepay.wxpay.utils.ClientCustomSSL;import com.mobilepay.wxpay.utils.RequestUtils;import com.mobilepay.wxpay.wxpayutils.WXPayUtil;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.apache.log4j.Logger;import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.SAXReader;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import javax.net.ssl.SSLContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.security.KeyStore;import java.util.SortedMap;import java.util.regex.Matcher;import java.util.regex.Pattern;import static com.mobilepay.wxpay.wxpayutils.WXPayUtil.genPayRequest;/*** @Author: HONGLINCHEN* @Description:微信支付* @Date: 2017-9-7 10:14*/@Controllerpublic class WeiXinPayController {private static final Logger logger = Logger.getLogger(WeiXinPayController.class);@RequestMapping(value = "/weixinpay",method = {RequestMethod.GET})public String weixinpay(HttpServletRequest request, HttpServletResponse response, Model model){return "wxpay";}@RequestMapping(value = "/wechatRefund",method = {RequestMethod.GET})public String wecharrefund(HttpServletRequest request, HttpServletResponse response, Model model){return "wechatrefund";}/*** @Author: HONGLINCHEN* @Description: 微信支付* @param number* @param money* @param request* @param response* @param model* @Date: 2017-9-11 13:51*/@RequestMapping(value = "/wxpay",method = {RequestMethod.GET,RequestMethod.POST})public String weixinpay(String number, double money, HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {String ipAddress = RequestUtils.getClientIpAddress(request);String bodyStr = "參與活動", detailStr = "微信支付測試 1.0*1";String paySignXml = WXPayUtil.unifiedOrder(number, bodyStr, detailStr, (int)(money*100), ipAddress);System.err.println("加密以後的支付參數\n"+paySignXml);try {String prepay_id = WXPayUtil.xmlToMap(paySignXml).get("prepay_id").toString();if(prepay_id!=null&&!"".equals(prepay_id)){SortedMap<Object,Object> pay = genPayRequest(prepay_id);System.err.println("實際支付參數\n"+pay);response.getWriter().print(JSON.toJSON(pay));}else{model.addAttribute("result","請求支付參數錯誤!");}} catch (Exception e) {e.printStackTrace();}return null;}/*** @Author: HONGLINCHEN 微信退款三種方式,隨便哪一個都可以* @Description:微信退款 注意::微信金額的單位是分 所以這裡要X100 轉成int是因為 退款的時候不能有小數點* @param merchantNumber 商戶這邊的訂單號* @param wxTransactionNumber 微信那邊的交易單號* @param totalFee 訂單的金額* @Date: 2017-9-12 11:18 */@RequestMapping(value = "/wxPayRefundTwo", method = { RequestMethod.GET, RequestMethod.POST })public String qxwxsign(String merchantNumber,String wxTransactionNumber,double totalFee,HttpServletResponse response, HttpServletRequest request) throws IOException {String param = WXPayUtil.wxPayRefund(merchantNumber,wxTransactionNumber,String.valueOf((int)(totalFee*100)));System.err.println("param"+param);String result = "";String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";try {result = WXPayUtil.wxPayBack(url, param);} catch (Exception e) {e.printStackTrace();}String tt = "2007072001201611180592733503";Pattern p = Pattern.compile("\\.*(\\w{" + tt.length() + "})\\.*");int st = result.indexOf("<refund_id>");String res = "";if (st >= 0) {int en = result.indexOf("</refund_id>");res = result.substring(st, en);Matcher m = p.matcher(res);if (m.find()) {res = m.group(1);}if (res.length() > 0) {result = "code:1,msg:退款成功";} else {result = "code:-1,msg:退款失敗";}response.getWriter().print(JSON.toJSON(result));}return null;}/*** @Author: HONGLINCHEN* @Description:微信退款 注意::微信金額的單位是分 所以這裡要X100 轉成int是因為 退款的時候不能有小數點* @param merchantNumber 商戶這邊的訂單號* @param wxTransactionNumber 微信那邊的交易單號* @param totalFee 訂單的金額* @Date: 2017-9-12 11:18*/@RequestMapping(value = "/wxPayRefund", method = { RequestMethod.GET, RequestMethod.POST })public Object wxPayRefund(String merchantNumber,String wxTransactionNumber,double totalFee) {try{KeyStore keyStore = KeyStore.getInstance("PKCS12");FileInputStream instream = new FileInputStream(new File("D:\\微信商戶平臺支付證書\\apiclient_cert.p12"));try {keyStore.load(instream, WXPayConstants.MCH_ID.toCharArray());}finally {instream.close();}// Trust own CA and all self-signed certsSSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()).build();// Allow TLSv1 protocol onlySSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();// HttpGet httpget = new // HttpGet("https://api.mch.weixin.qq.com/secapi/pay/refund");HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");//微信金額的單位是分 所以這裡要X100 轉成int是因為 退款的時候不能有小數點String xml = WXPayUtil.wxPayRefund(merchantNumber,wxTransactionNumber,String.valueOf((int)(totalFee*100)));try {StringEntity se = new StringEntity(xml);httppost.setEntity(se);System.out.println("executing request" + httppost.getRequestLine());CloseableHttpResponse responseEntry = httpclient.execute(httppost);try {HttpEntity entity = responseEntry.getEntity();System.out.println(responseEntry.getStatusLine());if (entity != null) {System.out.println("Response content length: "+ entity.getContentLength());SAXReader saxReader = new SAXReader();Document document = saxReader.read(entity.getContent());Element rootElt = document.getRootElement();System.out.println("根節點:" + rootElt.getName());System.out.println("==="+rootElt.elementText("result_code"));System.out.println("==="+rootElt.elementText("return_msg"));String resultCode = rootElt.elementText("result_code");JSONObject result = new JSONObject();Document documentXml = DocumentHelper.parseText(xml);Element rootEltXml = documentXml.getRootElement();if(resultCode.equals("SUCCESS")){System.out.println("=================prepay_id===================="+ rootElt.elementText("prepay_id"));System.out.println("=================sign===================="+ rootEltXml.elementText("sign"));result.put("weixinPayUrl", rootElt.elementText("code_url"));result.put("prepayId", rootElt.elementText("prepay_id"));result.put("status","success");result.put("msg","success");}else{result.put("status","false");result.put("msg",rootElt.elementText("err_code_des"));}return result;}EntityUtils.consume(entity);}finally {responseEntry.close();}}finally {httpclient.close();}return null;}catch(Exception e){e.printStackTrace();JSONObject result = new JSONObject();result.put("status","error");result.put("msg",e.getMessage());return result;}}/*** @Author: HONGLINCHEN* @Description:微信退款 注意::微信金額的單位是分 所以這裡要X100 轉成int是因為 退款的時候不能有小數點* @param merchantNumber 商戶這邊的訂單號* @param wxTransactionNumber 微信那邊的交易單號* @param totalFee 訂單的金額* @Date: 2017-9-12 11:18*/@RequestMapping(value = "/wxPayRefundone", method = { RequestMethod.GET, RequestMethod.POST })public Object wxPayRefundone(String merchantNumber,String wxTransactionNumber,double totalFee) {Object object = ClientCustomSSL.setUrl(merchantNumber,wxTransactionNumber,totalFee);return object;}}

WXPayConstants類代碼如下

package com.mobilepay.wxpay.constants;/*** @Author: HONGLINCHEN* @Description:微信支付參數* @Date: 2017-9-7 10:08*/public class WXPayConstants {//請同時修改 androidmanifest.xml裡面 .PayActivityd裡的屬性<data android:scheme="wxb4ba3c02aa476ea1"/>為新設置的appidpublic static final String APP_ID = "請替換為自己的";//商戶號public static final String MCH_ID = "請替換為自己的";//API密鑰,在商戶平臺設置public static final String API_KEY="請替換為自己的";//商戶號 微信小程序使用public static final String APPLET_MCHID = "請替換為自己的";//appid 微信小程序使用public static final String APPLET_APPID = "請替換為自己的";}

XMLUtil類代碼如下

package com.mobilepay.wxpay.wxpayutils;import org.dom4j.DocumentException;import org.dom4j.DocumentHelper;import org.jdom.Document;import org.jdom.Element;import org.jdom.JDOMException;import org.jdom.input.SAXBuilder;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;/*** @Author: HONGLINCHEN* @Description: xml 工具類* @Date: 2017-9-12 13:50*/public class XMLUtil {/** * 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml數據。 微信支付 解析xml xml轉map 獲取prepay_id * @param strxml* @throws JDOMException * @throws IOException */public static Map doXMLParse(String strxml) throws JDOMException, IOException {strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");if(null == strxml || "".equals(strxml)) {return null;}Map m = new HashMap();InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);Element root = doc.getRootElement();List list = root.getChildren();Iterator it = list.iterator();while(it.hasNext()) {Element e = (Element) it.next();String k = e.getName();String v = "";List children = e.getChildren();if(children.isEmpty()) {v = e.getTextNormalize();} else {v = XMLUtil.getChildrenText(children);}m.put(k, v);}//關閉流in.close();return m;}/** * @Author: HONGLINCHEN * @Description: 微信支付 解析xml xml轉map 獲取prepay_id * @param xml* @Date: 2017-9-8 10:13 */public static Map<String,Object> getResult(String xml){Map<String,Object> map = new HashMap<String, Object>();try {org.dom4j.Document document = DocumentHelper.parseText(xml);org.dom4j.Element root = document.getRootElement();Iterator<org.dom4j.Element> it = root.elementIterator();while (it.hasNext()) {org.dom4j.Element element = it.next();map.put(element.getName(), element.getTextTrim());}} catch (DocumentException e) {e.printStackTrace();}return map;}/** * 獲取子結點的xml * @param children* @return String */public static String getChildrenText(List children) {StringBuffer sb = new StringBuffer();if(!children.isEmpty()) {Iterator it = children.iterator();while(it.hasNext()) {Element e = (Element) it.next();String name = e.getName();String value = e.getTextNormalize();List list = e.getChildren();sb.append("<" + name + ">");if(!list.isEmpty()) {sb.append(XMLUtil.getChildrenText(list));}sb.append(value);sb.append("</" + name + ">");}}return sb.toString();}/** * 獲取xml編碼字符集* @param strxml* @return* @throws IOException * @throws JDOMException */public static String getXMLEncoding(String strxml) throws JDOMException, IOException {InputStream in = String2Inputstream(strxml);SAXBuilder builder = new SAXBuilder();Document doc = builder.build(in);in.close();return (String)doc.getProperty("encoding");}public static InputStream String2Inputstream(String str) {return new ByteArrayInputStream(str.getBytes());}}

MD5類代碼如下

package com.mobilepay.wxpay.wxpayutils;import com.mobilepay.wxpay.constants.WXPayConstants;import java.security.MessageDigest;import java.util.Iterator;import java.util.Map;import java.util.Set;import java.util.SortedMap;/*** @Author: HONGLINCHEN * @Description: MD5 工具類* @Date: 2017-9-12 13:51*/public class MD5 {public final static String getMessageDigest(byte[] buffer) {char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };try {MessageDigest mdTemp = MessageDigest.getInstance("MD5");mdTemp.update(buffer);byte[] md = mdTemp.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) {return null;}}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; } private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };/** * @Author: HONGLINCHEN * @Description:支付參數生成簽名* @param characterEncoding* @param parameters* @Date: 2017-9-8 10:29 */public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){ StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();//所有參與傳參的參數按照accsii排序(升序)Iterator it = es.iterator();while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); Object v = entry.getValue(); if(null != v && !"".equals(v)&& !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&"); }} sb.append("key=" + WXPayConstants.API_KEY);String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();return sign; }}

HttpUtil工具類代碼如下

package com.mobilepay.wxpay.wxpayutils;import org.apache.http.Consts;import org.apache.http.HttpEntity;import org.apache.http.NameValuePair;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.entity.StringEntity;import org.apache.http.entity.mime.HttpMultipartMode;import org.apache.http.entity.mime.MultipartEntityBuilder;import org.apache.http.entity.mime.content.FileBody;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Map;/*** @Author: HONGLINCHEN* @Description: Http工具類,發送Http請求, Get請求請將參數放在url中 Post請求請將參數放在Map中* @Date: 2017-9-12 13:52*/public class HttpUtil {private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);private static final CloseableHttpClient httpclient = HttpClients.createDefault();private static final String userAgent = "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36";/** * 發送HttpGet請求* * @param url* 請求地址* @return 返回字符串*/public static String sendGet(String url) {String result = null;CloseableHttpResponse response = null;try {HttpGet httpGet = new HttpGet(url);httpGet.setHeader("User-Agent", userAgent);response = httpclient.execute(httpGet);HttpEntity entity = response.getEntity();if (entity != null) {result = EntityUtils.toString(entity);}} catch (Exception e) {log.error("處理失敗 {}" + e);e.printStackTrace();} finally {if (response != null) {try {response.close();} catch (IOException e) {log.error(e.getMessage());}}}return result;}/** * 發送HttpPost請求,參數為map * * @param url* 請求地址* @param map* 請求參數* @return 返回字符串*/public static String sendPost(String url, Map<String, String> map) {// 設置參數List<NameValuePair> formparams = new ArrayList<NameValuePair>();for (Map.Entry<String, String> entry : map.entrySet()) {formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}// 編碼UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);// 取得HttpPost對象HttpPost httpPost = new HttpPost(url);// 防止被當成攻擊添加的httpPost.setHeader("User-Agent", userAgent);// 參數放入EntityhttpPost.setEntity(formEntity);CloseableHttpResponse response = null;String result = null;try {// 執行post請求response = httpclient.execute(httpPost);// 得到entityHttpEntity entity = response.getEntity();// 得到字符串result = EntityUtils.toString(entity);} catch (IOException e) {log.error(e.getMessage());} finally {if (response != null) {try {response.close();} catch (IOException e) {log.error(e.getMessage());}}}return result;}/** * 發送HttpPost請求,參數為文件,適用於微信上傳素材* * @param url* 請求地址* @param file* 上傳的文件* @return 返回字符串* @throws IOException * @throws ClientProtocolException */public static String sendPost(String url, File file) {String result = null;HttpPost httpPost = new HttpPost(url);// 防止被當成攻擊添加的httpPost.setHeader("User-Agent", userAgent);MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create();multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);multipartEntity.addPart("media", new FileBody(file));httpPost.setEntity(multipartEntity.build());CloseableHttpResponse response = null;try {response = httpclient.execute(httpPost);HttpEntity entity = response.getEntity();result = EntityUtils.toString(entity);} catch (IOException e) {log.error(e.getMessage());} finally {// 關閉CloseableHttpResponseif (response != null) {try {response.close();} catch (IOException e) {log.error(e.getMessage());}}}return result;}/** * 發送HttpPost請求,參數為json字符串* * @param url* @param jsonStr* @return*/public static String sendPost(String url, String jsonStr) {String result = null;// 字符串編碼StringEntity entity = new StringEntity(jsonStr, Consts.UTF_8);// 設置content-typeentity.setContentType("application/json");HttpPost httpPost = new HttpPost(url);// 防止被當成攻擊添加的httpPost.setHeader("User-Agent", userAgent);httpPost.setEntity(entity);CloseableHttpResponse response = null;try {response = httpclient.execute(httpPost);HttpEntity httpEntity = response.getEntity();result = EntityUtils.toString(httpEntity);} catch (IOException e) {log.error(e.getMessage());} finally {// 關閉CloseableHttpResponseif (response != null) {try {response.close();} catch (IOException e) {log.error(e.getMessage());}}}return result;}/** * 發送不帶參數的HttpPost請求* * @param url* @return*/public static String sendPost(String url) {String result = null;// 得到一個HttpPost對象HttpPost httpPost = new HttpPost(url);// 防止被當成攻擊添加的httpPost.setHeader("User-Agent", userAgent);CloseableHttpResponse response = null;try {// 執行HttpPost請求,並得到一個CloseableHttpResponseresponse = httpclient.execute(httpPost);// 從CloseableHttpResponse中拿到HttpEntityHttpEntity entity = response.getEntity();// 將HttpEntity轉換為字符串result = EntityUtils.toString(entity);} catch (IOException e) {log.error(e.getMessage());} finally {// 關閉CloseableHttpResponseif (response != null) {try {response.close();} catch (IOException e) {log.error(e.getMessage());}}}return result;}}

pom文件代碼如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.mobilepay.example</groupId><artifactId>MobilePay</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>MobilePay Maven Webapp</name><url>http://maven.apache.org</url><properties><!-- spring版本號 --><spring.version>4.0.2.RELEASE</spring.version><!-- mybatis版本號 --><mybatis.version>3.2.8</mybatis.version><!-- log4j日誌文件管理包版本 --><log4j.version>1.2.17</log4j.version><slf4j.version>1.7.21</slf4j.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--Spring--><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version><exclusions><exclusion><artifactId>commons-logging</artifactId><groupId>commons-logging</groupId></exclusion></exclusions></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-oxm</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!--Spring end--> <!-- log start --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>${slf4j.version}</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><!-- log end --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.32</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.6</version></dependency><!-- 微信支付工具類需要的jar start--><dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version></dependency><!-- 微信支付工具類需要的jar end--><dependency><groupId>jdom</groupId><artifactId>jdom</artifactId><version>1.1</version></dependency><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version><exclusions><exclusion><artifactId>commons-codec</artifactId><groupId>commons-codec</groupId></exclusion><exclusion><artifactId>commons-logging</artifactId><groupId>commons-logging</groupId></exclusion><exclusion><artifactId>commons-codec</artifactId><groupId>commons-codec</groupId></exclusion><exclusion><artifactId>commons-logging</artifactId><groupId>commons-logging</groupId></exclusion></exclusions></dependency><dependency><groupId>commons-cli</groupId><artifactId>commons-cli</artifactId><version>1.4</version></dependency><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.3</version><exclusions><exclusion><artifactId>commons-logging</artifactId><groupId>commons-logging</groupId></exclusion><exclusion><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId></exclusion></exclusions></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.10</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.3</version><exclusions><exclusion><artifactId>commons-codec</artifactId><groupId>commons-codec</groupId></exclusion><exclusion><artifactId>commons-logging</artifactId><groupId>commons-logging</groupId></exclusion><exclusion><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId></exclusion></exclusions></dependency><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.2</version></dependency><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version><exclusions><exclusion><artifactId>commons-pool</artifactId><groupId>commons-pool</groupId></exclusion></exclusions></dependency><dependency><groupId>commons-pool</groupId><artifactId>commons-pool</artifactId><version>1.6</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.3</version><exclusions><exclusion><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></exclusion></exclusions></dependency><dependency><groupId>net.sf.ezmorph</groupId><artifactId>ezmorph</artifactId><version>1.0.6</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency></dependencies><build><finalName>MobilePay</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.5.1</version><configuration><source>1.8</source><target>1.8</target><compilerArgument>-Xlint:all</compilerArgument><showWarnings>true</showWarnings><showDeprecation>true</showDeprecation></configuration></plugin></plugins></build></project>

好了,把這些 代碼複製到自己工程中並替換自己的東西,就可以跑起來了。

如果需要源代碼,或者整個工程(MobilePay)可以私聊我,我會解壓發給大家!

MobilePay這個項目中集成了所有的移動支付,包括2大平臺支付寶、微信 的支付模塊的 登錄模塊

java-微信支付-微信退款

起來改

下面這個gif和你們寫完代碼,測試成功後的表情是不是很像呢?哈哈哈哈哈.....

java-微信支付-微信退款

跟你們像不像

相關推薦

推薦中...