手把手教你完成微信公众号支付

微信公众号支付是我接触微信支付最复杂的一个了,当时总共弄了五天才弄好,很惭愧.

1,首先咋们还是先看看图,图看懂了一切都好说

手把手教你完成微信公众号支付

2,整个流程大概弄清楚了,需要做准备工作了

code -------------- 用户点击 充值 需要访问微信服务器 获取 code,然后服务器接收Code,此处特别注意,这个code用来获取openId的重要参数

/**
     * 用户点击充值 获取Code
     * @param request
     * @return
     */
    @RequestMapping(value = "getCode")
    public String getCode(HttpServletRequest request) {
        String code = request.getParameter("code");
        return "redirect:http://localhost:8080/faint-service/static/h5/topup.html?code=" + code;
    }

openId   --------------此参数是  调用同意下单接口  必要参数 

APIKEY ---------  支付秘钥(微信商户平台可查,需要自己设置)

appid -----   商户ID(微信商户平台可查)

body-------   商品名称

mch_id -----     支付商户号(微信商户平台可查)

nonce_str ---------- 随机字符串

/**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0 ; index < nonceChars.length ; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

out_trade_no------------   订单号

spbill_create_ip ------------请求IP

/**
     * 获取用户实际ip
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                //根据网卡取本机配置的IP  
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }
        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  
        if (ipAddress != null && ipAddress.length() > 15) { //"***.***.***.***".length() = 15  
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

total_fee------------ //,字符串类型,获取金额,单位分

trade_type -------------------//支付类型,公众号就是  "JSAPI"

notify_url   ----------------- //此路径是微信服务器调用支付结果带了一大批参数多次请求

 

3,废话不多说,上代码吧

/**
     * 微信公众号充值金币业务逻辑
     * @param request
      * @param code 微信返回的"code"
     * @param rechargeNumber  充值的用户ID
     * @param rechargeId 由 金钱+金币个数构成的字符串
     * @return
     */
    @RequestMapping(value = "goldOrders", method = RequestMethod.GET)
    @ResponseBody
    public Map goldOrders(HttpServletRequest request, String code, Integer rechargeNumber, String rechargeId) {

        try {
            //如果是模拟请求则返回null
            boolean bool = rechargeList.contains(rechargeId);
            if (bool == false) {
                return null;
            }
            //保存充值记录到数据库
          //此处写自己的业务逻辑
            //页面获取openId接口
            String getopenid_url = "https://api.weixin.qq.com/sns/oauth2/access_token";
            String param = "appid=" + WXPayConstants.APPID + "&secret=" + WXPayConstants.APPSECRET + "&code=" + code + "&grant_type=authorization_code";
            //向微信服务器发送get请求获取
            String openIdStr = HttpRequest.sendGet(getopenid_url, param);
            JSONObject json = JSONObject.parseObject(openIdStr);//转成Json格式
            String openId = json.getString("openid");//获取openId
            Integer money = mdRecharge.getRmb() * 100;//获取金额,单位分
            //拼接统一下单地址参数
            Map<String, String> paraMap = new HashMap<String, String>();
            //获取请求ip地址
            String ip = WXPayUtil.getIpAddr(request);
            String bodyName = "MEIDAO_" + mdRecharge.getNumber();
            paraMap.put("appid", WXPayConstants.APPID); //商户ID
            paraMap.put("body", bodyName); //商品名称
            paraMap.put("mch_id", WXPayConstants.MCHID);
            paraMap.put("nonce_str", WXPayUtil.generateNonceStr()); //String 随机字符串
            paraMap.put("openid", openId); //用户请求微信自动生成的ID
            paraMap.put("out_trade_no", mdRecharge.getNumber());//订单号
            paraMap.put("spbill_create_ip", ip);//请求IP
            paraMap.put("total_fee", money.toString()); //加钱
            paraMap.put("trade_type", "JSAPI");//类型
            paraMap.put("notify_url", "https://自己的域名/faint-service/f/weixin/callbackRecharge");// 此路径是微信服务器调用支付结果带了一大批参数多次请求
            String paternerKey = WXPayConstants.APIKEY;
            String sign = WXPayUtil.generateSignature(paraMap, paternerKey);
            paraMap.put("sign", sign);
            String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
            // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
            String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
            System.out.print("\r\n===========支付返回情况 start==========\r\n");
            //System.out.print(xmlStr);
            System.out.print("\r\n===========支付返回情况 end==========\r\n");
            //以下内容是返回前端页面的json数据
            String prepay_id = "";//预支付id
            if (xmlStr.indexOf("SUCCESS") != -1) {
                Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
                prepay_id = (String) map.get("prepay_id");
            }
            Map<String, String> payMap = new HashMap<String, String>();
            payMap.put("appId", WXPayConstants.APPID);
            payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
            payMap.put("nonceStr", WXPayUtil.generateNonceStr());
            payMap.put("signType", "MD5");
            payMap.put("package", "prepay_id=" + prepay_id);
            String paySign = WXPayUtil.generateSignature(payMap, paternerKey);
            payMap.put("paySign", paySign);
            return payMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

/*******************微信支付成功回调

/**
     * 微信支付成功返回"充值记录"结果
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("callbackRecharge")
    public String callbackRecharge(HttpServletRequest request, HttpServletResponse response) {

        InputStream is = null;
        try {
            is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
            String xml = WXPayUtil.inputStream2String(is, "UTF-8");
            Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
            if (notifyMap.get("return_code").equals("SUCCESS")) {
                if (notifyMap.get("result_code").equals("SUCCESS")) {
                    String orderSn = notifyMap.get("out_trade_no"); //商户订单号 
                    String amountpaid = notifyMap.get("total_fee"); //实际支付的订单金额:单位 分
                    BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);//将分转换成元-实际支付金额:元
                    String openid = notifyMap.get("openid"); //如果有需要可以获取
                    //处理自己的业务逻辑
                }
            }
            //告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
            response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

*********************************前端页面的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>充值</title>
    <link rel="stylesheet" href="https://自己的域名/faint-service/static/project/mobile/assets/mui/css/mui.min.css"  type="text/css">
    <link rel="stylesheet" href="https://自己的域名/faint-service/static/project/mobile/css/border.css"  type="text/css">
    <link rel="stylesheet" href="https://自己的域名/faint-service/static/project/mobile/css/reset.css"  type="text/css">
    <link rel="stylesheet" href="https://自己的域名faint-service/static/project/mobile/assets/font_jnyk9xz222/iconfont.css"  type="text/css">
    <link rel="stylesheet" href="https://自己的域名/faint-service/static/project/mobile/css/topup.css"  type="text/css">
    <link rel="stylesheet" href="https://自己的域名/faint-service/static/project/mobile/css/main.css"  type="text/css">
  
    <script src="https://自己的域名/faint-service/static/project/mobile/assets/mui/js/mui.min.js"></script>
    <script src="https://自己的域名/faint-service/static/project/mobile/assets/zepto/zepto.min.js"></script>
    <script src="https://自己的域名/faint-service/static/project/mobile/assets/artTemplate/template-native.js"></script>
</head>
<body>
    <div class="mui-content">
        <!-- 充值账户 -->
        <div  class="account">
            <h1>充值账户</h1>
            <a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx7ddca8845b6e588f&redirect_uri=https://自己的域名/faint-service/f/weixin/findMdRechargeList&response_type=code&scope=snsapi_base#wechat_redirect">充值记录</a>
            <input type="text" class="clear" id="rechargeNumber" placeholder="请输入您的隐隐ID">
            <input type="hidden" id="code" name="code" value="">
        </div>
        <div class="amount">
            <h1>充值金额</h1>
            <div class="grid mui-bar-tab">
                <a href="#" class="mui-tab-item mui-active"  data="6,396">
                    <i><p>396</p><p>金币</p></i>
                    <span>6元</span>
                </a>
                <a href="#" class="mui-tab-item"  data="30,1980">
                    <i><p>1980</p><p>金币</p></i>
                    <span>30元</span>
                </a>
                <a href="#" class="mui-tab-item"  data="60,3960">
                    <i><p>3960</p><p>金币</p></i>
                    <span>60元</span>
                </a>
                <a href="#" class="mui-tab-item"  data="108,7128">
                    <i><p>7128</p><p>金币</p></i>
                    <span>108元</span>
                </a>
                <a href="#" class="mui-tab-item" data="298,19668">
                    <i><p>19668</p><p>金币</p></i>
                    <span>298元</span>
                </a>
                <a href="#" class="mui-tab-item" data="648,42768">
                    <i><p>42768</p><p>金币</p></i>
                    <span>648元</span>
                </a>
            </div>
        </div>
        <!-- 微信支付 -->
        <div class="pay">
            <img src="https://自己的域名/faint-service/static/project/mobile/images/weixin.png" alt="">
            <h1>微信支付</h1>
        </div>
    </div>
    <!-- 底部--支付模块 -->
    <div class="footer" onclick="pay()">
        <h5>总价:</h5>
        <p id="fuzhi"><span>¥</span>6</p>
        <a id="a1">去支付</a>
    </div>
</body>
<script>
</script>

<script type="text/javascript">
    $('.mui-bar-tab').on('click','a',function(){
        var id= $('.mui-active').attr('data');
        var str = id.split(',');
        $('#fuzhi').text(str[0])
    })    
    // 解析url参数 获取code ........?code=""
    function getQueryString(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        var url=decodeURI(decodeURI(window.location.search))
        var r = url.substr(1).match(reg);
        if (r != null) return unescape(r[2]); return null;
    }
    function pay(){
        var anit = $(".footer");
        var rechargeNumber=$('#rechargeNumber').val();
        if(rechargeNumber.toString().length>8){
            alert("请输入正确的隐隐ID");
            return false;
        }
        var rechargeId=$('.mui-active').attr("data")  
        var code=getQueryString("code");
        if(rechargeNumber==""){
            alert("请输入隐隐ID");
            return false;
        }
       
        var verifyIdUrl="https://自己的域名/faint-service/f/weixin/verifyUserNumber?rechargeNumber="+rechargeNumber; 
        if(anit.hasClass("anit")){
            anit.removeClass("anit");
        }else{
            anit.addClass("anit");
            $.get(verifyIdUrl,function(data){
                if(data=="true"){
                    if(code){
                        var url="https://自己的域名/faint-service/f/weixin/goldOrders?code="+code+"&rechargeNumber="+rechargeNumber+"&rechargeId="+rechargeId;
                        
                          $.get(url,function(result) {
                              var appId = result.appId;
                              var    timeStamp = result.timeStamp;
                              var nonceStr = result.nonceStr;
                              var package = result.package;
                              var    signType = result.signType;
                              var    paySign = result.paySign;
                                if (typeof WeixinJSBridge == "undefined") {
                                    if (document.addEventListener) {
                                        document.addEventListener('WeixinJSBridgeReady',onBridgeReady(appId,timeStamp,nonceStr,package,paySign), false);
                                    } else if (document.attachEvent) {
                                        document.attachEvent('WeixinJSBridgeReady',onBridgeReady(appId,timeStamp,nonceStr,package,paySign));
                                        document.attachEvent('onWeixinJSBridgeReady',onBridgeReady(appId,timeStamp,nonceStr,package,paySign));
                                    }
                                } else {
                                    onBridgeReady(appId,timeStamp,nonceStr,package,paySign);
                                }
                        });
                        } else {
                            alert("服务器错误");
                        }
                }else{
                    alert("用户不存在");
                }
            });    
        }
        
    }
        function onBridgeReady(appId,timeStamp,nonceStr,package,paySign){
              WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
                  "appId":appId,     //公众号名称,由商户传入     
                  "timeStamp":timeStamp,         //时间戳,自1970年以来的秒数     
                  "nonceStr":nonceStr, //随机串     
                  "package":package,     
                  "signType":"MD5",         //微信签名方式:     
                  "paySign":paySign //微信签名
               }, 
               function(res){      
                   if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                       //支付成功后跳转的页面
                      location.href="https://自己的域名/faint-service/static/h5/success.html"
                   }else if(res.err_msg == "get_brand_wcpay_request:cancel"){
                       alert("您已取消支付");
                   }else if(res.err_msg == "get_brand_wcpay_request:fail"){
                       alert("支付失败,请稍后再试");
                       WeixinJSBridge.call('closeWindow');
                   } //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
         });   
        }

</script>
</html>

 

如有问题,请指教.有问题也可以给楼主留言