微信支付参考链接:
(1)微信公众平台开发文档:http://mp.weixin.qq.com/wiki/home/index.html
(2)微信支付普通商户接入文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
(3)接口调试工具:http://mp.weixin.qq.com/debug/
(4)开发者问答系统:http://mp.weixin.qq.com/qa/home/index.html
(5)JSSDK实例代码:http://demo.open.weixin.qq.com/jssdk/js/demo.js
(6)商户后台登陆界面:https://pay.weixin.qq.com/index.php/home/login?return_url=%2F
(7)商户平台开发文档:http://pay.weixin.qq.com/wiki/doc/api/index.html
(8)基于H5的微信支付开发详解:http://daimajun.com/web/31.html
(9)在Web应用中接入微信支付的流程:http://www.cnblogs.com/alex1128/p/wxpay.html
获取时间戳:
var
timestamp1 = Date.parse(
new
Date());
var
timestamp2 = (
new
Date()).valueOf();
var
timestamp3 =
new
Date().getTime();
支付宝支付
(1)即时支付:https://b.alipay.com/order/productDetail.htm?productId=2015110218012942
(2)在线文档:https://doc.open.alipay.com/doc2/detail?treeId=62&articleId=103566&docType=1
设定时间格式化函数:
Date.prototype.format = function (format) { var args = { "M+": this.getMonth() + 1, "d+": this.getDate(), "h+": this.getHours(), "m+": this.getMinutes(), "s+": this.getSeconds(), }; if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var i in args) { var n = args[i]; if (new RegExp("(" + i + ")").test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ("00" + n).substr(("" + n).length)); } return format; };
微信支付(统一下单)
思路:
①将appid、mch_id、nonce_str、body、attach、out_trade_no、total_fee、spbill_create_ip、notify_url、trade_type 这些参数以键值对的形式拼接起来用MD5进行第一次签名
②拼接xml:
例如:
<xml>
<appid>wx2421b1c4370ec43b</appid>
<attach>支付测试</attach>
<body>JSAPI支付测试</body>
<mch_id>10000100</mch_id>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
<notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
<out_trade_no>1415659990</out_trade_no>
<spbill_create_ip>14.23.150.211</spbill_create_ip>
<total_fee>1</total_fee>
<trade_type>JSAPI</trade_type>
<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>
,把这个xml 交个 "https://api.mch.weixin.qq.com/pay/unifiedorder" 在微信 生成一个预支付订单号prepay_id
③将 appid、partner、prepay_id、nonce_str、timestamp、partnerkey、key、package 通过键值对的形式拼接,然后MD5加密处理,和第一步加密方式一样进行第二次签名
④将appid、partnerid、prepayid、package、noncestr、timestamp、sign 传给 调起微信支付功能
注:一些用到的方法
1、MD5 将map 拼接成键值对的串,然后进行加密
/** * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 */ public String createSign(SortedMap<String, String> packageParams) { 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=" + this.getKey()); String sign = MD5Util.MD5Encode(sb.toString(), this.charset) .toUpperCase(); return sign; }
2、将xml交给 "https://api.mch.weixin.qq.com/pay/unifiedorder" 解析生成 预支付订单
如果参数提交失败,会在try里的 if 中 返回 开发的时候建议打断点,我是存session ,然后返回错误信息msg
/** *description:获取预支付id *@param urls *@param xmlParam *@return * @author ex_yangxiaoyi * @see */ public static String getPayNo(String url,String xmlParam){ Subject currentUser = SecurityUtils.getSubject(); Session session = currentUser.getSession(); DefaultHttpClient client = new DefaultHttpClient(); client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); HttpPost httpost= HttpClientConnectionManager.getPostMethod(url); String prepay_id = ""; try { httpost.setEntity(new StringEntity(xmlParam, "UTF-8")); HttpResponse response = httpclient.execute(httpost); String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); if(jsonStr.indexOf("FAIL")!=-1){ session.setAttribute("error_msg", jsonStr); return prepay_id; } Map map = doXMLParse(jsonStr); prepay_id = (String) map.get("prepay_id"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return prepay_id; }
public static InputStream String2Inputstream(String str) { return new ByteArrayInputStream(str.getBytes()); }
3、xml解析
/** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map doXMLParse(String strxml) throws Exception { if(null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = String2Inputstream(strxml); 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 = getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; }
/** * 获取子结点的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(getChildrenText(list)); } sb.append(value); sb.append("</" + name + ">"); } } return sb.toString(); }
4、微信回调函数
/** * 微信支付 回调函数 */ @RequestMapping("/notify") @ResponseBody protected void notify(HttpServletRequest request, HttpServletResponse response) throws Exception { PageData pd=new PageData(); logBefore(logger, "微信支付 回调函数"); //把如下代码贴到的你的处理回调的servlet 或者.do 中即可明白回调操作 logger.info("微信支付回调数据开始"); //示例报文 //String xml = "<xml><appid><![CDATA[wxb4dc385f953b356e]]></appid><bank_type><![CDATA[CCB_CREDIT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[Y]]></is_subscribe><mch_id><![CDATA[1228442802]]></mch_id><nonce_str><![CDATA[1002477130]]></nonce_str><openid><![CDATA[o-HREuJzRr3moMvv990VdfnQ8x4k]]></openid><out_trade_no><![CDATA[1000000000051249]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[1269E03E43F2B8C388A414EDAE185CEE]]></sign><time_end><![CDATA[20150324100405]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[1009530574201503240036299496]]></transaction_id></xml>"; String inputLine; String notityXml = ""; String resXml = ""; try { while ((inputLine = request.getReader().readLine()) != null) { notityXml += inputLine; } request.getReader().close(); } catch (Exception e) { e.printStackTrace(); } System.out.println("接收到的报文:" + notityXml); BufferedWriter writer = new BufferedWriter(new FileWriter(new File("c:\ResultXml.txt"),true)); // writer.write(DateUtil.getTime()+notityXml+" "); writer.close(); Map m = parseXmlToList2(notityXml); WxPayResult wpr = new WxPayResult(); wpr.setAppid(m.get("appid").toString()); wpr.setBankType(m.get("bank_type").toString()); wpr.setCashFee(m.get("cash_fee").toString()); wpr.setFeeType(m.get("fee_type").toString()); wpr.setIsSubscribe(m.get("is_subscribe").toString()); wpr.setMchId(m.get("mch_id").toString()); wpr.setNonceStr(m.get("nonce_str").toString()); wpr.setOpenid(m.get("openid").toString()); wpr.setOutTradeNo(m.get("out_trade_no").toString()); wpr.setResultCode(m.get("result_code").toString()); wpr.setReturnCode(m.get("return_code").toString()); wpr.setSign(m.get("sign").toString()); wpr.setTimeEnd(m.get("time_end").toString()); wpr.setTotalFee(m.get("total_fee").toString()); wpr.setTradeType(m.get("trade_type").toString()); wpr.setTransactionId(m.get("transaction_id").toString()); if("SUCCESS".equals(wpr.getResultCode())){ //支付成功 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; //修改订单状态 pd.put("WX_ORDER", wpr.getOutTradeNo()); wxPayService.editStatusByOutId(pd); //保存订单信息 pd.put("WX_ORDER_ID", UuidUtil.get32UUID());//微信订单主键ID pd.put("OPEN_ID", wpr.getOpenid());//用户的OPEN_ID pd.put("MCH_ID", wpr.getMchId());//商户号 pd.put("NONCE_STR", wpr.getNonceStr());//随机字符串 pd.put("SIGN", wpr.getSign());//SIGN pd.put("CASH_FEE", wpr.getCashFee());//现金支付金额 pd.put("TOTAL_FEE", wpr.getTotalFee());//总金额 pd.put("BANK_TYPE", wpr.getBankType());//付款银行 pd.put("TRADE_TYPE", wpr.getTradeType());//交易类型 pd.put("RESULT_CODE", wpr.getResultCode());//业务结果 pd.put("TRANSACTION_ID", wpr.getTotalFee());//微信支付订单号 pd.put("TIME_END", wpr.getTimeEnd());//微信支付完成时间 wxPayService.saveWxOrder(pd); }else{ resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } System.out.println("微信支付回调数据结束"); BufferedOutputStream out = new BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); }
解析微信通知xml
/** * description: 解析微信通知xml * * @param xml * @return * @author ex_yangxiaoyi * @see */ @SuppressWarnings({ "unused", "rawtypes", "unchecked" }) private static Map parseXmlToList2(String xml) { Map retMap = new HashMap(); try { StringReader read = new StringReader(xml); // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入 InputSource source = new InputSource(read); // 创建一个新的SAXBuilder SAXBuilder sb = new SAXBuilder(); // 通过输入源构造一个Document Document doc = (Document) sb.build(source); Element root = doc.getRootElement();// 指向根节点 List<Element> es = root.getChildren(); if (es != null && es.size() != 0) { for (Element element : es) { retMap.put(element.getName(), element.getValue()); } } } catch (Exception e) { e.printStackTrace(); } return retMap; }