【java web spring mvc】服务端 微信支付+微信异步通知

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

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


之前遇到的一些问题:
预支付id获取失败,签名失败,您没有JSAPI支付权
预支付id获取失败的原因是: 交易类型这是成默认APP ,一些 随机数位数 都要跟api 对应上,加密的时候api的那些字段都要排序好按照(a-b),获取的时候 需要传递两个参数 (统一下单接口地址,拼接成的xml)。
签名失败的原因是:预支付id获取失败,加密的时候排序的顺序,加密用MD5 32位转换大写!
您没有JSAPI支付权: 商户的一些id 一些号 都要对应上 
以上就是大致的错误!  现在上代码 !
首先 这个微信支付 官网的demo 是有bug的 研究了好几天  吸取了一些大神的指点才成功,还有csdn一些人发的代码都不全太坑,资源还少,今天我就整合一下,
把我的一些心得分享给大家 。



实体层代码

[java]  view plain  copy
  1. package com.model;  
  2.   
  3.   
  4.   
  5.   
  6. /** 
  7.  * 微信支付实体 
  8.  * @author 裴广庭 
  9.  * 
  10.  */  
  11. public class WxPay {  
  12.   
  13.   
  14.     private String orderId;//订单号  
  15.     private String totalFee;//金额  
  16.     //private String spbillCreateIp;//订单生成的机器 IP  
  17.     private String notifyUrl;//这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等  
  18.     private String body;// 商品描述根据情况修改  
  19.     private String openId;//微信用户对一个公众号唯一  
  20.       
  21.       
  22.       
  23.     public String getOrderId() {  
  24.         return orderId;  
  25.     }  
  26.     public void setOrderId(String orderId) {  
  27.         this.orderId = orderId;  
  28.     }  
  29.     public String getTotalFee() {  
  30.         return totalFee;  
  31.     }  
  32.     public void setTotalFee(String totalFee) {  
  33.         this.totalFee = totalFee;  
  34.     }  
  35. //  public String getSpbillCreateIp() {  
  36. //      return spbillCreateIp;  
  37. //  }  
  38. //  public void setSpbillCreateIp(String spbillCreateIp) {  
  39. //      this.spbillCreateIp = spbillCreateIp;  
  40. //  }  
  41.     public String getNotifyUrl() {  
  42.         return notifyUrl;  
  43.     }  
  44.     public void setNotifyUrl(String notifyUrl) {  
  45.         this.notifyUrl = notifyUrl;  
  46.     }  
  47.     public String getBody() {  
  48.         return body;  
  49.     }  
  50.     public void setBody(String body) {  
  51.         this.body = body;  
  52.     }  
  53.     public String getOpenId() {  
  54.         return openId;  
  55.     }  
  56.     public void setOpenId(String openId) {  
  57.         this.openId = openId;  
  58.     }  
  59. }  


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


[java]  view plain  copy
  1. package com.util.weixin;  
  2.   
  3. public class WeixinPayConstants {  
  4.     //微信支付商户开通后 微信会提供appid和appsecret和商户号partner  
  5.     public static final String appid = "****";//在微信开发平台登记的app应用  
  6.     public static final String appsecret = "****";  
  7.     public static final String partner = "****";//商户号  
  8.     //这个参数partnerkey是在商户后台配置的一个32位的key,微信商户平台-账户设置-安全设置-api安全  
  9.     public static final String partnerkey = "****";  
  10.     public static final String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
  11.     //openId 是微信用户针对公众号的标识,授权的部分这里不解释  
  12.     public static final String openId = "";  
  13.     //微信支付成功后通知地址 必须要求80端口并且地址不能带参数  
  14.     public static final String notifyurl = "http://**.**.**.**:8080/zhihuishe/weixin/notify";     
  15. }  




后台请求入口
[java]  view plain  copy
  1.     // 商户相关资料  
  2.     private static String appid = WeixinPayConstants.appid;  
  3.     private static String appsecret = WeixinPayConstants.appsecret;  
  4.     private static String partner = WeixinPayConstants.partner;  
  5.     private static String partnerkey = WeixinPayConstants.partnerkey;  
  6.   
  7.   
  8.     private static String notifyurl = WeixinPayConstants.notifyurl;  
  9. @RequestMapping(value = "/wxPay", method = RequestMethod.GET)  
  10.     public void wxPay(HttpServletRequest request, HttpSession session,  
  11.             HttpServletResponse response) throws IOException {  
  12.         Tool tool = new Tool();  
  13.         String totalFee = request.getParameter("totalFee");  
  14.         String body = request.getParameter("body");  
  15.         WxPay tpWxPay = new WxPay();  
  16.         tpWxPay.setTotalFee(totalFee);  
  17.         tpWxPay.setBody(body);  
  18.         tpWxPay.setOrderId(tool.orderNo());  
  19.         Object obj = getPackage(request,response, tpWxPay);  
  20.         JSONArray json = JSONArray.fromObject(obj);  
  21.         response.setCharacterEncoding(Constants.ENCODING_UTF8);  
  22.         response.getWriter().print(json.toString());  
  23.     }  


getPackage方法  加密,生成签名,请求手机端,吊起微信支付!
[java]  view plain  copy
  1. /** 
  2.      * 获取请求预支付id报文 
  3.      * @return 
  4.      * @throws IOException 
  5.      */  
  6.     public static Object getPackage(HttpServletRequest request,HttpServletResponse response,WxPay tpWxPay)  
  7.             throws IOException {  
  8.         JSONObject retMsgJson = new JSONObject();  
  9.         String openId = WeixinPayConstants.openId;  
  10.         // 订单号  
  11.         String orderId = tpWxPay.getOrderId();  
  12.         // 附加数据 原样返回  
  13.         String attach = "";  
  14.         // 总金额以分为单位,不带小数点  
  15.         String totalFee = getMoney(tpWxPay.getTotalFee());  
  16.         // 订单生成的机器 IP  
  17.         //String spbill_create_ip = tpWxPay.getSpbillCreateIp();  
  18.         // 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。  
  19.         String notify_url = notifyurl;  
  20.         //交易类型  
  21.         String trade_type = "APP";  
  22.   
  23.         // ---必须参数  
  24.         // 商户号  
  25.         String mch_id = partner;  
  26.         // 随机字符串  
  27.         String nonce_str = Tool.getRandom();  
  28.         // 商品描述根据情况修改  
  29.         String body = tpWxPay.getBody();  
  30.         // 商户订单号  
  31.         String out_trade_no = orderId;  
  32.   
  33.         SortedMap<String, String> packageParams = new TreeMap<String, String>();  
  34.         packageParams.put("appid", appid);//应用ID   ---微信开放平台审核通过的应用APPID  
  35.         packageParams.put("attach", attach);//附加数      ---附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据  
  36.         packageParams.put("body", body);//商品描述  
  37.         packageParams.put("mch_id", mch_id);//商户号  
  38.         packageParams.put("nonce_str", nonce_str);//随机字符串  
  39.         packageParams.put("notify_url", notify_url);//通知地址  ---微信给发的回调地址,要放在公网  
  40.         packageParams.put("openid", openId);////用户标识  
  41.         packageParams.put("out_trade_no", out_trade_no);//商户订单号  
  42.         //packageParams.put("spbill_create_ip", spbill_create_ip);//手机端ip  
  43.         packageParams.put("total_fee", totalFee);//总金额  
  44.         packageParams.put("trade_type", trade_type);//交易类型  
  45.   
  46.         RequestHandler reqHandler = new RequestHandler(request, response);  
  47.         reqHandler.init(appid, appsecret, partnerkey);  
  48.         //MD5加密  
  49.         String sign = reqHandler.createSign(packageParams);  
  50.         //拼接成xml 形式 生成预支付id---prepay_id  
  51.         String xml = "<xml>" + "<appid><![CDATA[" + appid + "]]></appid>"  
  52.                 + "<attach><![CDATA[" + attach + "]]></attach>"  
  53.                 + "<body><![CDATA[" + body + "]]></body>"  
  54.                 + "<mch_id><![CDATA[" +mch_id + "]]></mch_id>"  
  55.                 + "<nonce_str><![CDATA[" + nonce_str + "]]></nonce_str>"  
  56.                 + "<notify_url><![CDATA[" + notify_url + "]]></notify_url>"  
  57.                 + "<out_trade_no><![CDATA[" + out_trade_no + "]]></out_trade_no>"  
  58.                 //+ "<spbill_create_ip><![CDATA[" + spbill_create_ip + "]]></spbill_create_ip>"  
  59.                 + "<total_fee><![CDATA[" + totalFee + "]]></total_fee>"  
  60.                 + "<trade_type><![CDATA[" + trade_type + "]]></trade_type>"  
  61.                 + "<sign><![CDATA[" + sign + "]]></sign>" + "</xml>";  
  62.   
  63.         String prepay_id = "";  
  64.         //统一下单接口地址  
  65.         String createOrderURL = WeixinPayConstants.createOrderURL;  
  66.         //获取预支付id  
  67.         prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);  
  68.   
  69.         System.out.println("获取到的预支付ID:" + prepay_id);  
  70.   
  71.         // 获取到prepayid后对以下字段进行签名最终发送给app    
  72.         SortedMap<String, String> finalpackage = new TreeMap<String, String>();  
  73.         String timestamp = Sha1Util.getTimeStamp();  
  74.         finalpackage.put("appid", appid);  
  75.         finalpackage.put("timestamp", timestamp);  
  76.         finalpackage.put("noncestr", nonce_str);  
  77.         finalpackage.put("package""Sign=WXPay");  
  78.         finalpackage.put("partnerid", mch_id);  
  79.         finalpackage.put("prepayid", prepay_id);  
  80.         //MD5签名  
  81.         String finalsign = reqHandler.createSign(finalpackage);  
  82.         System.out.println("签名" + finalsign);  
  83.         //打印方便看  
  84.         String finaPackage = "appid=" + appid + "&partnerid=" + mch_id  
  85.                 + "&prepayid=" + prepay_id + "&package=" + "Sign=WXPay"  
  86.                 + "&noncestr=" + nonce_str + "×tamp=" + timestamp  
  87.                 + "&sign=" + finalsign;  
  88.         System.out.println("V3 jsApi package:" + finaPackage);  
  89.         //最后发给发给手机端  
  90.         retMsgJson.put("msg""ok");  
  91.         retMsgJson.put("appid", appid);  
  92.         retMsgJson.put("prepayid", prepay_id);  
  93.         retMsgJson.put("partnerid", mch_id);  
  94.         retMsgJson.put("package""Sign=WXPay");  
  95.         retMsgJson.put("noncestr", nonce_str);  
  96.         retMsgJson.put("timestamp", timestamp);  
  97.         retMsgJson.put("sign", finalsign);  
  98.         retMsgJson.put("sendUrl", notify_url);  
  99.         return retMsgJson;  
  100.     }  

以上是 微信支付  , 支付完成后 微信会回调一些服务器 首先这里 项目一定要放在公网上面 因为 方便 微信访问! 下面是回调代码!
方便在服务器上排除错 我用最笨的方法 就是加打印 都打印到日志上了。。  shell 没有研究明白
在声明一下 !! 这个回调地址 必须放在公网上 言外之意 你想测试项目 必须把项目放在公网上 注意 端口号必须是8080!!!!!!!!!!!
public static final String notifyurl = "http://123.**.**.**:8080/zhihuishe/weixin/notify";


微信异步通知

[java]  view plain  copy
  1. // 微信异步通知  
  2.     @RequestMapping(value = "/notify")  
  3.     @ResponseBody  
  4.     public String notify(HttpServletRequest request, HttpServletResponse response)  
  5.             throws Exception {  
  6.         String result;//返回给微信的处理结果  
  7.         String inputLine;  
  8.         String notityXml = "";  
  9.         request.setCharacterEncoding("UTF-8");  
  10.         response.setCharacterEncoding("UTF-8");  
  11.         response.setContentType("text/html;charset=UTF-8");  
  12.         response.setHeader("Access-Control-Allow-Origin""*");  
  13.         //微信给返回的东西  
  14.         try {  
  15.             while ((inputLine = request.getReader().readLine()) != null) {  
  16.                 notityXml += inputLine;  
  17.             }  
  18.             request.getReader().close();  
  19.         } catch (Exception e) {  
  20.             e.printStackTrace();  
  21.             result = setXml("fail","xml获取失败");  
  22.         }  
  23.         if (StringUtils.isEmpty(notityXml)) {  
  24.             result = setXml("fail","xml为空");  
  25.         }  
  26.         Map map = new GetWxOrderno().doXMLParse(notityXml);  
  27.         // 解析各种数据  
  28.         String appid = (String) map.get("appid");//应用ID  
  29.         String attach = (String) map.get("attach");//商家数据包  
  30.         String bank_type = (String) map.get("bank_type");//付款银行  
  31.         String cash_fee = (String) map.get("cash_fee");//现金支付金额  
  32.         String fee_type = (String) map.get("fee_type");//货币种类  
  33.         String is_subscribe = (String) map.get("is_subscribe");//是否关注公众账号  
  34.         String mch_id = (String) map.get("mch_id");//商户号  
  35.         String nonce_str = (String) map.get("nonce_str");//随机字符串  
  36.         String openid = (String) map.get("openid");//用户标识  
  37.         String out_trade_no = (String) map.get("out_trade_no");// 获取商户订单号  
  38.         String result_code = (String) map.get("result_code");// 业务结果  
  39.         String return_code = (String) map.get("return_code");// SUCCESS/FAIL  
  40.         String sign = (String) map.get("sign");// 获取签名  
  41.         String time_end = (String) map.get("time_end");//支付完成时间  
  42.         String total_fee = (String) map.get("total_fee");// 获取订单金额  
  43.         String trade_type = (String) map.get("trade_type");//交易类型  
  44.         String transaction_id = (String) map.get("transaction_id");//微信支付订单号  
  45.           
  46.         SortedMap<String, String> parameters = new TreeMap<String, String>();  
  47.         // 数据加密  
  48.         parameters.put("appid", appid);//应用ID  
  49.         parameters.put("attach", attach);//商家数据包  
  50.         parameters.put("bank_type", bank_type);//付款银行  
  51.         parameters.put("cash_fee", cash_fee);//现金支付金额  
  52.         parameters.put("fee_type", fee_type);//货币种类  
  53.         parameters.put("is_subscribe", is_subscribe);//是否关注公众账号  
  54.         parameters.put("mch_id", mch_id);//商户号  
  55.         parameters.put("nonce_str", nonce_str);//随机字符串  
  56.         parameters.put("openid", openid);//用户标识  
  57.         parameters.put("out_trade_no", out_trade_no);// 商户订单号  
  58.         parameters.put("result_code", result_code);// 业务结果  
  59.         parameters.put("return_code", return_code);// SUCCESS/FAIL  
  60.         parameters.put("time_end", time_end);// 支付完成时间  
  61.         parameters.put("total_fee", total_fee);// 获取订单金额  
  62.         parameters.put("trade_type", trade_type);//交易类型  
  63.         parameters.put("transaction_id", trade_type);//微信支付订单号  
  64.         //加密前验证notify支付订单网关---https://gw.tenpay.com/gateway/simpleverifynotifyid.xml  
  65.         RequestHandler reqHandler = new RequestHandler(request, response);  
  66.         reqHandler.init(appid, appsecret, partnerkey);  
  67.         //MD5加密  
  68.         String endsign = reqHandler.createSign(parameters);  
  69.           
  70.           
  71.         System.out.println("**************************************************************************************************");  
  72.         System.out.println(appid+"-------------------应用ID");  
  73.         System.out.println(attach+"-------------------商家数据包");  
  74.         System.out.println(bank_type+"-------------------付款银行");  
  75.         System.out.println(cash_fee+"-------------------现金支付金额");  
  76.         System.out.println(fee_type+"-------------------货币种类");  
  77.         System.out.println(is_subscribe+"-------------------是否关注公众账号");  
  78.         System.out.println(mch_id+"-------------------商户号");  
  79.         System.out.println(nonce_str+"-------------------随机字符串");  
  80.         System.out.println(openid+"-------------------用户标识");  
  81.         System.out.println(out_trade_no+"-------------------获取商户订单号");  
  82.         System.out.println(result_code+"-------------------业务结果");  
  83.         System.out.println(return_code+"------------------- SUCCESS/FAIL");  
  84.         System.out.println(sign+"-------------------获取签名-微信回调的签名");  
  85.         System.out.println(time_end+"-------------------支付完成时间");  
  86.         System.out.println(total_fee+"-------------------获取订单金额");  
  87.         System.out.println(trade_type+"-------------------交易类型");  
  88.         System.out.println(transaction_id+"-------------------微信支付订单号");  
  89.         System.out.println(endsign+"-------------------第二次加密sign");  
  90.         System.out.println("**************************************************************************************************");  
  91.           
  92.   
  93.         // 验证签名  
  94.         if (sign.equals(endsign)) {  
  95.             result = setXml("SUCCESS""OK");  
  96.         } else {  
  97.             System.err.println("签名不一致!");  
  98.             result = setXml("fail""签名不一致!");  
  99.         }  
  100.         if (!"SUCCESS".equals("SUCCESS")) {  
  101.             System.err.println("微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");  
  102.             result =  setXml("fail""微信返回的交易状态不正确(result_code=" + "SUCCESS" + ")");  
  103.         }  
  104.         //如果成功写入数据库  
  105.         if ("SUCCESS".equals("SUCCESS")) {// 如果微信返回的结果是success,则修改订单状态  
  106.             //判断订单号是否重复  
  107.             List<CapitalTable> userList = cpitalTableService.queryOrder(out_trade_no);  
  108.             if (userList.size() > 0) {  
  109.                 result = setXml("fail""订单号重复");  
  110.             }else{  
  111.                 CapitalTable capitalTable = new CapitalTable();  
  112.                 UserAdmin userAdmin = new UserAdmin();  
  113.                 userAdmin.setId(6);  
  114.                 capitalTable.setCapital(total_fee);//金币  
  115.                 capitalTable.setState("1");//类型:1充值2提问3回答  
  116.                 capitalTable.setDatetime(new Date());//流入时间  
  117.                 capitalTable.setOrderNo(out_trade_no);  
  118.                 capitalTable.setUserAdmin(userAdmin);  
  119.                 cpitalTableService.insertCapital(capitalTable);  
  120.             }  
  121.         }  
  122.         System.out.println("回调成功");  
  123.         System.out.println("----返回给微信的xml:" + result);  
  124.         return result;  
  125.     }  
  126.   
  127.     //通过xml 发给微信消息  
  128.     public static String setXml(String return_code, String return_msg) {  
  129.         SortedMap<String, String> parameters = new TreeMap<String, String>();  
  130.         parameters.put("return_code", return_code);  
  131.         parameters.put("return_msg", return_msg);  
  132.         return "<xml><return_code><![CDATA[" + return_code + "]]>" +   
  133.                 "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";  
  134.     }  

有的需求需要将元转成分

[java]  view plain  copy
  1. /** 
  2.      * 元转换成分 
  3.      * @param money 
  4.      * @return 
  5.      */  
  6.     public static String getMoney(String amount) {  
  7.         if(amount==null){  
  8.             return "";  
  9.         }  
  10.         // 金额转化为分为单位  
  11.         String currency =  amount.replaceAll("\\$|\\¥|\\,""");  //处理包含, ¥ 或者$的金额    
  12.         int index = currency.indexOf(".");    
  13.         int length = currency.length();    
  14.         Long amLong = 0l;    
  15.         if(index == -1){    
  16.             amLong = Long.valueOf(currency+"00");    
  17.         }else if(length - index >= 3){    
  18.             amLong = Long.valueOf((currency.substring(0, index+3)).replace("."""));    
  19.         }else if(length - index == 2){    
  20.             amLong = Long.valueOf((currency.substring(0, index+2)).replace(".""")+0);    
  21.         }else{    
  22.             amLong = Long.valueOf((currency.substring(0, index+1)).replace(".""")+"00");    
  23.         }    
  24.         return amLong.toString();   
  25.     }  


以上就是 微信支付的全过程 需要用到的工具包 我已经发布在csdn了    地址是 http://download.csdn.net/detail/qq_29739821/9702230  

猜你喜欢

转载自blog.csdn.net/yelin042/article/details/80711248