APP微信支付

 

前置准备

微信的东西比支付宝要复杂一点,要先去注册开发者账号,然后一系列巴拉巴拉……,然后得到下面列出的我们开发需要的参数,下面的参数中TOKEN和CERT_PATH是需要退款和设计到其他功能才需要的,如果只做APP支付功能的同学可以忽略。

  • APP_ID : 服务号的应用ID
  • APP_SECRET : 服务号的应用密钥
  • TOKEN : 服务号的配置token
  • MCH_ID : 商户号
  • API_KEY : API密钥
  • SIGN_TYPE : 签名加密方式
  • CERT_PATH : 微信支付证书名称、

支付流程

具体的流程大概就是后台拿到(或生成)自己的订单号后,拿着一堆参数按ASCII码(即abc…)排序后用MD5加密后调用微信的服务器地址拿到一个prepayId,再将prepayId和当前的参数再次排序和加密(二次加密)生成sign后返回前端进行支付,支付完成后,微信的后台会回调我们的后台接口。

Java代码

maven依赖

 1 `<!-- 微信支付依赖 -->
 2 <dependency>
 3     <groupId>org.xmlpull</groupId>
 4     <artifactId>xmlpull</artifactId>
 5     <version>1.1.3.1 </version>
 6 </dependency>
 7 <dependency>
 8     <groupId>net.sf.json-lib</groupId>
 9     <artifactId>json-lib</artifactId>
10     <version>2.3</version>
11     <classifier>jdk15</classifier>
12 </dependency>
13 <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
14 <dependency>
15     <groupId>com.thoughtworks.xstream</groupId>
16     <artifactId>xstream</artifactId>
17     <version>1.4.5</version>
18 </dependency>
19 <!-- https://mvnrepository.com/artifact/com.ning/async-http-client -->
20 <dependency>
21     <groupId>com.ning</groupId>
22     <artifactId>async-http-client</artifactId>
23     <version>1.8.13</version>
24 </dependency>`

 

 

Java代码

 1 @ResponseBody
 2 @RequestMapping(value="/wxpaySign",method=RequestMethod.POST)
 3 public JsonResult getWXPaySign(double totalAmount,String userId,String out_trade_no,String ip) 
 4             throws JDOMException, IOException{
 5         //预备参数
 6         WXPayDTO wxPayDTO = new WXPayDTO();
 7         String subject = "******";
 8         String body = "******";
 9         String nonceStr = setNonceStr();
10         long timeStamp = (long)CommonUtil.getSecondTimestamp(new Date());
11         String packageStr = "Sign=WXPay";
12         String total_fee = String.valueOf(CommonUtil.double100ToInt(totalAmount));
13 
14         SortedMap<String,String> payMap = genOrderData(PayConstants.WX_APP_ID,body,out_trade_no,
15                 nonceStr,packageStr,PayConstants.WX_PARTNER_ID,total_fee,subject,ip);
16 
17         //设置WXPayDTO
18         wxPayDTO.setAppId(PayConstants.WX_APP_ID);
19         //商家id
20         wxPayDTO.setPartnerId(PayConstants.WX_PARTNER_ID);  
21         wxPayDTO.setPrepayId(out_trade_no);     //订单
22         wxPayDTO.setNonceStr(nonceStr); //设置随机串
23         wxPayDTO.setTimeStamp(timeStamp);   //设置时间戳
24         wxPayDTO.setPackageStr(packageStr);
25         wxPayDTO.setSign(payMap.get("sign"));
26         wxPayDTO.setPrepayId(payMap.get("prepayid"));
27         return new JsonResult(Message.M2000,wxPayDTO);
28     }
29 
30 
31 private SortedMap<String, String> genOrderData(String appId, String body, String out_trade_no,
32             String nonceStr, String packageStr, String partnerId,String total_fee,String subject,String ip) 
33                     throws JDOMException, IOException {
34         SortedMap<String, String> paraMap = new TreeMap<String,String>();
35     //按照官方文档的要求,这里参数名ASCII码从小到大排序(字典序);
36         paraMap.put("appid", appId);
37         paraMap.put("body",body);
38         paraMap.put("mch_id",partnerId);        //微信商户账号
39         paraMap.put("nonce_str",nonceStr);  //32位不重复的编号
40         paraMap.put("notify_url", 
41         PayConstants.WX_Notify_Url);    //设置一个回调的地址
42         paraMap.put("out_trade_no", out_trade_no);  //订单号
43         paraMap.put("spbill_create_ip", ip);//前端传回来的ip
44         paraMap.put("total_fee",total_fee);     //设置金额
45         paraMap.put("trade_type","APP");    //方式为APP支付
46         //用上面封装的参数生成sign
47         String sign = PayCommonUtil.createSign("UTF-8", paraMap,PayConstants.WX_API_KEY);
48         //这里的sign用二次签名生成的sign
49         paraMap.put("sign",sign);
50         //统一下单地址
51         //将上面集合内容转成xml
52         String xml = getRequestXML(paraMap);
53         String xmlStr = HttpUtil.postData(PayConstants.WX_Notify_Url,xml);
54         //将返回的xml转换成map
55         Map map = XMLUtil.doXMLParse(xmlStr);
56         //预付商品id
57         String prepay_id = (String) map.get("prepay_id");
58 
59         //这里要对参数进行二次签名
60         SortedMap<String, String> secParaMap = new TreeMap<String,String>();
61         secParaMap.put("appid", appId);
62         secParaMap.put("partnerid",partnerId);
63         secParaMap.put("prepayid", prepay_id);
64         //这里不确定是不是要重新生成一个随机串,再改
65         secParaMap.put("noncestr", nonceStr);
66         secParaMap.put("timestamp", CommonUtil.getTimeStamp());
67         secParaMap.put("package", "Sign=WXPay");
68         String secSign = PayCommonUtil.createSign("UTF-8", secParaMap, PayConstants.WX_API_KEY);
69         secParaMap.put("sign", secSign);
70         secParaMap.put("prepayid", prepay_id);
71 
72         return secParaMap;
73     }

 

 

支付回调 
微信的支付回调是用流形式传输的,所以要先对流形式的数据进行解析再得到我们需要的东西。

 1     @RequestMapping(value = "payNotifyUrl", produces = "application/json;charset=UTF-8")
 2     @ResponseBody
 3     public String payNotifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
 4         //读取参数 
 5 
 6         InputStream inputStream ;  
 7         StringBuffer sb = new StringBuffer();  
 8         inputStream = request.getInputStream();  
 9         String s ;  
10         BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));  
11         while ((s = in.readLine()) != null){  
12             sb.append(s);  
13         }  
14         in.close();  
15         inputStream.close();  
16 
17         //解析xml成map  
18         Map<String, String> m = new HashMap<String, String>();  
19         m = XMLUtil.doXMLParse(sb.toString());  
20 
21         //过滤空 设置 TreeMap  
22         SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();        
23         Iterator it = m.keySet().iterator();  
24         while (it.hasNext()) {  
25             String parameter = (String) it.next();  
26             String parameterValue = m.get(parameter);  
27 
28             String v = "";  
29             if(null != parameterValue) {  
30                 v = parameterValue.trim();  
31             }  
32             packageParams.put(parameter, v);  
33         }  
34 
35         //判断签名是否正确  
36         if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,PayConstants.WX_API_KEY)) {  
37             //------------------------------  
38             //处理业务开始  
39             //------------------------------  
40             String resXml = "";  
41             if("SUCCESS".equals((String)packageParams.get("result_code"))){  
42                 // 这里是支付成功  
43                 //////////执行自己的业务逻辑////////////////  
44                 String mch_id = (String)packageParams.get("mch_id");  
45                 String openid = (String)packageParams.get("openid");  
46                 String is_subscribe = (String)packageParams.get("is_subscribe");  
47                 String out_trade_no = (String)packageParams.get("out_trade_no");  
48 
49                 String total_fee = (String)packageParams.get("total_fee");  
50 
51                 System.out.println("mch_id:"+mch_id);  
52                 System.out.println("openid:"+openid);  
53                 logger.info("is_subscribe:"+is_subscribe);  
54                 logger.info("out_trade_no:"+out_trade_no);  
55                 logger.info("total_fee:"+total_fee);  
56 
57                 //////////执行自己的业务逻辑////////////////  
58 
59                 logger.info("支付成功");  
60                 //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.  
61                 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
62                         + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
63 
64             } else {  
65                 logger.info("支付失败,错误信息:" + packageParams.get("err_code"));  
66                 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
67                         + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";  
68             }  
69             //------------------------------  
70             //处理业务完毕  
71             //------------------------------  
72             BufferedOutputStream out = new BufferedOutputStream(  
73                     response.getOutputStream());  
74             out.write(resXml.getBytes());  
75             out.flush();  
76             out.close();  
77         } else{  
78             logger.info("通知签名验证失败");  
79         }  
80         return "SUCCESS";
81     }

 

posted on 2018-08-27 16:52  wangpeihua  阅读(200)  评论(0编辑  收藏  举报

导航