微信支付之App支付
項目接入微信支付的準(zhǔn)備工作:
接入App支付的業(yè)務(wù)流程主要如下圖所示:
接下來,就描述一下接入項目的詳細(xì)步驟:
?WeiChartConfig.java
此文件主要配置接入微信支付需要的基礎(chǔ)信息,例如:商戶號、AppId、密鑰、異步通知地址等信息,以及微信支付Api地址等信息。
1 import com.erenju.util.GlobleConfig; 2 3 /** 4 * 微信支付基礎(chǔ)信息配置 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 * 預(yù)支付請求接口(統(tǒng)一下單) 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 * 異步通知回調(diào)地址 ,外網(wǎng)可訪問 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 * 關(guān)閉訂單地址 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位數(shù)字 54 */ 55 public static final String MchId = "**********"; 56 57 /** 58 * 商戶密鑰 (32位),正式環(huán)境和沙箱環(huán)境的商戶密鑰是不同的 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
將業(yè)務(wù)邏輯和調(diào)用Api接口的邏輯分開寫了,這樣業(yè)務(wù)邏輯沒有那么復(fù)雜,還增加了代碼的復(fù)用率。
主要涉及的API如下圖所示:(詳細(xì)的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 * 微信支付調(diào)用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 * 請求獲取預(yù)支付訂單 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");//返回狀態(tài)碼 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");//應(yīng)用APPID 88 String mch_id = resultMap.get("mch_id");//商戶號 89 // String device_info = resultMap.get("device_info");//設(shè)備號 90 String nonce_str = resultMap.get("nonce_str");//隨機字符串 91 String sign = resultMap.get("sign");//簽名 92 String result_code = resultMap.get("result_code");//業(yè)務(wù)結(jié)果 93 94 if("SUCCESS".equals(result_code)){ 95 String trade_type = resultMap.get("trade_type");//交易類型:APP 96 String prepay_id = resultMap.get("prepay_id");//預(yù)支付交易會話標(biāo)識,有效期為兩個小時 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 * 統(tǒng)一下單 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);//應(yīng)用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()));//交易結(jié)束時間,非必填 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("微信調(diào)起統(tǒng)一下單接口返回結(jié)果:"+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 * 關(guān)閉訂單 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 * 是否簽名正確,規(guī)則是:按參數(shù)名稱a-z排序,遇到空值的參數(shù)不參加簽名。 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 // 對返回結(jié)果做校驗.去除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 * 將文本轉(zhuǎn)排序后,換成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
這里主要涉及一些業(yè)務(wù)處理,代碼中我主要粘了對外的異步通知接口(主要作用是App支付成功后,會有一個支付成功的返回信息告知商戶),其他需要的接口已經(jīng)在WeiChartUtil.java中處理過了,直接調(diào)用即可。
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 * 異步通知,回調(diào)方法 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異步通知,回調(diào)方法"); 47 //讀取參數(shù) 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="";//響應(yīng)數(shù)據(jù) 78 //創(chuàng)建一個對象,保存通知信息,可以根據(jù)業(yè)務(wù)需求自己定義 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");//返回狀態(tài)碼 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 //業(yè)務(wù)處理,查詢訂單 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("參數(shù)錯誤"); 124 log.info("支付失敗,錯誤信息:" + "參數(shù)錯誤"); 125 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" 126 + "<return_msg><![CDATA[參數(shù)錯誤]]></return_msg>" + "</xml> "; 127 }else{ 128 if(order.getOrder_status()==7){ 129 //邏輯處理,支付完成,修改訂單狀態(tài) 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("訂單已經(jīng)被處理"); 141 log.info("訂單已經(jīng)被處理"); 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 //返回微信支付系統(tǒng)告知成功接收 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?
在接入微信支付時,入了很多坑,特別注意:生成簽名時傳入?yún)?shù)的順序,不同的順序會導(dǎo)致生成的簽名與微信返回的簽名不一致。尤其注意調(diào)用統(tǒng)一下單接口后,重新生成簽名的順序,一定要按照appid,partnerid,prepayid,noncestr,timestamp,package的順序,否則App會調(diào)起支付頁面失敗,報簽名異常的錯誤。另外注意:異步通知地址一定是外網(wǎng)可以訪問的,而且和微信平臺上配置的異步通知地址一致。
轉(zhuǎn)載于:https://www.cnblogs.com/ning0628/p/9237380.html
總結(jié)
以上是生活随笔為你收集整理的微信支付之App支付的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为数通笔记-文件传输协议FTP
- 下一篇: spring cloud tencent