微信公眾號實現支付功能(基於官方sdk實現)--備忘001
阿新 • • 發佈:2019-01-30
首先要明白微信支付相關的三個賬號
1:一定要認真閱讀官方開發文件,不然好多坑啊
官方sdk-maven
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
開發的相關流程:
a>:通過統一下單方法獲取到預付訂單資訊(prepay_id-預付訂單資訊)
b>:對預付訂單進行二次簽名返回json資料給前端準備調起支付(二次簽名需要自己實現,微信不提供,可參考微信簽名方法)
c>:前端根據獲取到的資料喚起支付頁面進行支付
2:根據自己專案需求寫相關的介面實現(從前端獲取官方文件中的相關引數)
3:調官方sdk填充資料的方法進行關鍵資訊的填充
//調官方sdk方法填充資料
data = wxPay.fillRequestData(data);
/** * 向 Map 中新增 appid、mch_id、nonce_str、sign_type、sign <br> * 該函式適用於商戶適用於統一下單等介面,不適用於紅包、代金券介面 * * @param reqData * @return * @throws Exception */ public Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception { reqData.put("appid", config.getAppID()); reqData.put("mch_id", config.getMchID()); reqData.put("nonce_str", WXPayUtil.generateNonceStr()); if (SignType.MD5.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.MD5); } else if (SignType.HMACSHA256.equals(this.signType)) { reqData.put("sign_type", WXPayConstants.HMACSHA256); } reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType)); return reqData; }
4:完成相關資料填充後調官方sdk的統一下單方法
//調官方sdk統一下單方法
Map<String, String> result = wxPay.unifiedOrder(data);
/** * 作用:統一下單<br> * 場景:公共號支付、掃碼支付、APP支付 * @param reqData 向wxpay post的請求資料 * @return API返回資料 * @throws Exception */ public Map<String, String> unifiedOrder(Map<String, String> reqData) throws Exception { return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs()); } /** * 作用:統一下單<br> * 場景:公共號支付、掃碼支付、APP支付 * @param reqData 向wxpay post的請求資料 * @param connectTimeoutMs 連線超時時間,單位是毫秒 * @param readTimeoutMs 讀超時時間,單位是毫秒 * @return API返回資料 * @throws Exception */ public Map<String, String> unifiedOrder(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception { String url; if (this.useSandbox) { url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL; } else { url = WXPayConstants.UNIFIEDORDER_URL; } String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs); return this.processResponseXml(respXml); }
5:對統一下單方法返回資料進行二次簽名準備返回給前端(注意該方法需要自己去實現,官方沒有單獨提供二次簽名方法,我是把官方簽名方法copy出來自己建了一個工具類,然後調自己的工具類進行的二次簽名,僅供參考)
if (req.getTradeType().equals(PayRequest.TRADE_TYPE_JSAPI)) {
out.put("appId", result.get("appid"));
out.put("nonceStr", String.valueOf(System.currentTimeMillis()));
out.put("package", "prepay_id=" + result.get("prepay_id"));
out.put("signType", "MD5");
out.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
//##對返回資料進行二次簽名 TODO
String packageSign = WXPayUtil.generateSignature(out,wxPayProperties.getKey());
out.put("paySign", packageSign);
}
/**
* 生成簽名. 注意,若含有sign_type欄位,必須和signType引數保持一致。
*
* @param data 待簽名資料
* @param key API金鑰
* @param signType 簽名方式
* @return 簽名
*/
public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 引數值為空,則不參與簽名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* 生成 MD5
*
* @param data 待處理資料
* @return MD5結果
*/
public static String MD5(String data) throws Exception {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}
6:把簽名後的資料返回給前端,剩下的事就交給前端實現