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 certs SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()).build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory 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 block e.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 certs SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()) .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory 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())); 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" }; }
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 */ @Controller public 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 certs SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPayConstants.MCH_ID.toCharArray()).build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory 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"/>为新设置的appid public 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); // 参数放入Entity httpPost.setEntity(formEntity); CloseableHttpResponse response = null; String result = null; try { // 执行post请求 response = httpclient.execute(httpPost); // 得到entity HttpEntity 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 { // 关闭CloseableHttpResponse if (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-type entity.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 { // 关闭CloseableHttpResponse if (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请求,并得到一个CloseableHttpResponse response = httpclient.execute(httpPost); // 从CloseableHttpResponse中拿到HttpEntity HttpEntity entity = response.getEntity(); // 将HttpEntity转换为字符串 result = EntityUtils.toString(entity); } catch (IOException e) { log.error(e.getMessage()); } finally { // 关闭CloseableHttpResponse if (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大平台支付宝、微信 的支付模块的 登录模块
起来改
下面这个gif和你们写完代码,测试成功后的表情是不是很像呢?哈哈哈哈哈.....
跟你们像不像
本文暂时没有评论,来添加一个吧(●'◡'●)