在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1.登录微信支付商户平台 https://pay.weixin.qq.com/index.php/partner/public/home 2.点击开发文档 3.进入如下界面点击小程序支付 4.微信公众平台支付账户认证 认证流程如下:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=3_1 认证完成后,微信开发支付参数说明如下: appid为和服务商商户号绑定的服务商appid,一般情况为认证的服务号appid; mch_id为服务商商户号,目前仅在认证服务号后台(mp.weixin.qq.com)开放申请服务商商户号,申请开通后即在微信支付系统创建绑定关系; sub_mch_id为和服务商商户号有父子绑定关系的子商户号; sub_appid为服务商模式的场景appid,在小程序中拉起支付时该字段必传; trade_type请填写JSAPI; openid为appid对应的微信用户标识; sub_openid为sub_appid对应的微信用户标识,小程序服务商模式下单中的openid和sub_openid必须至少传其中一个,在小程序中拉起支付一般情况下只能获取到sub_openid,即使用wx.login接口获得的openid。 5.小程序业务流程 商户系统和微信支付系统主要交互: 1)小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】 2)商户server调用支付统一下单,api参见公共api【统一下单API】 3)商户server调用再次签名,api参见公共api【再次签名】 4)商户server接收支付通知,api参见公共api【支付结果通知API】 5)商户server查询支付结果,api参见公共api【查询订单API】 小程序支付的交互图如下: 6.java程序接口API实现:
1) 生成订单 packagecom.jingweiiot.smart_home.utils.weixin.WXPay;
importjava.util.Map; importjava.util.SortedMap; importjava.util.TreeMap;
importjavax.servlet.http.HttpServletRequest; importcom.fasterxml.jackson.core.JsonProcessingException; importcom.fasterxml.jackson.databind.ObjectMapper; importcom.jingweiiot.smart_home.model.UserOrderInfo; publicclass CreateUserOrderInfo { /** * 生成订单 * @paramuserOrderInfo * @paramrequest *@return *@throws JsonProcessingException */ public static Map<String, String>createPayInfo(UserOrderInfo userOrderInfo,HttpServletRequest request) throwsJsonProcessingException {
SortedMap<String, String>params = new TreeMap<String, String>(); //自定义不重复的长度不长于32位 String nonceStr =StringUtil.getRandomString(30); params.put("openid",userOrderInfo.getOpenId()); //微信开放平台审核通过的应用APPID params.put("appid",WXPramsContent.appId); //微信支付分配的商户号 params.put("mch_id",WXPramsContent.mchId); //随机字符串 // params.put("nonce_str","1233212131221121212"); params.put("nonce_str",nonceStr); //商品描述 params.put("body",WXPramsContent.body); //商户订单号 params.put("out_trade_no",userOrderInfo.getOrderNum()); //总金额 params.put("total_fee","1"); // params.put("total_fee",userOrderInfo.getPayAmount().multiply(new BigDecimal(100)).toString()); //终端IP params.put("spbill_create_ip",WXPramsContent.getIpAddr(request)); //通知地址 params.put("notify_url",WXPramsContent.notifyUrl); //交易类型 params.put("trade_type",WXPramsContent.tradeType); //MD5签名 String sign =WeChat.createSign(params); params.put("sign", sign); //统一下单支付接口 String xmlStr =WeChat.httpsRequest(WXPramsContent.payUrl,"POST",WeChat.map2XmlString(params)); // System.err.println("xml:" +WeChat.map2XmlString(params)); //微信商户平台返回支付结果以及预支付id等 Map<String, String> response =WeChat.readXmlString2Map(xmlStr); //二次签名 //拼接签名需要的参数 ObjectMapper mapper = newObjectMapper(); System.err.println("response:" +mapper.writeValueAsString(response)); SortedMap<String, String>signParams = new TreeMap<String, String>(); signParams.put("appId",WXPramsContent.appId);//app_id signParams.put("nonceStr", nonceStr);//自定义不重复的长度不长于32位 signParams.put("package","prepay_id="+response.get("prepay_id"));//预付订单id System.out.println("package:"+response.get("prepay_id")); signParams.put("signType","MD5"); signParams.put("timeStamp",String.valueOf(System.currentTimeMillis()));//北京时间时间戳 String signAgain =WeChat.createSign(signParams); signParams.put("paySign",signAgain); return signParams; } }
2) 工具类 packagecom.jingweiiot.smart_home.utils.weixin.WXPay; importorg.dom4j.Document; importorg.dom4j.DocumentException; importorg.dom4j.DocumentHelper; importorg.dom4j.Element;
importcom.fasterxml.jackson.core.JsonProcessingException; importcom.fasterxml.jackson.databind.ObjectMapper;
importjava.io.BufferedReader; importjava.io.InputStream; importjava.io.InputStreamReader; importjava.io.OutputStream; importjava.net.ConnectException; importjava.net.HttpURLConnection; importjava.net.URL; importjava.security.MessageDigest; importjava.util.HashMap; importjava.util.Iterator; importjava.util.List; importjava.util.Map; importjava.util.Set; importjava.util.SortedMap; importjava.util.TreeMap; /** *dom4j解析xml * 利用HttpClient进行post请求的工具类 */ publicclass WeChat { // 微信支付请求 static String httpsRequest(StringrequestUrl, String requestMethod, String outputStr) { try { URL url = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(GET/POST) conn.setRequestMethod(requestMethod); conn.setRequestProperty("content-type","application/x-www-form-urlencoded"); // 当outputStr不为null时向输出流写数据 if (null != outputStr) { OutputStream outputStream =conn.getOutputStream(); // 注意编码格式 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 从输入流读取返回内容 InputStream inputStream =conn.getInputStream(); InputStreamReader inputStreamReader= new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = newBufferedReader(inputStreamReader); String str; StringBuffer buffer = newStringBuffer(); while ((str = bufferedReader.readLine())!= null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); conn.disconnect(); return buffer.toString(); } catch (ConnectException ce) { } catch (Exception e) { } return null; }
/** * map转xml格式字符串 */ static Stringmap2XmlString(SortedMap<String, String> params) { String xmlResult;
StringBuffer sb = new StringBuffer(); sb.append("<xml>"); for (String key : params.keySet()) { String value ="<![CDATA[" + params.get(key) + "]]>"; sb.append("<" + key +">" + value + "</" + key + ">"); } sb.append("</xml>"); xmlResult = sb.toString(); return xmlResult; }
/** * 将xml字符串转换成map */ static HashMap<String, String>readXmlString2Map(String xml) { HashMap<String,String> map = new HashMap<String, String>(); Document doc; try { doc =DocumentHelper.parseText(xml); // 将字符串转为XML Element rootElt =doc.getRootElement(); // 获取根节点 List<Element> list =rootElt.elements();// 获取根节点下所有节点 for (Element element : list) { // 遍历节点 map.put(element.getName(),element.getText()); // 节点的name为map的key,text为map的value } } catch (DocumentException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return map; } public static String createSign(SortedMap<String,String> params) { StringBuffer sb = new StringBuffer(); Set es = params.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+ "&"); } } //第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->**设置 sb.append("key="+WXPramsContent.key);
String sign = MD5Util.MD5Encode(sb.toString(),"utf-8") .toUpperCase();//MD5加密
return sign; } static class MD5Util { private static StringbyteArrayToHexString(byte[] b) { StringBuffer resultSb = newStringBuffer(); for (int i = 0; i < b.length;i++) resultSb.append(byteToHexString(b[i]));
return resultSb.toString(); }
private static StringbyteToHexString(byte b) { int n = b; if (n < 0) n += 256; int d1 = n / 16; int d2 = n % 16; return hexDigits[d1] +hexDigits[d2]; }
static String MD5Encode(String origin,String charsetname) { String resultString = null; try { resultString = newString(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= new String[]{"0", "1", "2", "3","4", "5","6", "7", "8","9", "a", "b", "c", "d","e", "f"}; }
public static boolean isTenpaySign(StringcharacterEncoding, SortedMap<Object, Object> packageParams, StringAPI_KEY) { StringBuffer sb = newStringBuffer(); 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(!"sign".equals(k)&& null != v && !"".equals(v)) { sb.append(k + "=" + v+ "&"); } }
sb.append("key=" +API_KEY);
//算出摘要 String mysign =MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); String tenpaySign =((String)packageParams.get("sign")).toLowerCase();
//System.out.println(tenpaySign +" " + mysign); return tenpaySign.equals(mysign); }
} 3) 订单支付完成回调更新订单状态
public void PayNotifyAction(HttpServletRequest request,HttpServletResponseresponse) throws Exception{ System.err.println("已进入微信支付回调接口-----订单支付完成回调更新订单状态"); //读取参数 InputStream inputStream ; StringBuffer sb = new StringBuffer(); inputStream= request.getInputStream(); String s ; BufferedReader in = new BufferedReader(newInputStreamReader(inputStream, "UTF-8")); while((s = in.readLine()) != null){ sb.append(s); } in.close(); inputStream.close(); //解析xml成map Map<String, String> map = new HashMap<String,String>(); map= XMLUtil.doXMLParse(sb.toString()); System.err.println("map:" +map); //过滤空 设置TreeMap SortedMap<Object,Object> packageParams = newTreeMap<Object,Object>(); Iteratorit = map.keySet().iterator(); while(it.hasNext()) { String parameter = (String) it.next(); String parameterValue = map.get(parameter);
String v = ""; if(null!= parameterValue) { v = parameterValue.trim(); } packageParams.put(parameter,v); }
// 账号信息 String key = WXPramsContent.key;// key
logger.info(packageParams); //判断签名是否正确 if(WeChat.isTenpaySign("UTF-8",packageParams,key)) { String mch_id = (String)packageParams.get("mch_id"); String openid = (String)packageParams.get("openid"); String is_subscribe = (String)packageParams.get("is_subscribe"); String out_trade_no = (String)packageParams.get("out_trade_no"); String total_fee = (String)packageParams.get("total_fee"); logger.info("mch_id:"+mch_id); logger.info("openid:"+openid); logger.info("is_subscribe:"+is_subscribe); logger.info("out_trade_no:"+out_trade_no); logger.info("total_fee:"+total_fee); String resXml = ""; if("SUCCESS".equals((String)packageParams.get("result_code"))){ //--------------您的业务逻辑处理部分--------------- logger.info("支付成功"); //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>"+ "</xml> "; } } else { logger.info("支付失败,错误信息:" + packageParams.get("err_code")); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml>"; } BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); System.err.println("resXml:" + resXml.getBytes()); } else{ logger.info("通知签名验证失败"); } }
|
请发表评论