微信支付之App支付

项目接入微信支付的准备工作:

  1. 注册成为开发者,进行资质认证,这里是需要300元的审核费用的;
  2. 在微信商户平台创建应用,提交等待审核(大致需要5-7个工作日);
  3. 应用审核通过之后,进入应用,开通微信支付,提交审核(大致需要2-3个工作日);
  4. 审核通过之后,微信会给注册的邮箱发送商户号,用户和密码等信息。

接入App支付的业务流程主要如下图所示:

接下来,就描述一下接入项目的详细步骤:

  1. 基础信息配置文件:WeiChartConfig.java
  2. 调用API接口的工具类:WeiChartUtil.java
  3. 对外接口:WeiChartController.java

 WeiChartConfig.java

此文件主要配置接入微信支付需要的基础信息,例如:商户号、AppId、密钥、异步通知地址等信息,以及微信支付Api地址等信息。

 1 import com.erenju.util.GlobleConfig;
 2 
 3 /**
 4  * 微信支付基础信息配置
 5  * 沙箱测试地址前边添加:sandboxnew 例如:https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery
 6  * @author rxn
 7  * @date 2018/04/23
 8  *
 9  */
10 public class WeiChartConfig {
11 
12     /**
13      * 预支付请求接口(统一下单)
14      */
15     public static final String PrePayUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
16 //    public static final String PrePayUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder";
17     
18     /**
19      * 异步通知回调地址 ,外网可访问
20      */
21     public static final String notify_url = GlobleConfig.getProperty("PayNotifyUrl")+"/wxpay/notify.json";
22     
23     /**
24      * 查询订单地址
25      */
26     public static final String OrderUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
27 //    public static final String OrderUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery";
28     
29     /**
30      * 关闭订单地址
31      */
32     public static final String CloseOrderUrl = "https://api.mch.weixin.qq.com/pay/closeorder";
33 //    public static final String CloseOrderUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/closeorder";
34     
35     /**
36      * 申请退款地址
37      */
38     public static final String RefundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";
39 //    public static final String RefundUrl = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund";
40     
41     /**
42      * 查询退款地址
43      */
44     public static final String RefundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";
45 //    public static final String RefundQueryUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/refundquery";
46     
47     /**
48      * 商户AppId
49      */
50     public static final String AppId = "wx****************";
51     
52     /**
53      * 商户号,10位数字
54      */
55     public static final String MchId = "**********";
56     
57     /**
58      * 商户密钥 (32位),正式环境和沙箱环境的商户密钥是不同的
59      */
60     public static final String AppSercret = "*****";//正式
61     /**
62      * Api Key(32位)
63      */
64     public static final String ApiKey = "*****";
65     
66     /**
67      * 商品描述
68      */
69     public static final String body = "****";
70     
71     /**
72      * 退款需要证书文件,证书文件的地址
73      */
74     public static final String refund_file_path = "";
75 }
View Code

 WeiChartUtil.java

将业务逻辑和调用Api接口的逻辑分开写了,这样业务逻辑没有那么复杂,还增加了代码的复用率。

主要涉及的API如下图所示:(详细的API,请参考微信支付开放平台https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)

  1 package com.xhgx.web.pay.weiChart;
  2 
  3 import java.net.InetAddress;
  4 import java.net.UnknownHostException;
  5 import java.text.SimpleDateFormat;
  6 import java.util.Arrays;
  7 import java.util.Calendar;
  8 import java.util.HashMap;
  9 import java.util.Iterator;
 10 import java.util.Map;
 11 import java.util.Random;
 12 import java.util.Set;
 13 
 14 import org.dom4j.Document;
 15 import org.dom4j.DocumentException;
 16 import org.dom4j.DocumentHelper;
 17 import org.dom4j.Element;
 18 
 19 
 20 import com.xhgx.util.HttpClientUtil;
 21 import com.xhgx.util.StringUtil;
 22 
 23 import common.Logger;
 24 
 25 /**
 26  * 微信支付调用API接口
 27  * @author rxn
 28  * @date 2018/04/23
 29  *
 30  */
 31 public class WeiChartUtil {
 32 
 33     public static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
 34     
 35     public static Logger log = Logger.getLogger(WeiChartUtil.class);
 36     
 37     public static void main(String[] args) {
 38         
 39         Map map = new HashMap<>();
 40         map.put("mch_id", WeiChartConfig.MchId);
 41         map.put("nonce_str", getRandomString());
 42         String sign = getSign(map);
 43         map.put("sign", sign);
 44         System.out.println(map.get("mch_id"));
 45         System.out.println(map.get("nonce_str"));
 46         System.out.println(sign);
 47         
 48         String string = HttpClientUtil.sendHttpPost("http://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", map);
 49         System.out.println(string);
 50     }
 51     
 52     /**
 53      * 请求获取预支付订单
 54      * @param orderId    订单id
 55      * @param totalFee    总金额(单位:分)
 56      * @return
 57      */
 58     public static Map<String, Object> getPrepayOrderInfo(String orderId,String totalFee){
 59         Map<String, Object> m = new HashMap<String, Object>();
 60         try {
 61             for(int i=0;i<1;i++){
 62                 if(StringUtil.isEmpty(orderId)){
 63                     m.put("code", -1);
 64                     m.put("message", "订单号不能为空");
 65                     break;
 66                 }
 67                 if(Double.parseDouble(totalFee)<=0){
 68                     m.put("code", -1);
 69                     m.put("message", "订单金额有误");
 70                     break;
 71                 }
 72                 
 73                 Map<String,String> resultMap = getPreyId(orderId, totalFee, "义龙出行");
 74 
 75                 System.out.println("resultMap:"+resultMap);
 76                 
 77                 String return_code = resultMap.get("return_code");//返回状态码
 78                 String return_msg = resultMap.get("return_msg");//返回信息
 79                 //签名失败
 80                 /*if(!StringUtil.isEmpty(return_msg)){
 81                     m.put("code", -1);
 82                     m.put("message", return_msg);
 83                     break;
 84                 }*/
 85                     
 86                 if("SUCCESS".equals(return_code)){
 87 //                    String appid = resultMap.get("appid");//应用APPID
 88                     String mch_id = resultMap.get("mch_id");//商户号
 89 //                    String device_info = resultMap.get("device_info");//设备号
 90                     String nonce_str = resultMap.get("nonce_str");//随机字符串
 91                     String sign = resultMap.get("sign");//签名
 92                     String result_code = resultMap.get("result_code");//业务结果
 93                     
 94                     if("SUCCESS".equals(result_code)){
 95                         String trade_type = resultMap.get("trade_type");//交易类型:APP
 96                         String prepay_id = resultMap.get("prepay_id");//预支付交易会话标识,有效期为两个小时
 97                         
 98                         //重新生成sign
 99                         Map<String,String> signMap = new HashMap<String,String>();
100                         String timeStamp = getTenTimes();
101 //                        signMap.put("appid", appid);
102                         signMap.put("appid", WeiChartConfig.AppId);
103                         signMap.put("partnerid", mch_id);
104                         signMap.put("prepayid", prepay_id);
105                         signMap.put("package", "Sign=WXPay");
106                         signMap.put("noncestr", nonce_str);
107                         signMap.put("timestamp", timeStamp);//时间戳:10位
108                         
109                         String newSign = getSign(signMap);
110 //                        System.out.println("String:"+newSign);
111                         System.out.println(creatXml(signMap));
112                         m.put("sign", newSign);
113 //                        m.put("sign", sign);
114                         m.put("appid", WeiChartConfig.AppId);
115                         m.put("mch_id", mch_id);
116                         m.put("nonce_str", nonce_str);
117                         m.put("trade_type", trade_type);
118                         m.put("prepay_id", prepay_id);
119                         m.put("package", "WXPay");
120                         m.put("timestamp", timeStamp);
121                         
122                         m.put("code", 0);
123                         m.put("message", "请求成功");
124                         break;
125                     }else{
126                         String err_code = resultMap.get("err_code");//错误代码
127                         String err_code_des = resultMap.get("err_code_des");//错误代码描述
128                         
129                         m.put("code", -1);
130                         m.put("err_code", err_code);
131                         m.put("message", err_code_des);
132                         break;
133                     }
134                     
135                 }else{
136                     m.put("code", -1);
137                     m.put("message", "请求失败");
138                     break;
139                 }
140             
141             }
142         } catch (Exception e) {
143             e.printStackTrace();
144             m.put("code", -1);
145             m.put("message", "程序异常");
146         }
147         return m;
148     }
149     
150     /**
151      * 统一下单
152      * @param orderId 订单id
153      * @param totalFee    总金额(分)
154      * @param schoolLabel
155      * @return
156      */
157     public static Map<String, String> getPreyId(String orderId,String totalFee,String schoolLabel){
158         Map<String,String> m = new HashMap<String,String>();
159         m.put("appid", WeiChartConfig.AppId);//应用id
160         m.put("body", "【"+schoolLabel+"】"+WeiChartConfig.body);//商品描述
161         m.put("mch_id", WeiChartConfig.MchId);//商户号
162         m.put("nonce_str", getRandomString());//随机字符串
163         m.put("notify_url", WeiChartConfig.notify_url);//通知地址
164         m.put("out_trade_no", orderId);//订单号
165         m.put("spbill_create_ip", getHostIp());//用户端实际ip
166         Calendar cal = Calendar.getInstance();
167         cal.add(Calendar.HOUR_OF_DAY, 2);//有效时间
168         m.put("time_expire", sdf.format(cal.getTime()));//交易结束时间,非必填
169         Calendar cal1 = Calendar.getInstance();
170         m.put("time_start", sdf.format(cal1.getTime()));//交易起始时间,非必填
171 //        m.put("total_fee", totalFee);//总金额
172         m.put("total_fee", 1+"");//总金额
173         m.put("trade_type", "APP");//交易类型
174         m.put("sign", getSign(m));//签名
175         
176         String reqStr = creatXml(m);
177         String retStr = HttpClientUtil.postHtpps(WeiChartConfig.PrePayUrl, reqStr);
178         
179         System.out.println("微信调起统一下单接口返回结果:"+retStr);
180         return getInfoByXml(retStr);
181     }
182     
183     /**
184      * 查询订单
185      * @param orderId
186      * @return
187      */
188     public static Map<String, String> getOrder(String orderId){
189         Map<String, String> m = new HashMap<String,String>();
190         m.put("appid", WeiChartConfig.AppId);
191         m.put("mch_id", WeiChartConfig.MchId);
192         m.put("nonce_str", getRandomString());
193         m.put("out_trade_no", orderId);//商户订单号
194         m.put("sign", getSign(m));
195         
196         String reqStr = creatXml(m);
197         String retStr = HttpClientUtil.postHtpps(WeiChartConfig.OrderUrl, reqStr);
198         return getInfoByXml(retStr);
199     }
200     
201     /**
202      * 关闭订单
203      * @param orderId
204      * @return
205      */
206     public static Map<String, String> closeOrder(String orderId){
207         Map<String, String> m = new HashMap<String,String>();
208         m.put("appid", WeiChartConfig.AppId);
209         m.put("mch_id", WeiChartConfig.MchId);
210         m.put("out_trade_no", orderId);//商户订单号
211         m.put("nonce_str", getRandomString());
212         m.put("sign", getSign(m));
213         
214         String reqStr = creatXml(m);
215         String retStr = HttpClientUtil.postHtpps(WeiChartConfig.CloseOrderUrl, reqStr);
216         return getInfoByXml(retStr);
217     }
218     
219     /**
220      * 退款
221      * @param orderId    订单号
222      * @param refundId    退款单号
223      * @param totalFee    订单金额(分)
224      * @param refundFee    退款金额(分)
225      * @return
226      */
227     public static Map<String, String> refund(String orderId,String refundId,String totalFee,String refundFee){
228         Map<String, String> m = new HashMap<String,String>();
229         m.put("appid", WeiChartConfig.AppId);
230         m.put("mch_id", WeiChartConfig.MchId);
231         m.put("nonce_str", getRandomString());
232         m.put("out_trade_no", orderId);//商户订单号
233         m.put("out_refund_no", refundId);//退款单号
234         m.put("total_fee", totalFee);//订单金额
235         m.put("refund_fee", refundFee);//退款金额
236         m.put("sign", getSign(m));
237         
238         String reqStr = creatXml(m);
239         String retStr = "";
240         try {
241             retStr = HttpClientUtil.postHttplientNeedSSL(WeiChartConfig.RefundUrl, reqStr, WeiChartConfig.refund_file_path, WeiChartConfig.MchId);
242         } catch (Exception e) {
243             // TODO Auto-generated catch block
244             e.printStackTrace();
245             return null;
246         }
247         return getInfoByXml(retStr);
248     }
249     /**
250      * 查询退款
251      * @param orderId
252      * @return
253      */
254     public static Map<String, String> getOrderRefundQueryInfo(String orderId){
255         Map<String,String> m = new HashMap<String,String>();
256         m.put("appid", WeiChartConfig.AppId);
257         m.put("mch_id", WeiChartConfig.MchId);
258         m.put("nonce_str", getRandomString());
259         m.put("out_trade_no", orderId);//订单号
260         m.put("sign", getSign(m));
261         
262         String reqStr = creatXml(m);
263         String retStr = HttpClientUtil.postHtpps(WeiChartConfig.RefundQueryUrl, reqStr);
264         return getInfoByXml(retStr);
265     }
266     
267     /**
268      * 得到随机字符串
269      * 
270      * @param length
271      * @return
272      */
273     public static String getRandomString() {
274         int length = 32;
275         String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
276         Random random = new Random();
277         StringBuffer sb = new StringBuffer();
278 
279         for (int i = 0; i < length; ++i) {
280             int number = random.nextInt(62);// [0,62)
281             sb.append(str.charAt(number));
282         }
283         return sb.toString();
284     }
285 
286     /**
287      * 得到本地机器的IP
288      * 
289      * @return
290      */
291     private static String getHostIp() {
292         String ip = "";
293         try {
294             ip = InetAddress.getLocalHost().getHostAddress();
295         } catch (UnknownHostException e) {
296             e.printStackTrace();
297         }
298         return ip;
299     }
300     /**
301      * 生成为头为XML的xml字符串,例如:<xml><key>123</key></xml>
302      * @param reqMap
303      * @return
304      */
305     public static String creatXml(Map<String, String> reqMap){
306           Set<String> set = reqMap.keySet();
307           StringBuffer b = new StringBuffer();
308           b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
309           b.append("<xml>");
310           for(String key : set){
311              b.append("<"+key+">").append(reqMap.get(key)).append("</"+key+">");
312           }
313           b.append("</xml>");
314           return b.toString();
315        }
316 
317     /**
318      * 生成签名
319      * 
320      * @param map
321      * @return
322      */
323     public static String getSign(Map<String, String> map) {
324         String[] keys = map.keySet().toArray(new String[0]);
325         Arrays.sort(keys);
326         StringBuffer reqStr = new StringBuffer();
327         for (String key : keys) {
328             String v = map.get(key);
329             if (v != null && !v.equals("")) {
330                 reqStr.append(key).append("=").append(v).append("&");
331             }
332         }
333         reqStr.append("key").append("=").append(WeiChartConfig.ApiKey);
334 
335         return getMd5ByOrder(reqStr.toString()).toUpperCase();
336     }
337 
338     /** 
339      * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 
340      * @return boolean 
341      */  
342     public static boolean isTenpaySign(Map<String, String> map) { 
343         
344         String sign = map.get("sign");//获取微信返回的sign,进行比较
345         map.remove("sign");//生成签名时,去除sign
346         
347         String[] keys = map.keySet().toArray(new String[0]);
348         Arrays.sort(keys);
349         StringBuffer reqStr = new StringBuffer();
350         for (String key : keys) {
351             String v = map.get(key);
352             if (v != null && !v.equals("")) {
353                 reqStr.append(key).append("=").append(v).append("&");
354             }
355         }
356         reqStr.append("key").append("=").append(WeiChartConfig.ApiKey);
357 
358         //算出摘要  
359         String mysign = getMd5ByOrder(reqStr.toString()).toLowerCase();  
360         String tenpaySign = sign.toLowerCase();  
361 
362 //        System.out.println(tenpaySign + "    " + mysign);  
363         return tenpaySign.equals(mysign);  
364     } 
365     
366     /**
367      * 解析xml
368      * 
369      * @param xmlStr
370      * @return
371      */
372     public static Map<String, String> getInfoByXml(String xmlStr) {
373         try {
374             Map<String, String> m = new HashMap<String, String>();
375             Document d = DocumentHelper.parseText(xmlStr);
376             Element root = d.getRootElement();
377             for (Iterator<?> i = root.elementIterator(); i.hasNext();) {
378                 Element element = (Element) i.next();
379                 String name = element.getName();
380                 if (!element.isTextOnly()) {
381                     // 不是字符串 跳过。确定了微信放回的xml只有根目录
382                     continue;
383                 } else {
384                     m.put(name, element.getTextTrim());
385                 }
386             }
387             Map<String,String> map = new HashMap<String,String>();
388             map.putAll(m);
389             // 对返回结果做校验.去除sign 字段再去加密
390             String retSign = m.get("sign");
391             m.remove("sign");
392             String rightSing = getSign(m);
393             if (rightSing.equals(retSign)) {
394                 return map;
395             }
396         } catch (DocumentException e) {
397             // TODO Auto-generated catch block
398             e.printStackTrace();
399         }
400         return null;
401     }
402 
403     /**
404      * 获取10位的时间戳
405      * @return
406      */
407     public static String getTenTimes(){
408         String time = System.currentTimeMillis()+"";
409         return time.substring(0, time.length()-3);
410     }
411         /**
412      * 将文本转排序后,换成MD5加密后的字符串
413      * @param s
414      * @return
415      * @author Rxn
416      * @date 2018-05-08
417      */
418     public static String getMd5ByOrder(String s){
419         MessageDigest md;
420         StringBuilder sStringBuilder = new StringBuilder();
421         try {
422             md = MessageDigest.getInstance("MD5");
423             md.reset();
424             try {
425                 md.update(s.getBytes("utf-8"));
426             } catch (UnsupportedEncodingException e) {
427                 e.printStackTrace();
428             }
429             byte[] digest = md.digest();
430             sStringBuilder.setLength(0);
431             
432             for (int i = 0; i < digest.length; ++i) {  
433                 int b = digest[i] & 255;  
434                 if (b < 16) {  
435                     sStringBuilder.append('0');  
436                 }  
437       
438                 sStringBuilder.append(Integer.toHexString(b));  
439             }  
440       
441             return sStringBuilder.toString().toUpperCase();
442             
443         } catch (NoSuchAlgorithmException e) {
444             e.printStackTrace();
445         }
446         
447         return null;
448     }
449 }
450     
View Code

 WeiChartController.java

这里主要涉及一些业务处理,代码中我主要粘了对外的异步通知接口(主要作用是App支付成功后,会有一个支付成功的返回信息告知商户),其他需要的接口已经在WeiChartUtil.java中处理过了,直接调用即可。

  1 import java.io.BufferedOutputStream;
  2 import java.io.BufferedReader;
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.io.InputStreamReader;
  6 import java.math.BigDecimal;
  7 import java.text.ParseException;
  8 import java.text.SimpleDateFormat;
  9 import java.util.Date;
 10 import java.util.HashMap;
 11 import java.util.Iterator;
 12 import java.util.Map;
 13 import javax.servlet.http.HttpServletRequest;
 14 import javax.servlet.http.HttpServletResponse;
 15 import org.springframework.beans.factory.annotation.Autowired;
 16 import org.springframework.stereotype.Controller;
 17 import org.springframework.web.bind.annotation.RequestMapping;
 18 import org.springframework.web.bind.annotation.ResponseBody;
 19 import com.xhgx.util.StringUtil;
 20 import com.xhgx.web.SpringContextUtil;
 21 import common.Logger;
 22 
 23 /**
 24  * 
 25  * @author rxn
 26  * @data 2018/05/03
 27  *
 28  */
 29 @Controller
 30 public class WeiChartController{
 31 
 32     public static Logger log = Logger.getLogger(WeiChartController.class);
 33     
 34     public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 35     public static SimpleDateFormat ymdhms = new SimpleDateFormat("yyyyMMddHHmmss");
 36     
 37     /**
 38      * 异步通知,回调方法
 39      * @param request
 40      * @param response
 41      * @throws IOException 
 42      */
 43     @ResponseBody
 44     @RequestMapping("/wxpay/notify.json")
 45     public static void getNotifyInfo(HttpServletRequest request, HttpServletResponse response) throws IOException{
 46         System.out.println("微信APP异步通知,回调方法");
 47         //读取参数
 48         InputStream inputStream ;  
 49         StringBuffer sb = new StringBuffer();  
 50         inputStream = request.getInputStream();  
 51         String s ;  
 52         BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));  
 53         while ((s = in.readLine()) != null){  
 54             sb.append(s);  
 55         }  
 56         in.close();  
 57         inputStream.close(); 
 58          
 59         String reqStr = new String(sb);
 60         //将xml解析成map
 61         Map<String, String> reqMap = WeiChartUtil.getInfoByXml(reqStr);
 62         
 63         //过滤空
 64         Map<String,String> paramMap = new HashMap<String,String>();
 65         Iterator it = reqMap.keySet().iterator();
 66         while (it.hasNext()) {
 67             String name = (String) it.next();
 68             String value = reqMap.get(name);
 69             
 70             String v = "";
 71             if(value!=null){
 72                 v = value.trim();
 73             }
 74             paramMap.put(name, v);
 75         }
 76         
 77         String resXml="";//响应数据
 78         //创建一个对象,保存通知信息,可以根据业务需求自己定义
 79         PayNotifyTbl payNotifyTbl = new PayNotifyTbl();
 80         payNotifyTbl.setPay_type(1);//支付类型: 1微信 2支付宝
 81         payNotifyTbl.setCreate_dt(new Date());
 82         //验证签名
 83         if(WeiChartUtil.isTenpaySign(paramMap)){
 84             String return_code = paramMap.get("return_code");//返回状态码
 85             String return_msg = paramMap.get("return_msg");//返回信息
 86             String result_code = paramMap.get("result_code");
 87             String err_code = paramMap.get("err_code");
 88             String err_code_des = paramMap.get("err_code_des");
 89             
 90             payNotifyTbl.setReturn_code(return_code);
 91             payNotifyTbl.setReturn_msg(return_msg);
 92             payNotifyTbl.setResult_code(result_code);
 93             payNotifyTbl.setErr_code(err_code);
 94             payNotifyTbl.setErr_code_des(err_code_des);
 95             
 96             if("SUCCESS".equals(return_code)&&"SUCCESS".equals(result_code)){
 97                 String appid = paramMap.get("appid");
 98                 String mch_id = paramMap.get("mch_id");
 99                 String openid = paramMap.get("openid");
100                 String trade_type = paramMap.get("trade_type");
101                 String total_fee = paramMap.get("total_fee");//单位:分
102                 String transaction_id = paramMap.get("transaction_id");//微信支付订单号
103                 String out_trade_no = paramMap.get("out_trade_no");//商户订单号
104                 String time_end = paramMap.get("time_end");//支付完成时间
105                 
106                 payNotifyTbl.setAppid(appid);
107                 payNotifyTbl.setOpenid(openid);
108                 payNotifyTbl.setOrder_id(out_trade_no);
109                 payNotifyTbl.setTrade_type(trade_type);
110                 payNotifyTbl.setTotal_fee(Double.parseDouble(total_fee)/100.00);
111                 payNotifyTbl.setTransaction_id(transaction_id);
112                 try {
113                     payNotifyTbl.setTime_end(sdf.format(ymdhms.parse(time_end)));
114                 } catch (ParseException e) {
115                     e.printStackTrace();
116                 }
117                 
118                 
119                 //业务处理,查询订单
120                 OrderTbl order = orderTblService.get(Integer.parseInt(out_trade_no));
121                 //安全起见,添加金额作比较
122                 if(!WeiChartConfig.MchId.equals(mch_id) || order==null || Double.parseDouble(total_fee)/100!=getIntRound(order.getPrice().doubleValue()){
123                     payNotifyTbl.setPay_result("参数错误");
124                     log.info("支付失败,错误信息:" + "参数错误");  
125                     resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
126                                  + "<return_msg><![CDATA[参数错误]]></return_msg>" + "</xml> ";
127                 }else{
128                     if(order.getOrder_status()==7){
129                         //逻辑处理,支付完成,修改订单状态
130                         order.setOrder_status(OrderStatus.STEP_08.getNodeId());//订单完成
131                         order.setTotal_price(Double.parseDouble(total_fee)/100);//支付费用
132                         order.setPay_way(1);//微信支付
133                         order.setPay_time(new Date());//支付时间
134                         order = ycOrderTblService.save(order);
135                         
136                         payNotifyTbl.setPay_result("支付成功");
137                         resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
138                                 + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
139                     }else{
140                         payNotifyTbl.setPay_result("订单已经被处理");
141                         log.info("订单已经被处理");
142                         resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
143                                  + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
144                     }
145                     
146                 }
147                 
148             }else{
149                 payNotifyTbl.setPay_result(paramMap.get("return_msg"));
150                 log.info("微信支付异步通知返回的错误信息:"+paramMap.get("return_msg"));
151                 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
152                         + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
153             }
154             
155         }else{
156             payNotifyTbl.setPay_result("微信支付异步通知签名验证失败");
157             log.info("微信支付异步通知签名验证失败");
158             resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
159                     + "<return_msg><![CDATA[通知签名验证失败]]></return_msg>" + "</xml> ";
160         }
161         
162         if(payNotifyTblService==null){
163             payNotifyTblService= (PayNotifyTblService) SpringContextUtil.getBean(PayNotifyTblService.class);
164         }
165         
166         payNotifyTbl = payNotifyTblService.save(payNotifyTbl);
167         //返回微信支付系统告知成功接收
168         BufferedOutputStream out = new BufferedOutputStream(  
169                 response.getOutputStream());  
170         out.write(resXml.getBytes());  
171         out.flush();  
172         out.close();
173     }
174     
175 }
176     
View Code

在接入微信支付时,入了很多坑,特别注意:生成签名时传入参数的顺序,不同的顺序会导致生成的签名与微信返回的签名不一致。尤其注意调用统一下单接口后,重新生成签名的顺序,一定要按照appid,partnerid,prepayid,noncestr,timestamp,package的顺序,否则App会调起支付页面失败,报签名异常的错误。另外注意:异步通知地址一定是外网可以访问的,而且和微信平台上配置的异步通知地址一致。

猜你喜欢

转载自www.cnblogs.com/ning0628/p/9237380.html