微信公众号支付详细步骤(整理)

来源:互联网 发布:2k16mc捏脸数据乔丹 编辑:程序博客网 时间:2024/05/16 12:03

公司做公众号时需要接入微信支付,个人根据网上的demo摸索着完成了公司公众号的支付和退款功能。现也将代码分享出来,希望对需要朋友有帮助。
一.提交支付的toPay.jsp页面代码:

<%    String basePath = request.getScheme() + "://"+ request.getServerName() + request.getContextPath()+ "/";%><html><body>    ....    <div class="zdx3"><button onclick="pay()">共需支付${sumPrice }元&nbsp;&nbsp;确认支付</button></div></body></html> <script>    function pay() {        var url="<%=basePath%>wechat/pay?money=${sumPrice}"; //注意此处的basePath是没有端口号的域名地址。如果包含:80,在提交给微信时有可能会提示 “redirect_uri参数错误” 。        //money为订单需要支付的金额        //state中存放的为商品订单号        var weixinUrl="https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri="+encodeURI(url)+"&response_type=code&scope=snsapi_userinfo&state=${orderId}#wechat_redirect";        window.location.href=encodeURI(weixinUrl);    }</script>

二.后台处理支付功能代码
(包含两部分:
1.处理支付信息,通过微信接口生成订单号,返回支付页面
2.提供一个微信支付完成后的回调接口)
第1部分代码:

/** * 用户提交支付,获取微信支付订单接口 */@RequestMapping(value="/pay")public ModelAndView pay(HttpServletRequest request,HttpServletResponse response){    ModelAndView mv = new ModelAndView();    String GZHID = "wxfd7c065eee11112222";// 微信公众号id    String GZHSecret = "b5b3a627f5d1f8888888888888";// 微信公众号密钥id    String SHHID = "111111111";// 财付通商户号    String SHHKEY = "mmmmmmmmmmmmmmm";// 商户号对应的密钥    /*------1.获取参数信息------- */    //商户订单号    String out_trade_no= request.getParameter("state");     //价格    String money = request.getParameter("money");    //金额转化为分为单位    String finalmoney = WeChat.getMoney(money);    //获取用户的code    String code = request.getParameter("code");    /*------2.根据code获取微信用户的openId和access_token------- */    //注: 如果后台程序之前已经得到了用户的openId 可以不需要这一步,直接从存放openId的位置或session中获取就可以。    //toPay.jsp页面中提交的url路径也就不需要再经过微信重定向。写成:http://localhost:8080/项目名/wechat/pay?money=${sumPrice}&state=${orderId}    String openid=null;    try {        List<Object> list = accessToken(code);        openid=list.get(1).toString();    } catch (IOException e) {        logger.error("根据code获取微信用户的openId出现错误", e);        mv.setViewName("error");        return mv;    }    /*------3.生成预支付订单需要的的package数据------- */    //随机数     String nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());    //订单生成的机器 IP    String spbill_create_ip = request.getRemoteAddr();    //交易类型 :jsapi代表微信公众号支付    String trade_type = "JSAPI";    //这里notify_url是 微信处理完支付后的回调的应用系统接口url。    String notify_url ="http://69a6a38e.ngrok.natapp.cn/heyi-console/wechat/weixinNotify";    SortedMap<String, String> packageParams = new TreeMap<String, String>();    packageParams.put("appid",  GZHID);      packageParams.put("mch_id",  SHHID);      packageParams.put("nonce_str", nonce_str);      packageParams.put("body", "费用");      packageParams.put("out_trade_no", out_trade_no);      packageParams.put("total_fee", finalmoney);      packageParams.put("spbill_create_ip", spbill_create_ip);      packageParams.put("notify_url", notify_url);      packageParams.put("trade_type", trade_type);     packageParams.put("openid", openid);     /*------4.根据package数据生成预支付订单号的签名sign------- */    RequestHandler reqHandler = new RequestHandler(request, response);    reqHandler.init( GZHID,  GZHSecret,  SHHKEY);    String sign = reqHandler.createSign(packageParams);    /*------5.生成需要提交给统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 的xml数据-------*/    String xml="<xml>"+            "<appid>"+ GZHID+"</appid>"+            "<mch_id>"+ SHHID+"</mch_id>"+            "<nonce_str>"+nonce_str+"</nonce_str>"+            "<sign>"+sign+"</sign>"+            "<body><![CDATA["+"费用"+"]]></body>"+            "<out_trade_no>"+out_trade_no+"</out_trade_no>"+            "<total_fee>"+finalmoney+"</total_fee>"+            "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+            "<notify_url>"+notify_url+"</notify_url>"+            "<trade_type>"+trade_type+"</trade_type>"+            "<openid>"+openid+"</openid>"+            "</xml>";    /*------6.调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 生产预支付订单----------*/    String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";    String prepay_id="";    try {        prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);        if(prepay_id.equals("")){            mv.addObject("ErrorMsg", "支付错误");            mv.setViewName("error");            return mv;        }    } catch (Exception e) {        logger.error("统一支付接口获取预支付订单出错", e);        mv.setViewName("error");        return mv;    }    /*将prepay_id存到库中*/    PageData p = new PageData();    p.put("shopId", out_trade_no);    p.put("prePayId", prepay_id);    activityService.updatePrePayId(p);    /*------7.将预支付订单的id和其他信息生成签名并一起返回到jsp页面 ------- */    nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());    SortedMap<String, String> finalpackage = new TreeMap<String, String>();    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);    String packages = "prepay_id="+prepay_id;    finalpackage.put("appId",  GZHID);      finalpackage.put("timeStamp", timestamp);      finalpackage.put("nonceStr", nonce_str);      finalpackage.put("package", packages);      finalpackage.put("signType", "MD5");    String finalsign = reqHandler.createSign(finalpackage);    mv.addObject("appid",  GZHID);    mv.addObject("timeStamp", timestamp);    mv.addObject("nonceStr", nonce_str);    mv.addObject("packageValue", packages);    mv.addObject("paySign", finalsign);    mv.addObject("success","ok");    mv.setViewName("wechat/pay");   return mv;}

第2部分代码:

/** * 提交支付后的微信异步返回接口 */@RequestMapping(value="/weixinNotify")public void weixinNotify(HttpServletRequest request, HttpServletResponse response){    String out_trade_no=null;    String return_code =null;    try {        InputStream inStream = request.getInputStream();        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();        byte[] buffer = new byte[1024];        int len = 0;        while ((len = inStream.read(buffer)) != -1) {            outSteam.write(buffer, 0, len);        }        outSteam.close();        inStream.close();        String resultStr  = new String(outSteam.toByteArray(),"utf-8");        logger.info("支付成功的回调:"+resultStr);        Map<String, Object> resultMap = parseXmlToList(resultStr);        String result_code = (String) resultMap.get("result_code");        String is_subscribe = (String) resultMap.get("is_subscribe");        String transaction_id = (String) resultMap.get("transaction_id");        String sign = (String) resultMap.get("sign");        String time_end = (String) resultMap.get("time_end");        String bank_type = (String) resultMap.get("bank_type");        out_trade_no = (String) resultMap.get("out_trade_no");        return_code = (String) resultMap.get("return_code");        request.setAttribute("out_trade_no", out_trade_no);        //通知微信.异步确认成功.必写.不然微信会一直通知后台.八次之后就认为交易失败了.        response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));    }  catch (Exception e) {        logger.error("微信回调接口出现错误:",e);        try {            response.getWriter().write(RequestHandler.setXML("FAIL", "error"));        } catch (IOException e1) {            e1.printStackTrace();        }    }     if(return_code.equals("SUCCESS")){        //支付成功的业务逻辑    }else{        //支付失败的业务逻辑    }}

三.微信app中具体支付的jsp页面

<html><head><script src="js/jquery-1.8.2.min.js" type="text/javascript"></script></head><body onload="javascript:pay();">    <script type="text/javascript">        function pay(){            if (typeof WeixinJSBridge == "undefined"){               if( document.addEventListener ){                   document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);               }else if (document.attachEvent){                   document.attachEvent('WeixinJSBridgeReady', onBridgeReady);                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);               }            }else{               onBridgeReady();            }               }        function onBridgeReady(){           WeixinJSBridge.invoke(               'getBrandWCPayRequest', {                   "appId" : "${appid}",     //公众号名称,由商户传入                        "timeStamp": "${timeStamp}",         //时间戳,自1970年以来的秒数                        "nonceStr" : "${nonceStr}", //随机串                        "package" : "${packageValue}",                        "signType" : "MD5",         //微信签名方式:                        "paySign" : "${paySign}"    //微信签名                },function(res){                if(res.err_msg == "get_brand_wcpay_request:ok"){                      alert("微信支付成功!");                }else if(res.err_msg == "get_brand_wcpay_request:cancel"){                      alert("用户取消支付!");                }else{                     alert("支付失败!");                }              });         }    </script></body></html>

其他需要用到的相关类和方法:

金额 元转分:

      /**         * 元转换成分         * @param money         * @return         */        public static String getMoney(String amount) {            if(amount==null){                return "";            }            // 金额转化为分为单位            String currency =  amount.replaceAll("\\$|\\¥|\\,", "");  //处理包含, ¥ 或者$的金额              int index = currency.indexOf(".");              int length = currency.length();              Long amLong = 0l;              if(index == -1){                  amLong = Long.valueOf(currency+"00");              }else if(length - index >= 3){                  amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));              }else if(length - index == 2){                  amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);              }else{                  amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");              }              return amLong.toString();         }

通过微信用户code获取用户的openId:

    /**     * 通过微信用户的code换取网页授权access_token     * @return     * @throws IOException     * @throws     */    public List<Object> accessToken(String code) throws IOException {        List<Object> list = new ArrayList<Object>();        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="                + WeChat.HYGZHID + "&secret=" + WeChat.HYGZHSecret+ "&code=" + code + "&grant_type=authorization_code";        HttpClient client = new DefaultHttpClient();        HttpPost post = new HttpPost(url);        HttpResponse res = client.execute(post);        if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {            HttpEntity entity = res.getEntity();            String str = org.apache.http.util.EntityUtils.toString(entity, "utf-8");            ObjectMapper mapper=new com.fasterxml.jackson.databind.ObjectMapper.ObjectMapper();            Map<String,Object> jsonOb=mapper.readValue(str, Map.class);            list.add(jsonOb.get("access_token"));            list.add(jsonOb.get("openid"));        }        return list;    }

MD5提取摘要:

/** * MD5加密 */public class MD5 {    private MD5() {}    /**     * 对传入的数据提取摘要     * @param buffer     * @return     */    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;        }    }}

解析微信回调的xml数据:

    /**     * description: 解析微信通知xml     *      * @param xml     * @return     * @author ex_yangxiaoyi     * @see     */    @SuppressWarnings({ "unused", "rawtypes", "unchecked" })    private static Map parseXmlToList(String xml) {        Map retMap = new HashMap();        try {            StringReader read = new StringReader(xml);            // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入            InputSource source = new InputSource(read);            // 创建一个新的SAXBuilder            SAXBuilder sb = new org.jdom.input.SAXBuilder.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;    }

java文件和需要用到的工具类,我都放到csdn的下载中了。
地址:http://download.csdn.net/detail/aofavx/9606697。
如果有不对或者少文件的地方,请留言。我给大家补正。

3 0
原创粉丝点击