您现在的位置:首页 >> 前端 >> 内容

服务端的微信支付+微信异步通知功能实现教程

时间:2018/6/21 11:00:04 点击:

  核心提示:首先 这个微信支付 官网的demo 是有bug的 研究了好几天 吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,把我的一些心得分享给大家 。之前遇到的一些...

首先 这个微信支付 官网的demo 是有bug的 研究了好几天  吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,

把我的一些心得分享给大家 。

之前遇到的一些问题:

预支付id获取失败,签名失败,您没有JSAPI支付权

预支付id获取失败的原因是: 交易类型这是成默认APP ,一些 随机数位数 都要跟api 对应上,加密的时候api的那些字段都要排序好按照(a-b),获取的时候 需要传递两个参数 (统一下单接口地址,拼接成的xml)。

签名失败的原因是:预支付id获取失败,加密的时候排序的顺序,加密用MD5 32位转换大写!

您没有JSAPI支付权: 商户的一些id 一些号 都要对应上 

以上就是大致的错误!  现在上代码 !

首先 这个微信支付 官网的demo 是有bug的 研究了好几天  吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,

把我的一些心得分享给大家 。

实体层代码

[java] view plain copy

package com.model;  

/** 

 * 微信支付实体 

 * @author 裴广庭 

 * 

 */  

public class WxPay {  

    private String orderId;//订单号  

    private String totalFee;//金额  

    //private String spbillCreateIp;//订单生成的机器 IP  

    private String notifyUrl;//这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等  

    private String body;// 商品描述根据情况修改  

    private String openId;//微信用户对一个公众号唯一  

      

      

      

    public String getOrderId() {  

        return orderId;  

    }  

    public void setOrderId(String orderId) {  

        this.orderId = orderId;  

    }  

    public String getTotalFee() {  

        return totalFee;  

    }  

    public void setTotalFee(String totalFee) {  

        this.totalFee = totalFee;  

    }  

//  public String getSpbillCreateIp() {  

//      return spbillCreateIp;  

//  }  

//  public void setSpbillCreateIp(String spbillCreateIp) {  

//      this.spbillCreateIp = spbillCreateIp;  

//  }  

    public String getNotifyUrl() {  

        return notifyUrl;  

    }  

    public void setNotifyUrl(String notifyUrl) {  

        this.notifyUrl = notifyUrl;  

    }  

    public String getBody() {  

        return body;  

    }  

    public void setBody(String body) {  

        this.body = body;  

    }  

    public String getOpenId() {  

        return openId;  

    }  

    public void setOpenId(String openId) {  

        this.openId = openId;  

    }  

}  

单独写的微信商户平台信息的类

[java] view plain copy

package com.util.weixin;  

public class WeixinPayConstants {  

    //微信支付商户开通后 微信会提供appid和appsecret和商户号partner  

    public static final String appid = "****";//在微信开发平台登记的app应用  

    public static final String appsecret = "****";  

    public static final String partner = "****";//商户号  

    //这个参数partnerkey是在商户后台配置的一个32位的key,微信商户平台-账户设置-安全设置-api安全  

    public static final String partnerkey = "****";  

    public static final String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";  

    //openId 是微信用户针对公众号的标识,授权的部分这里不解释  

    public static final String openId = "";  

    //微信支付成功后通知地址 必须要求80端口并且地址不能带参数  

    public static final String notifyurl = "https://**.**.**.**:8080/zhihuishe/weixin/notify";     

}  

后台请求入口

[java] view plain copy

    // 商户相关资料  

    private static String appid = WeixinPayConstants.appid;  

    private static String appsecret = WeixinPayConstants.appsecret;  

    private static String partner = WeixinPayConstants.partner;  

    private static String partnerkey = WeixinPayConstants.partnerkey;  

    private static String notifyurl = WeixinPayConstants.notifyurl;  

@RequestMapping(value = "/wxPay", method = RequestMethod.GET)  

    public void wxPay(HttpServletRequest request, HttpSession session,  

            HttpServletResponse response) throws IOException {  

        Tool tool = new Tool();  

        String totalFee = request.getParameter("totalFee");  

        String body = request.getParameter("body");  

        WxPay tpWxPay = new WxPay();  

        tpWxPay.setTotalFee(totalFee);  

        tpWxPay.setBody(body);  

        tpWxPay.setOrderId(tool.orderNo());  

        Object obj = getPackage(request,response, tpWxPay);  

        JSONArray json = JSONArray.fromObject(obj);  

        response.setCharacterEncoding(Constants.ENCODING_UTF8);  

        response.getWriter().print(json.toString());  

    }  

getPackage方法  加密,生成签名,请求手机端,吊起微信支付!

[java] view plain copy

/** 

     * 获取请求预支付id报文 

     * @return 

     * @throws IOException 

     */  

    public static Object getPackage(HttpServletRequest request,HttpServletResponse response,WxPay tpWxPay)  

            throws IOException {  

        JSONObject retMsgJson = new JSONObject();  

        String openId = WeixinPayConstants.openId;  

        // 订单号  

        String orderId = tpWxPay.getOrderId();  

        // 附加数据 原样返回  

        String attach = "";  

        // 总金额以分为单位,不带小数点  

        String totalFee = getMoney(tpWxPay.getTotalFee());  

        // 订单生成的机器 IP  

        //String spbill_create_ip = tpWxPay.getSpbillCreateIp();  

        // 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。  

        String notify_url = notifyurl;  

        //交易类型  

        String trade_type = "APP";  

        // ---必须参数  

        // 商户号  

        String mch_id = partner;  

        // 随机字符串  

        String nonce_str = Tool.getRandom();  

        // 商品描述根据情况修改  

        String body = tpWxPay.getBody();  

        // 商户订单号  

        String out_trade_no = orderId;  

        SortedMap<String, String> packageParams = new TreeMap<String, String>();  

        packageParams.put("appid", appid);//应用ID   ---微信开放平台审核通过的应用APPID  

        packageParams.put("attach", attach);//附加数      ---附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据  

        packageParams.put("body", body);//商品描述  

        packageParams.put("mch_id", mch_id);//商户号  

        packageParams.put("nonce_str", nonce_str);//随机字符串  

        packageParams.put("notify_url", notify_url);//通知地址  ---微信给发的回调地址,要放在公网  

        packageParams.put("openid", openId);////用户标识  

        packageParams.put("out_trade_no", out_trade_no);//商户订单号  

        //packageParams.put("spbill_create_ip", spbill_create_ip);//手机端ip  

        packageParams.put("total_fee", totalFee);//总金额  

        packageParams.put("trade_type", trade_type);//交易类型  

        RequestHandler reqHandler = new RequestHandler(request, response);  

        reqHandler.init(appid, appsecret, partnerkey);  

        //MD5加密  

        String sign = reqHandler.createSign(packageParams);  

        //拼接成xml 形式 生成预支付id---prepay_id  

        String xml = "<xml>" + "<appid><![CDATA[" + appid + "]]></appid>"  

                + "<attach><![CDATA[" + attach + "]]></attach>"  

                + "<body><![CDATA[" + body + "]]></body>"  

                + "<mch_id><![CDATA[" +mch_id + "]]></mch_id>"  

                + "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>"  

                + "<notify_url><![CDATA[" + notify_url + "]]></notify_url>"  

                + "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>"  

                //+ "<spbill_create_ip><![CDATA[" + spbill_create_ip + "]]></spbill_create_ip>"  

                + "<total_fee><![CDATA[" + totalFee + "]]></total_fee>"  

                + "<trade_type><![CDATA[" + trade_type + "]]></trade_type>"  

                + "<sign><![CDATA[" + sign + "]]></sign>" + "</xml>";  

        String prepay_id = "";  

        //统一下单接口地址  

        String createOrderURL = WeixinPayConstants.createOrderURL;  

        //获取预支付id  

        prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);  

        System.out.println("获取到的预支付ID:" + prepay_id);  

        // 获取到prepayid后对以下字段进行签名最终发送给app    

        SortedMap<String, String> finalpackage = new TreeMap<String, String>();  

        String timestamp = Sha1Util.getTimeStamp();  

        finalpackage.put("appid", appid);  

        finalpackage.put("timestamp", timestamp);  

        finalpackage.put("noncestr", nonce_str);  

        finalpackage.put("package", "Sign=WXPay");  

        finalpackage.put("partnerid", mch_id);  

        finalpackage.put("prepayid", prepay_id);  

        //MD5签名  

        String finalsign = reqHandler.createSign(finalpackage);  

        System.out.println("签名" + finalsign);  

        //打印方便看  

        String finaPackage = "appid=" + appid + "&partnerid=" + mch_id  

                + "&prepayid=" + prepay_id + "&package=" + "Sign=WXPay"  

                + "&noncestr=" + nonce_str + "×tamp=" + timestamp  

                + "&sign=" + finalsign;  

        System.out.println("V3 jsApi package:" + finaPackage);  

        //最后发给发给手机端  

        retMsgJson.put("msg", "ok");  

        retMsgJson.put("appid", appid);  

        retMsgJson.put("prepayid", prepay_id);  

        retMsgJson.put("partnerid", mch_id);  

        retMsgJson.put("package", "Sign=WXPay");  

        retMsgJson.put("noncestr", nonce_str);  

        retMsgJson.put("timestamp", timestamp);  

        retMsgJson.put("sign", finalsign);  

        retMsgJson.put("sendUrl", notify_url);  

        return retMsgJson;  

    }  

以上是 微信支付  , 支付完成后 微信会回调一些服务器 首先这里 项目一定要放在公网上面 因为 方便 微信访问! 下面是回调代码!

方便在服务器上排除错 我用最笨的方法 就是加打印 都打印到日志上了。。  shell 没有研究明白

在声明一下 !! 这个回调地址 必须放在公网上 言外之意 你想测试项目 必须把项目放在公网上 注意 端口号必须是8080!!!!!!!!!!!

public static final String notifyurl = "https://123.**.**.**:8080/zhihuishe/weixin/notify";

微信异步通知

[java] view plain copy

// 微信异步通知  

    @RequestMapping(value = "/notify")  

    @ResponseBody  

    public String notify(HttpServletRequest request, HttpServletResponse response)  

            throws Exception {  

        String result;//返回给微信的处理结果  

        String inputLine;  

        String notityXml = "";  

        request.setCharacterEncoding("UTF-8");  

        response.setCharacterEncoding("UTF-8");  

        response.setContentType("text/html;charset=UTF-8");  

        response.setHeader("Access-Control-Allow-Origin", "*");  

        //微信给返回的东西  

        try {  

            while ((inputLine = request.getReader().readLine()) != null) {  

                notityXml += inputLine;  

            }  

            request.getReader().close();  

        } catch (Exception e) {  

            e.printStackTrace();  

            result = setXml("fail","xml获取失败");  

        }  

        if (StringUtils.isEmpty(notityXml)) {  

            result = setXml("fail","xml为空");  

        }  

        Map map = new GetWxOrderno().doXMLParse(notityXml);  

        // 解析各种数据  

        String appid = (String) map.get("appid");//应用ID  

        String attach = (String) map.get("attach");//商家数据包  

        String bank_type = (String) map.get("bank_type");//付款银行  

        String cash_fee = (String) map.get("cash_fee");//现金支付金额  

        String fee_type = (String) map.get("fee_type");//货币种类  

        String is_subscribe = (String) map.get("is_subscribe");//是否关注公众账号  

        String mch_id = (String) map.get("mch_id");//商户号  

        String nonce_str = (String) map.get("nonce_str");//随机字符串  

        String openid = (String) map.get("openid");//用户标识  

        String out_trade_no = (String) map.get("out_trade_no");// 获取商户订单号  

        String result_code = (String) map.get("result_code");// 业务结果  

        String return_code = (String) map.get("return_code");// SUCCESS/FAIL  

        String sign = (String) map.get("sign");// 获取签名  

        String time_end = (String) map.get("time_end");//支付完成时间  

        String total_fee = (String) map.get("total_fee");// 获取订单金额  

        String trade_type = (String) map.get("trade_type");//交易类型  

        String transaction_id = (String) map.get("transaction_id");//微信支付订单号  

          

        SortedMap<String, String> parameters = new TreeMap<String, String>();  

        // 数据加密  

        parameters.put("appid", appid);//应用ID  

        parameters.put("attach", attach);//商家数据包  

        parameters.put("bank_type", bank_type);//付款银行  

        parameters.put("cash_fee", cash_fee);//现金支付金额  

        parameters.put("fee_type", fee_type);//货币种类  

        parameters.put("is_subscribe", is_subscribe);//是否关注公众账号  

        parameters.put("mch_id", mch_id);//商户号  

        parameters.put("nonce_str", nonce_str);//随机字符串  

        parameters.put("openid", openid);//用户标识  

        parameters.put("out_trade_no", out_trade_no);// 商户订单号  

        parameters.put("result_code", result_code);// 业务结果  

        parameters.put("return_code", return_code);// SUCCESS/FAIL  

        parameters.put("time_end", time_end);// 支付完成时间  

        parameters.put("total_fee", total_fee);// 获取订单金额  

        parameters.put("trade_type", trade_type);//交易类型  

        parameters.put("transaction_id", trade_type);//微信支付订单号  

        //加密前验证notify支付订单网关---https://gw.tenpay.com/gateway/simpleverifynotifyid.xml  

        RequestHandler reqHandler = new RequestHandler(request, response);  

        reqHandler.init(appid, appsecret, partnerkey);  

        //MD5加密  

        String endsign = reqHandler.createSign(parameters);  

          

          

        System.out.println("**************************************************************************************************");  

        System.out.println(appid+"-------------------应用ID");  

        System.out.println(attach+"-------------------商家数据包");  

        System.out.println(bank_type+"-------------------付款银行");  

        System.out.println(cash_fee+"-------------------现金支付金额");  

        System.out.println(fee_type+"-------------------货币种类");  

        System.out.println(is_subscribe+"-------------------是否关注公众账号");  

        System.out.println(mch_id+"-------------------商户号");  

        System.out.println(nonce_str+"-------------------随机字符串");  

        System.out.println(openid+"-------------------用户标识");  

        System.out.println(out_trade_no+"-------------------获取商户订单号");  

        System.out.println(result_code+"-------------------业务结果");  

        System.out.println(return_code+"------------------- SUCCESS/FAIL");  

        System.out.println(sign+"-------------------获取签名-微信回调的签名");  

        System.out.println(time_end+"-------------------支付完成时间");  

        System.out.println(total_fee+"-------------------获取订单金额");  

        System.out.println(trade_type+"-------------------交易类型");  

        System.out.println(transaction_id+"-------------------微信支付订单号");  

        System.out.println(endsign+"-------------------第二次加密sign");  

        System.out.println("**************************************************************************************************");  

          

        // 验证签名  

        if (sign.equals(endsign)) {  

            result = setXml("SUCCESS", "OK");  

        } else {  

            System.err.println("签名不一致!");  

            result = setXml("fail", "签名不一致!");  

        }  

        if (!"SUCCESS".equals("SUCCESS")) {  

            System.err.println("微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");  

            result =  setXml("fail", "微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");  

        }  

        //如果成功写入数据库  

        if ("SUCCESS".equals("SUCCESS")) {// 如果微信返回的结果是success,则修改订单状态  

            //判断订单号是否重复  

            List<CapitalTable> userList = cpitalTableService.queryOrder(out_trade_no);  

            if (userList.size() > 0) {  

                result = setXml("fail", "订单号重复");  

            }else{  

                CapitalTable capitalTable = new CapitalTable();  

                UserAdmin userAdmin = new UserAdmin();  

                userAdmin.setId(6);  

                capitalTable.setCapital(total_fee);//金币  

                capitalTable.setState("1");//类型:1充值2提问3回答  

                capitalTable.setDatetime(new Date());//流入时间  

                capitalTable.setOrderNo(out_trade_no);  

                capitalTable.setUserAdmin(userAdmin);  

                cpitalTableService.insertCapital(capitalTable);  

            }  

        }  

        System.out.println("回调成功");  

        System.out.println("----返回给微信的xml:" + result);  

        return result;  

    }  

    //通过xml 发给微信消息  

    public static String setXml(String return_code, String return_msg) {  

        SortedMap<String, String> parameters = new TreeMap<String, String>();  

        parameters.put("return_code", return_code);  

        parameters.put("return_msg", return_msg);  

        return "<xml><return_code><![CDATA[" + return_code + "]]>" +   

                "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";  

    }  

有的需求需要将元转成分

[java] view plain copy

/** 

     * 元转换成分 

     * @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();   

    }  

以上就是 微信支付的全过程

作者:网络 来源:书写人生