微信支付H5调用支付详解

微信公众号支付H5调用支付详解

最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验。


一、配置公众号微信支付  

   需要我们配置微信公众号支付地址和测试白名单。

  

     比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/

            那此处配置www.xxx.com/shop/pay/


  二、开发流程

     借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=7_4),我们需要开发的为红色标记出的。如下:

    

 

三、向微信服务器端下订单

             调用统一下单接口,这样就能获取微信支付的prepay_id(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1)。

     在调用该接口前有几个字段是H5支付必须填写的openid

    3.1 获取openid

         可以通过网页授权形式(http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)

       在微信中发送如下链接

      

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=要跳转的下订单的url&response_type=code&scope=snsapi_base&state=123#wechat_redirect


   3.2 下订单获取prepay_id

    代码如下,实际上是通过post发送一个xml 文件,获取微信服务器端发送过来的prepay_id。

   

[java] view plain copy
  1. import java.io.ByteArrayInputStream;  
  2. import java.io.IOException;  
  3. import java.io.InputStream;  
  4. import java.io.UnsupportedEncodingException;  
  5. import java.util.Date;  
  6. import java.util.HashMap;  
  7. import java.util.Iterator;  
  8. import java.util.Map;  
  9. import java.util.Map.Entry;  
  10. import java.util.Random;  
  11.   
  12. import javax.servlet.http.HttpServletRequest;  
  13. import javax.servlet.http.HttpServletResponse;  
  14.   
  15. import org.apache.commons.codec.digest.DigestUtils;  
  16. import org.springframework.stereotype.Controller;  
  17. import org.springframework.web.bind.annotation.RequestMapping;  
  18. import org.xmlpull.v1.XmlPullParser;  
  19. import org.xmlpull.v1.XmlPullParserException;  
  20. import org.xmlpull.v1.XmlPullParserFactory;  
  21.   
  22. import com.fasterxml.jackson.databind.JsonNode;  
  23. import com.gson.oauth.Oauth;  
  24. import com.gson.oauth.Pay;  
  25. import com.gson.util.HttpKit;  
  26. import com.sy.util.DatetimeUtil;  
  27. import com.sy.util.JsonUtil;  
  28.   
  29. @Controller  
  30. @RequestMapping("/pay")  
  31. public class WXPayController {  
  32.   
  33.     @RequestMapping(value = "wxprepay.do")  
  34.     public void jspay(HttpServletRequest request, HttpServletResponse response, String callback) throws Exception {  
  35.         // 获取openid  
  36.         String openId = SessionUtil.getAtt(request, "openId");  
  37.         if (openId == null) {  
  38.             openId = getUserOpenId(request);  
  39.         }  
  40.   
  41.         String appid = "wx16691fcb0523c1a4";  
  42.         String paternerKey = "ININGFENG1234567fdfwfdfd1ss234567";  
  43.           
  44.         String out_trade_no = getTradeNo();  
  45.         Map<String, String> paraMap = new HashMap<String, String>();  
  46.         paraMap.put("appid", appid);  
  47.         paraMap.put("attach""测试");  
  48.         paraMap.put("body""测试购买支付");  
  49.         paraMap.put("mch_id""10283271");  
  50.         paraMap.put("nonce_str", create_nonce_str());  
  51.         paraMap.put("openid", openId);  
  52.         paraMap.put("out_trade_no", out_trade_no);  
  53.         paraMap.put("spbill_create_ip", getAddrIp(request));  
  54.         paraMap.put("total_fee""1");  
  55.         paraMap.put("trade_type""JSAPI");  
  56.         paraMap.put("notify_url""http://www.xxx.co/bank/page/wxnotify");  
  57.         String sign = getSign(paraMap, paternerKey);  
  58.         paraMap.put("sign", sign);  
  59.   
  60.         // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder  
  61.         String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
  62.   
  63.         String xml = ArrayToXml(paraMap);  
  64.   
  65.         String xmlStr = HttpKit.post(url, xml);  
  66.   
  67.         // 预付商品id  
  68.         String prepay_id = "";  
  69.   
  70.         if (xmlStr.indexOf("SUCCESS") != -1) {  
  71.             Map<String, String> map = doXMLParse(xmlStr);  
  72.             prepay_id = (String) map.get("prepay_id");  
  73.         }  
  74.   
  75.         Map<String, String> payMap = new HashMap<String, String>();  
  76.         payMap.put("appId", appid);  
  77.         payMap.put("timeStamp", create_timestamp());  
  78.         payMap.put("nonceStr", create_nonce_str());  
  79.         payMap.put("signType""MD5");  
  80.         payMap.put("package""prepay_id=" + prepay_id);  
  81.         String paySign = getSign(payMap, paternerKey);  
  82.           
  83.         payMap.put("pg", prepay_id);  
  84.         payMap.put("paySign", paySign);  
  85.           
  86.           
  87.         WebUtil.response(response, WebUtil.packJsonp(callback, JsonUtil.warpJsonNodeResponse(JsonUtil.objectToJsonNode(payMap)).toString()));  
  88.     }  
  89.   
  90.     /** 
  91.      * map转成xml 
  92.      *  
  93.      * @param arr 
  94.      * @return 
  95.      */  
  96.     public String ArrayToXml(Map<String, String> arr) {  
  97.         String xml = "<xml>";  
  98.   
  99.         Iterator<Entry<String, String>> iter = arr.entrySet().iterator();  
  100.         while (iter.hasNext()) {  
  101.             Entry<String, String> entry = iter.next();  
  102.             String key = entry.getKey();  
  103.             String val = entry.getValue();  
  104.             xml += "<" + key + ">" + val + "</" + key + ">";  
  105.         }  
  106.   
  107.         xml += "</xml>";  
  108.         return xml;  
  109.     }  
  110.   
  111.     // 获取openId  
  112.     private String getUserOpenId(HttpServletRequest request) throws Exception {  
  113.         String code = request.getParameter("code");  
  114.         if (code == null) {  
  115.             String openId = request.getParameter("openId");  
  116.             return openId;  
  117.         }  
  118.         Oauth o = new Oauth();  
  119.         String token = o.getToken(code);  
  120.         JsonNode node = JsonUtil.StringToJsonNode(token);  
  121.         String openId = node.get("openid").asText();  
  122.         return openId;  
  123.     }  
  124.   
  125.     private String create_nonce_str() {  
  126.             String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";  
  127.             String res = "";  
  128.             for (int i = 0; i < 16; i++) {  
  129.                 Random rd = new Random();  
  130.                 res += chars.charAt(rd.nextInt(chars.length() - 1));  
  131.             }  
  132.             return res;  
  133.     }  
  134.       
  135.     private String getAddrIp(HttpServletRequest request){  
  136.         return request.getRemoteAddr();  
  137.     }  
  138.   
  139.     private String create_timestamp() {  
  140.         return Long.toString(System.currentTimeMillis() / 1000);  
  141.     }  
  142.       
  143.     private String getTradeNo(){  
  144.         String timestamp = DatetimeUtil.formatDate(new Date(), DatetimeUtil.DATETIME_PATTERN);  
  145.         return "HZNO" + timestamp;  
  146.     }  
  147.       
  148.     private String getSign(Map<String, String> params, String paternerKey )  
  149.             throws UnsupportedEncodingException {  
  150.         String string1 = Pay.createSign(params, false);  
  151.         String stringSignTemp = string1 + "&key=" + paternerKey;  
  152.         String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();  
  153.         return  signValue;  
  154.     }  
  155.   
  156.     private Map<String, String> doXMLParse(String xml)  
  157.             throws XmlPullParserException, IOException {  
  158.   
  159.         InputStream inputStream = new ByteArrayInputStream(xml.getBytes());  
  160.   
  161.         Map<String, String> map = null;  
  162.   
  163.         XmlPullParser pullParser = XmlPullParserFactory.newInstance()  
  164.                 .newPullParser();  
  165.   
  166.         pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据  
  167.   
  168.         int eventType = pullParser.getEventType();  
  169.   
  170.         while (eventType != XmlPullParser.END_DOCUMENT) {  
  171.             switch (eventType) {  
  172.             case XmlPullParser.START_DOCUMENT:  
  173.                 map = new HashMap<String, String>();  
  174.                 break;  
  175.   
  176.             case XmlPullParser.START_TAG:  
  177.                 String key = pullParser.getName();  
  178.                 if (key.equals("xml"))  
  179.                     break;  
  180.   
  181.                 String value = pullParser.nextText();  
  182.                 map.put(key, value);  
  183.   
  184.                 break;  
  185.   
  186.             case XmlPullParser.END_TAG:  
  187.                 break;  
  188.   
  189.             }  
  190.   
  191.             eventType = pullParser.next();  
  192.   
  193.         }  
  194.   
  195.         return map;  
  196.     }  
  197.   
  198. }  

四、H5支付

      H5支付其实很简单,只需要调用微信内嵌浏览器的js方法就行(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=7_7)

   

[plain] view plain copy
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>  
  3. <%  
  4.     String path = request.getContextPath();  
  5.     String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";  
  6. %>  
  7. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  8. <html>  
  9. <head>  
  10. <meta charset="utf-8" />  
  11. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />  
  12. <meta name="apple-mobile-web-app-capable" content="yes" />  
  13. <meta name="apple-mobile-web-app-status-bar-style" content="black" />  
  14. <meta name="format-detection" content="telephone=no" />  
  15. <title>测试支付</title>  
  16. <link href="../css/css.css?v=1.0" rel="stylesheet" type="text/css">  
  17. </head>  
  18.   
  19. <body>  
  20.     <div class="index_box">  
  21.         <div class="apply_name">微信js支付测试</div>  
  22.           
  23.           
  24.         <div class="branch_con">  
  25.             <ul>  
  26.                 <li><span class="name">测试支付信息</span></li>  
  27.             </ul>  
  28.             <p class="cz_btn"><a href="javascript:pay();" class="btn_1">立即支付</a></p>  
  29.         </div>  
  30.     </div>  
  31.   
  32.     <script type="text/javascript" src="../js/zepto.min.js"></script>  
  33.     <script type="text/javascript" src="../js/common.js"></script>  
  34.     <script type="text/javascript">  
  35.        
  36.     var appId = urlparameter("appId");  
  37.     var timeStamp = urlparameter("timeStamp");  
  38.     var nonceStr = urlparameter("nonceStr");  
  39.     var pg = urlparameter("pg");  
  40.     var signType = urlparameter("signType");  
  41.     var paySign = urlparameter("paySign");  
  42.       
  43.       
  44.       function onBridgeReady(){  
  45.            
  46.            WeixinJSBridge.invoke(  
  47.                'getBrandWCPayRequest', {  
  48.                    "appId" : appId,     //公众号名称,由商户传入       
  49.                    "timeStamp": timeStamp,         //时间戳,自1970年以来的秒数       
  50.                    "nonceStr" : nonceStr, //随机串       
  51.                    "package" : "prepay_id=" + pg,       
  52.                    "signType" : signType,         //微信签名方式:       
  53.                    "paySign" : paySign    //微信签名   
  54.                },  
  55.                  
  56.                function(res){       
  57.                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {  
  58.                          
  59.                        alert("支付成功");  
  60.                    }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。   
  61.                }  
  62.            );   
  63.         }  
  64.         
  65.         
  66.         function pay(){  
  67.               
  68.             if (typeof WeixinJSBridge == "undefined"){  
  69.                if( document.addEventListener ){  
  70.                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);  
  71.                }else if (document.attachEvent){  
  72.                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady);   
  73.                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);  
  74.                }  
  75.             }else{  
  76.                onBridgeReady();  
  77.             }   
  78.               
  79.         }  
  80.     </script>  
  81. </body>  
  82. </html>  

效果如下

https://blog.csdn.net/u014351782/article/details/52186932

展开阅读全文
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值