大家好,我是小悟
1、介紹
用戶支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給清算機(jī)構(gòu),清算機(jī)構(gòu)需要接收處理后返回應(yīng)答成功,然后繼續(xù)給異步通知到下游從業(yè)機(jī)構(gòu)。
對后臺通知交互時,如果微信收到應(yīng)答不是成功或超時,微信認(rèn)為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。

2、對通知數(shù)據(jù)進(jìn)行解密
系統(tǒng)對于開啟結(jié)果通知的內(nèi)容一定要做簽名驗(yàn)證,并校驗(yàn)通知的信息是否與我們的信息一致,防止數(shù)據(jù)泄露導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
支付通知和獲取微信支付平臺證書一樣,需要對獲取到的內(nèi)容進(jìn)行解密,解密規(guī)則一樣,AesUtils這個解密工具類參考官方文檔給的demo。
String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);
System.out.println("微信支付回調(diào)返回參數(shù)result:=====" + result);
JSONObject json = JSONObject.parseObject(result);
System.out.println("微信支付回調(diào)返回參數(shù)json:=====" + json);
JSONObject resourceRes = json.getJSONObject("resource");
System.out.println("微信支付回調(diào)返回參數(shù)resourceRes:=====" + resourceRes);
AesUtils aesUtil = new AesUtils("APIv3密鑰".getBytes(StandardCharsets.UTF_8));
String resourceStr = aesUtil.decryptToString(resourceRes.getString("associated_data").getBytes(StandardCharsets.UTF_8),
resourceRes.getString("nonce").getBytes(StandardCharsets.UTF_8),
resourceRes.getString("ciphertext"));
JSONObject resourceJson = JSONObject.parseObject(resourceStr);
System.out.println("微信支付回調(diào)返回參數(shù)resourceJson明文:=====" + resourceJson);

3、避免重復(fù)下發(fā)通知
同樣的通知可能會多次發(fā)送給我們自身系統(tǒng),所以我們需要做好正確處理重復(fù)通知的邏輯。當(dāng)自身系統(tǒng)收到通知進(jìn)行處理時,先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進(jìn)行處理,如果已處理,則直接返回結(jié)果成功。
為盡可能提高通知的成功率,微信側(cè)會重復(fù)發(fā)起通知,為了避免這樣的結(jié)果影響到處理業(yè)務(wù)邏輯,我們需要返回一定格式的響應(yīng)數(shù)據(jù)給微信,如下,親測有效。
Map<String,Object> res = new HashMap<String, Object> ();
res.put("code","SUCCESS");
res.put("message","OK");
res.put("code","ERROR_NAME");
res.put("message",e.getMessage());

4、支付通知接口
在合單支付的notify_url參數(shù)字段傳入"https://xxx/combineNotify"即可
@RequestMapping(value = "/combineNotify", method = {RequestMethod.POST})
public Map<String,Object> combineNotify(HttpServletRequest request) {
Map<String,Object> res = new HashMap<String, Object> ();
try {
// 創(chuàng)建支付應(yīng)答對象
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String result = new String(outSteam.toByteArray(), StandardCharsets.UTF_8);
System.out.println("微信支付回調(diào)返回參數(shù)result:=====" + result);
JSONObject json = JSONObject.parseObject(result);
System.out.println("微信支付回調(diào)返回參數(shù)json:=====" + json);
JSONObject resourceRes = json.getJSONObject("resource");
System.out.println("微信支付回調(diào)返回參數(shù)resourceRes:=====" + resourceRes);
AesUtils aesUtil = new AesUtils("APIv3密鑰".getBytes(StandardCharsets.UTF_8));
String resourceStr = aesUtil.decryptToString(resourceRes.getString("associated_data").getBytes(StandardCharsets.UTF_8),
resourceRes.getString("nonce").getBytes(StandardCharsets.UTF_8),
resourceRes.getString("ciphertext"));
JSONObject resourceJson = JSONObject.parseObject(resourceStr);
System.out.println("微信支付回調(diào)返回參數(shù)resourceJson明文:=====" + resourceJson);
//驗(yàn)證微信支付返回簽名
String Wtimestamp = request.getHeader("Wechatpay-Timestamp");
String Wnonce = request.getHeader("Wechatpay-Nonce");
String Wsign = request.getHeader("Wechatpay-Signature");
System.out.println("Wtimestamp:"+Wtimestamp+",Wnonce:"+Wnonce+",Wsign:"+Wsign);
//拼裝待簽名串
StringBuffer ss =new StringBuffer();
ss.append(Wtimestamp).append("\n");
ss.append(Wnonce).append("\n");
ss.append(result).append("\n");
//驗(yàn)證簽名
if(SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), "/data/tomcat/webapps/ROOT/wechat_pay_platform_4927801AFE1D0A15A2E4491C9C13E6414B17AFCC.pem")) {
System.out.println("微信支付回調(diào)簽名驗(yàn)證成功");
}else {
System.out.println("微信支付回調(diào)簽名驗(yàn)證失敗");
}
res.put("code","SUCCESS");
res.put("message","OK");
} catch (GeneralSecurityException e) {
e.printStackTrace();
res.put("code","ERROR_NAME");
res.put("message",e.getMessage());
} catch (IOException e) {
e.printStackTrace();
res.put("code","ERROR_NAME");
res.put("message",e.getMessage());
} catch (Exception e) {
e.printStackTrace();
res.put("code","ERROR_NAME");
res.put("message",e.getMessage());
}
return res;
}

5、結(jié)果
微信支付回調(diào)返回參數(shù)json:====={"summary":"支付成功","event_type":"TRANSACTION.SUCCESS","create_time":"2020-03-24T18:07:42+08:00","resource":{"associated_data":"transaction","ciphertext":"6XMaa17DRH9uKYuRJneC3wy6ihGiPquKGaCsCScBtxxMY5PLHEeLPl3kBgH/Yes+FOrLh92zsbQa85OIAtnc7eqlLpWb1uiP3jJhglmjzul35WK+naUsxzKLDgUFnUcyfV1PTM287QEFRIC+jvbwHK82lpELOEUCnBx0/ompQM3fzxWQczlw3CvPWTciSgy8XUqui5owvXxkbrKwruIEfigY/LOByXW0w26jX7hEKLjAghdD1NvIgFhkKf3MkbGduNiDsTn1V5z9hzoWR2MwJI/NZFRpsdr9QmxkSiGwf0FzqnOhCLsjntXAKru89CsdWyfznl2BRdbBYF+4ZRqRgbMr+sROQ9TNXVMYjNFeeyXdnpM0BNAdOIKCMI7eBkHsyARgKkXVVlAUkInatbkO/IyIUyJ4PaUJJAYkbxsgIrh1XXpDMfmR8lVpDT8FfumNebL4cILpcOCTfJ+4mn8Es8xKdOiGgEH6ZVqYrjWVkUwBwAHel4xGdat8i80wlIUh2q1z9IN0QggIHp4lCbnSeyeqiTh3WwFiM6Yv/1pHaYde/JSRo0fmdIhFrPGR383GXWqCkQK7yoUydu8e5Dq4qY1GPI9VcaAkMG68sVl762w3Us5/VvO41+nX1BlhFWNsg0VqDLHRvWL+I/gsbXHffub34Je2UF1e0mL7ghmFEXT6k6fQ4FYvSEPQ8CI3KaxMW1RJfUBRqpzKfrzkfi6EgVDAKXQvJc4HvwSmdix8UkRXysger/yfzugVAqwUV2SC6qm+m29MOHGgb37fCaL5fJOnXkvBeb7suYsT2RbyIvoA","original_type":"transaction","nonce":"qyzVVgtmQ0fk","algorithm":"AEAD_AES_256_GCM"},"resource_type":"encrypt-resource","id":"7b3b0fa6-a627-59c1-0733-2606ec31153c"}
微信支付回調(diào)返回參數(shù)resourceJson明文:====={"combine_appid":"wxd352ef315ac365bd","sub_orders":[{"transaction_id":"4323220200001484847904033204","amount":{"payer_amount":1,"total_amount":1,"currency":"CNY","payer_currency":"CNY"},"mchid":"1915696108","trade_state":"SUCCESS","out_trade_no":"out_trade_no2_1585030201441","bank_type":"OTHERS","trade_type":"JSAPI","attach":"123&456&789","success_time":"2020-03-24T18:07:43+08:00","sub_mchid":"1564468071"}],"combine_payer_info":{"openid":"ofMy16jrqy7Z8pS23M5JI4SkKvwc"},"combine_out_trade_no":"out_trade_no1_1504430158999","combine_mchid":"1811569960","scene_info":{"device_id":"POS1:12"}}
Wtimestamp:1546844504,Wnonce:jXQ70fE0SepL62SNpUhduNCooXF2RseC,Wsign:m2QZupx0hp3fPmfAfYD35FoYK+o1DOzWQs8vkeGTiFY68JHkIlx1cx825sPbW/AHu5xsQ4nlOt4BZZ0Q4Z6szqYgxJUZe/JR0OXNtoG0yHq0m5teVLoFY5eEAuY3szAPC5RIsUOs0ByXP62KEiNNiw7sYbdVXDar4MkKLho7NY6sjaigRQZeSGvsV0q0TIy1HTQTR9otAJ5lnibwbheecXaCLvvkvHGr/kDPHkvnP1fIzVzeIM32VDTf9L4/k7vN4zdgd4R73Y/6hmk8vyTsB+VfciqUpDUQ0rC0SigGzaLukawRK+S3r4XBe1nNiM0jVTKIe5l7s8BO9THd+gwI6A==
微信支付回調(diào)簽名驗(yàn)證成功

您的一鍵三連,是我更新的最大動力,謝謝
山水有相逢,來日皆可期,謝謝閱讀,我們再會
我手中的金箍棒,上能通天,下能探海