本篇內容主要講解“微信支付接入步驟”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“微信支付接入步驟”吧!
成都創(chuàng)新互聯(lián)-專業(yè)網站定制、快速模板網站建設、高性價比故城網站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式故城網站制作公司更省心,省錢,快速模板網站建設找我們,業(yè)務覆蓋故城地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。
微信支付接入大概步驟如下:
獲取支付接口 URL
構建請求參數(shù)
發(fā)起請求
喚起支付
支付異步通知處理
步驟一中獲取支付接口 URL,需要考慮這幾點
如何同時支持國內微信支付與境外微信支付
如何同時支持普通的商戶模式以及服務商模式
步驟二中經常遇到的問題就是參數(shù)簽名驗證問題
MD5 加密
HMAC-SHA256 加密
步驟三中難點在于微信支付雙向證書的處理
步驟四中預付訂單二次簽名異常以及喚起支付提示各種配置錯誤
步驟五中異步通知驗證簽名、訂單重復通知以及敏感數(shù)據的解密問題
以上接入步驟中,你踩過那些坑呢?歡迎評論區(qū)分享交流
Talk is cheap. Show me the code
有人會說「這不很簡單么」官方文檔接口中就有提供。對你說的沒錯,那如何做到一套系統(tǒng)同時支持國內微信支付與境外微信支付,又如何做跨城冗災方案呢?
根據業(yè)務區(qū)域的不同微信提供了不同的域名來支持
api.mch.weixin.qq.com(建議接入點:中國國內)
api2.mch.weixin.qq.com(建議接入點:中國國內備用)
apihk.mch.weixin.qq.com(建議接入點:東南亞)
apius.mch.weixin.qq.com(建議接入點:其它)
api.mch.weixin.qq.com/sandboxnew(特殊:仿真測試)
聰明的你,不難就會想到枚舉,具體跨城冗災方案可以參考微信支付商戶系統(tǒng)跨城冗災升級指引
/** * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯(lián)支付常用的支付方式以及各種常用的接口。</p> * * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發(fā),可輕松嵌入到任何系統(tǒng)里。 </p> * * <p>IJPay 交流群: 723992875</p> * * <p>Node.js 版: https://gitee.com/javen205/TNW</p> * * <p>微信支付可用域名枚舉</p> * * @author Javen */ public enum WxDomain { /** * 中國國內 */ CHINA("https://api.mch.weixin.qq.com"), /** * 中國國內(備用域名) */ CHINA2("https://api2.mch.weixin.qq.com"), /** * 東南亞 */ HK("https://apihk.mch.weixin.qq.com"), /** * 其它 */ US("https://apius.mch.weixin.qq.com"); /** * 域名 */ private final String domain; WxDomain(String domain) { this.domain = domain; } public String getType() { return domain; } }
至此獲取微信支付接口 URL 已解決掉了核心問題。剩下的就是根據不同的支付方式來拼接具體的支付接口 URL。
付款碼支付、JSAPI支付、Native支付、App支付、H5支付、小程序支付、紅包、企業(yè)付款、酒店押金、刷臉支付常用的支付方式以及支付工具不完全統(tǒng)計接口大概有 90+
package com.ijpay.wxpay.enums; /** * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯(lián)支付常用的支付方式以及各種常用的接口。</p> * * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發(fā),可輕松嵌入到任何系統(tǒng)里。 </p> * * <p>IJPay 交流群: 723992875</p> * * <p>Node.js 版: https://gitee.com/javen205/TNW</p> * * <p>微信支付接口枚舉</p> * * @author Javen */ public enum WxApiType { /** * 沙箱環(huán)境 */ SAND_BOX_NEW("/sandboxnew"), /** * 獲取沙箱環(huán)境驗簽秘鑰 */ GET_SIGN_KEY("/sandboxnew/pay/getsignkey"), /** * 統(tǒng)一下單 */ UNIFIED_ORDER("/pay/unifiedorder"), /** * 提交付款碼支付 */ MICRO_PAY("/pay/micropay"), /** * 查詢訂單 */ ORDER_QUERY("/pay/orderquery"), /** * 關閉訂單 */ CLOSE_ORDER("/pay/closeorder"), /** * 撤銷訂單 */ REVERSE("/secapi/pay/reverse"), /** * 申請退款 */ REFUND("/secapi/pay/refund"), /** * 查詢退款 */ REFUND_QUERY("/pay/refundquery"), /** * 下載對賬單 */ DOWNLOAD_BILL("/pay/downloadbill"), /** * 下載資金對賬單 */ DOWNLOAD_FUND_FLOW("/pay/downloadfundflow"), /** * 交易保障 */ REPORT("/payitil/report"), /** * 轉換短鏈接 */ SHORT_URL("/tools/shorturl"), /** * 授權碼查詢 openId */ AUTH_CODE_TO_OPENID("/tools/authcodetoopenid"), /** * 拉取訂單評價數(shù)據 */ BATCH_QUERY_COMMENT("/billcommentsp/batchquerycomment"), /** * 企業(yè)付款 */ TRANSFER("/mmpaymkttransfers/promotion/transfers"), /** * 查詢企業(yè)付款 */ GET_TRANSFER_INFO("/mmpaymkttransfers/gettransferinfo"), /** * 企業(yè)付款到銀行卡 */ TRANSFER_BANK("/mmpaysptrans/pay_bank"), /** * 查詢企業(yè)付款到銀行卡 */ GET_TRANSFER_BANK_INFO("/mmpaysptrans/query_bank"), /** * 獲取 RSA 加密公鑰 */ GET_PUBLIC_KEY("/risk/getpublickey"), /** * 發(fā)放紅包 */ SEND_RED_PACK("/mmpaymkttransfers/sendredpack"), /** * 發(fā)放裂變紅包 */ SEND_GROUP_RED_PACK("/mmpaymkttransfers/sendgroupredpack"), /** * 查詢紅包記錄 */ GET_HB_INFO("/mmpaymkttransfers/gethbinfo"), /** * 小程序發(fā)紅包 */ SEND_MINI_PROGRAM_HB("/mmpaymkttransfers/sendminiprogramhb"), /** * 發(fā)放代金券 */ SEND_COUPON("/mmpaymkttransfers/send_coupon"), /** * 查詢代金券批次 */ QUERY_COUPON_STOCK("/mmpaymkttransfers/query_coupon_stock"), /** * 查詢代金券信息 */ QUERY_COUPONS_INFO("/mmpaymkttransfers/querycouponsinfo"), /** * 請求單次分賬 */ PROFIT_SHARING("/secapi/pay/profitsharing"), /** * 請求多次分賬 */ MULTI_PROFIT_SHARING("/secapi/pay/multiprofitsharing"), /** * 查詢分賬結果 */ PROFIT_SHARING_QUERY("/pay/profitsharingquery"), /** * 添加分賬接收方 */ PROFITS_HARING_ADD_RECEIVER("/pay/profitsharingaddreceiver"), /** * 刪除分賬接收方 */ PROFIT_SHARING_REMOVE_RECEIVER("/pay/profitsharingremovereceiver"), /** * 完結分賬 */ PROFIT_SHARING_FINISH("/secapi/pay/profitsharingfinish"), /** * 分賬回退 */ PROFIT_SHARING_RETURN("/secapi/pay/profitsharingreturn"), /** * 分賬回退結果查詢 */ PROFIT_SHARING_RETURN_QUERY("/pay/profitsharingreturnquery"), /** * 支付押金(人臉支付) */ DEPOSIT_FACE_PAY("/deposit/facepay"), /** * 支付押金(付款碼支付) */ DEPOSIT_MICRO_PAY("/deposit/micropay"), /** * 查詢訂單(押金) */ DEPOSIT_ORDER_QUERY("/deposit/orderquery"), /** * 撤銷訂單(押金) */ DEPOSIT_REVERSE("/deposit/reverse"), /** * 消費押金 */ DEPOSIT_CONSUME("/deposit/consume"), /** * 申請退款(押金) */ DEPOSIT_REFUND("/deposit/refund"), /** * 查詢退款(押金) */ DEPOSIT_REFUND_QUERY("deposit/refundquery"), /** * 公眾號純簽約 */ ENTRUST_WEB("/papay/entrustweb"), /** * 公眾號純簽約(服務商模式) */ PARTNER_ENTRUST_WEB("/papay/partner/entrustweb"), /** * APP純簽約 */ PRE_ENTRUST_WEB("/papay/preentrustweb"), /** * APP純簽約(服務商模式) */ PARTNER_PRE_ENTRUST_WEB("/papay/partner/preentrustweb"), /** * H5純簽約 */ H5_ENTRUST_WEB("/papay/h6entrustweb"), /** * H5純簽約(服務商模式) */ PARTNER_H5_ENTRUST_WEB("/papay/partner/h6entrustweb"), /** * 支付中簽約 */ PAY_CONTRACT_ORDER("/pay/contractorder"), /** * 查詢簽約關系 */ QUERY_ENTRUST_CONTRACT("/papay/querycontract"), /** * 查詢簽約關系(服務商模式) */ PARTNER_QUERY_ENTRUST_CONTRACT("/papay/partner/querycontract"), /** * 代扣申請扣款 */ PAP_PAY_APPLY("/pay/pappayapply"), /** * 代扣申請扣款(服務商模式) */ PARTNER_PAP_PAY_APPLY("/pay/partner/pappayapply"), /** * 查詢代扣訂單 */ PAP_ORDER_QUERY("/pay/paporderquery"), /** * 查詢代扣訂單 */ PARTNER_PAP_ORDER_QUERY("/pay/partner/paporderquery"), /** * 代扣申請解約 */ DELETE_ENTRUST_CONTRACT("/papay/deletecontract"), /** * 代扣申請解約(服務商模式) */ PARTNER_DELETE_ENTRUST_CONTRACT("/papay/partner/deletecontract"), /** * 刷臉支付 */ FACE_PAY("/pay/facepay"), /** * 查詢刷臉支付訂單 */ FACE_PAY_QUERY("/pay/facepayqueryy"), /** * 撤銷刷臉支付訂單 */ FACE_PAY_REVERSE("/secapi/pay/facepayreverse"), /** * 小微商戶申請入駐 */ MICRO_SUBMIT("/applyment/micro/submit"), /** * 查詢申請狀態(tài) */ GET_MICRO_SUBMIT_STATE("/applyment/micro/getstate"), /** * 提交升級申請 */ MICRO_SUBMIT_UPGRADE("/applyment/micro/submitupgrade"), /** * 查詢升級申請單狀態(tài) */ GET_MICRO_UPGRADE_STATE("/applyment/micro/getupgradestate"), /** * 查詢提現(xiàn)狀態(tài) */ QUERY_AUTO_WITH_DRAW_BY_DATE("/fund/queryautowithdrawbydate"), /** * 修改結算銀行卡 */ MICRO_MODIFY_ARCHIVES("/applyment/micro/modifyarchives"), /** * 重新發(fā)起提現(xiàn) */ RE_AUTO_WITH_DRAW_BY_DATE("/fund/reautowithdrawbydate"), /** * 修改聯(lián)系信息 */ MICRO_MODIFY_CONTACT_INFO("/applyment/micro/modifycontactinfo"), /** * 小微商戶關注功能配置 */ ADD_RECOMMEND_CONF("/secapi/mkt/addrecommendconf"), /** * 小微商戶開發(fā)配置新增支付目錄 */ ADD_SUB_DEV_CONFIG("/secapi/mch/addsubdevconfig"), /** * 小微商戶開發(fā)配置查詢 */ QUERY_SUB_DEV_CONFIG("/secapi/mch/querysubdevconfig"); /** * 類型 */ private final String type; WxApiType(String type) { this.type = type; } public String getType() { return type; } }
同時支持任意接口任意域名的切換,為跨城冗災打下良好基礎
/** * 獲取接口請求的 URL * * @param wxApiType {@link WxApiType} 支付 API 接口枚舉 * @return {@link String} 返回完整的接口請求URL */ public static String getReqUrl(WxApiType wxApiType) { return getReqUrl(wxApiType, null, false); } /** * 獲取接口請求的 URL * * @param wxApiType {@link WxApiType} 支付 API 接口枚舉 * @param isSandBox 是否是沙箱環(huán)境 * @return {@link String} 返回完整的接口請求URL */ public static String getReqUrl(WxApiType wxApiType, boolean isSandBox) { return getReqUrl(wxApiType, null, isSandBox); } /** * 獲取接口請求的 URL * * @param wxApiType {@link WxApiType} 支付 API 接口枚舉 * @param wxDomain {@link WxDomain} 支付 API 接口域名枚舉 * @param isSandBox 是否是沙箱環(huán)境 * @return {@link String} 返回完整的接口請求URL */ public static String getReqUrl(WxApiType wxApiType, WxDomain wxDomain, boolean isSandBox) { if (wxDomain == null) { wxDomain = WxDomain.CHINA; } return wxDomain.getType() .concat(isSandBox ? WxApiType.SAND_BOX_NEW.getType() : "") .concat(wxApiType.getType()); }
這里構建請求參數(shù)使用的是 Lombok + Java 反射機制來實現(xiàn)。
BaseModel 實現(xiàn)將 Lombok builder 后對象中的屬性以及值轉為 Map并提供創(chuàng)建簽名的方法自動生成 sign (同時支持 MD5 以及 HMAC-SHA256)。以微信支付中的統(tǒng)一下單為例代碼如下
public class BaseModel { /** * 將建構的 builder 轉為 Map * * @return 轉化后的 Map */ public Map<String, String> toMap() { String[] fieldNames = getFiledNames(this); HashMap<String, String> map = new HashMap<String, String>(fieldNames.length); for (int i = 0; i < fieldNames.length; i++) { String name = fieldNames[i]; String value = (String) getFieldValueByName(name, this); if (StrUtil.isNotEmpty(value)) { map.put(name, value); } } return map; } /** * 構建簽名 Map * * @param partnerKey API KEY * @param signType {@link SignType} 簽名類型 * @return 構建簽名后的 Map */ public Map<String, String> createSign(String partnerKey, SignType signType) { return createSign(partnerKey,signType,true); } /** * 構建簽名 Map * * @param partnerKey API KEY * @param signType {@link SignType} 簽名類型 * @param haveSignType 簽名是否包含 sign_type 字段 * @return 構建簽名后的 Map */ public Map<String, String> createSign(String partnerKey, SignType signType, boolean haveSignType) { return WxPayKit.buildSign(toMap(), partnerKey, signType,haveSignType); } /** * 獲取屬性名數(shù)組 * * @param obj 對象 * @return 返回對象屬性名數(shù)組 */ public String[] getFiledNames(Object obj) { Field[] fields = obj.getClass().getDeclaredFields(); String[] fieldNames = new String[fields.length]; for (int i = 0; i < fields.length; i++) { fieldNames[i] = fields[i].getName(); } return fieldNames; } /** * 根據屬性名獲取屬性值 * * @param fieldName 屬性名稱 * @param obj 對象 * @return 返回對應屬性的值 */ public Object getFieldValueByName(String fieldName, Object obj) { try { String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = new StringBuffer().append("get") .append(firstLetter) .append(fieldName.substring(1)) .toString(); Method method = obj.getClass().getMethod(getter, new Class[]{}); return method.invoke(obj, new Object[]{}); } catch (Exception e) { return null; } } }
UnifiedOrderModel 微信統(tǒng)一下單
/** * <p>IJPay 讓支付觸手可及,封裝了微信支付、支付寶支付、銀聯(lián)支付常用的支付方式以及各種常用的接口。</p> * * <p>不依賴任何第三方 mvc 框架,僅僅作為工具使用簡單快速完成支付模塊的開發(fā),可輕松嵌入到任何系統(tǒng)里。 </p> * * <p>IJPay 交流群: 723992875</p> * * <p>Node.js 版: https://gitee.com/javen205/TNW</p> * * <p>統(tǒng)一下單 Model</p> * * @author Javen */ package com.ijpay.wxpay.model; import com.ijpay.core.model.BaseModel; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @Builder @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter public class UnifiedOrderModel extends BaseModel { private String appid; private String mch_id; private String sub_appid; private String sub_mch_id; private String device_info; private String nonce_str; private String sign; private String sign_type; private String body; private String detail; private String attach; private String out_trade_no; private String fee_type; private String total_fee; private String spbill_create_ip; private String time_start; private String time_expire; private String goods_tag; private String notify_url; private String trade_type; private String product_id; private String limit_pay; private String openid; private String sub_openid; private String receipt; private String scene_info; }
UnifiedOrderModel 中是熟悉字段完全來自官方接口文檔。遺憾的是 Model 不能遵守小駝峰式命名規(guī)則。
MD5 以及 HMAC-SHA256 簽名算法實現(xiàn)使用的是 Hutool 提供的工具類來實現(xiàn)
public static String hmacSha256(String data, String key) { return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(data, CharsetUtil.UTF_8); } public static String md5(String data) { return SecureUtil.md5(data); }
構建簽名邏輯如下
/** * 構建簽名 * * @param params 需要簽名的參數(shù) * @param partnerKey 密鑰 * @param signType 簽名類型 * @return 簽名后的 Map */ public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType) { return buildSign(params,partnerKey,signType,true); } /** * 構建簽名 * * @param params 需要簽名的參數(shù) * @param partnerKey 密鑰 * @param signType 簽名類型 * @param haveSignType 簽名是否包含 sign_type 字段 * @return 簽名后的 Map */ public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType, boolean haveSignType) { if(haveSignType){ params.put(FIELD_SIGN_TYPE, signType.getType()); } String sign = createSign(params, partnerKey, signType); params.put(FIELD_SIGN, sign); return params; } /** * 生成簽名 * * @param params 需要簽名的參數(shù) * @param partnerKey 密鑰 * @param signType 簽名類型 * @return 簽名后的數(shù)據 */ public static String createSign(Map<String, String> params, String partnerKey, SignType signType) { if (signType == null) { signType = SignType.MD5; } // 生成簽名前先去除sign params.remove(FIELD_SIGN); String tempStr = PayKit.createLinkString(params); String stringSignTemp = tempStr + "&key=" + partnerKey; if (signType == SignType.MD5) { return md5(stringSignTemp).toUpperCase(); } else { return hmacSha256(stringSignTemp, partnerKey).toUpperCase(); } }
通過上面的封裝后不到 20 行代碼就可以通過 Model 構建出微信支付接口所需要的 xml 數(shù)據
WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig(); Map<String, String> params = UnifiedOrderModel .builder() .appid(wxPayApiConfig.getAppId()) .mch_id(wxPayApiConfig.getMchId()) .nonce_str(WxPayKit.generateStr()) .body("IJPay 讓支付觸手可及-公眾號支付") .attach("Node.js 版:https://gitee.com/javen205/TNW") .out_trade_no(WxPayKit.generateStr()) .total_fee("1000") .spbill_create_ip(ip) .notify_url(notifyUrl) .trade_type(TradeType.JSAPI.getTradeType()) .openid(openId) .build() .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256); String xml = WxPayKit.toXml(params); log.info(xml);
由于篇幅原因這里不做詳細介紹,請參考 擴展 Http 請求
這里常見的問題就是預付訂單二次簽名異常以及喚起支付提示各種配置錯誤,比如授權目錄沒有配置
預付訂單二次簽名封裝
/** * <p>公眾號支付-預付訂單再次簽名</p> * <p>注意此處簽名方式需與統(tǒng)一下單的簽名類型一致</p> * * @param prepayId 預付訂單號 * @param appId 應用編號 * @param partnerKey API Key * @param signType 簽名方式 * @return 再次簽名后的 Map */ public static Map<String, String> prepayIdCreateSign(String prepayId, String appId, String partnerKey, SignType signType) { Map<String, String> packageParams = new HashMap<String, String>(6); packageParams.put("appId", appId); packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis())); packageParams.put("package", "prepay_id=" + prepayId); if (signType == null) { signType = SignType.MD5; } packageParams.put("signType", signType.getType()); String packageSign = WxPayKit.createSign(packageParams, partnerKey, signType); packageParams.put("paySign", packageSign); return packageParams; } /** * <p>APP 支付-預付訂單再次簽名</p> * <p>注意此處簽名方式需與統(tǒng)一下單的簽名類型一致</p> * * @param appId 應用編號 * @param partnerId 商戶號 * @param prepayId 預付訂單號 * @param partnerKey API Key * @param signType 簽名方式 * @return 再次簽名后的 Map */ public static Map<String, String> appPrepayIdCreateSign(String appId, String partnerId, String prepayId, String partnerKey, SignType signType) { Map<String, String> packageParams = new HashMap<String, String>(8); packageParams.put("appid", appId); packageParams.put("partnerid", partnerId); packageParams.put("prepayid", prepayId); packageParams.put("package", "Sign=WXPay"); packageParams.put("noncestr", String.valueOf(System.currentTimeMillis())); packageParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); if (signType == null) { signType = SignType.MD5; } String packageSign = createSign(packageParams, partnerKey, signType); packageParams.put("sign", packageSign); return packageParams; } /** * <p>小程序-預付訂單再次簽名</p> * <p>注意此處簽名方式需與統(tǒng)一下單的簽名類型一致</p> * * @param appId 應用編號 * @param prepayId 預付訂單號 * @param partnerKey API Key * @param signType 簽名方式 * @return 再次簽名后的 Map */ public static Map<String, String> miniAppPrepayIdCreateSign(String appId, String prepayId, String partnerKey, SignType signType) { Map<String, String> packageParams = new HashMap<String, String>(6); packageParams.put("appId", appId); packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis())); packageParams.put("package", "prepay_id=" + prepayId); if (signType == null) { signType = SignType.MD5; } packageParams.put("signType", signType.getType()); String packageSign = createSign(packageParams, partnerKey, signType); packageParams.put("paySign", packageSign); return packageParams; }
具體使用案例請參考 IJPay-Demo-SpringBoot
目前微信支付異步通知有兩種:支付結果異步通知、微信退款異步通知
注意事項: 1、及時響應對應的應答 2、異步通知需要根據訂單號做去重處理 3、支付結果的異步通知簽名方法必須與統(tǒng)一下單的簽名方式保持一致 4、微信退款異步通知出現(xiàn) java.security.InvalidKeyException: Illegal key size
異常 解決方案
/** * 支付異步通知時校驗 sign * * @param params 參數(shù) * @param partnerKey 支付密鑰 * @param signType {@link SignType} * @return */ public static boolean verifyNotify(Map<String, String> params, String partnerKey, SignType signType) { String sign = params.get("sign"); String localSign = createSign(params, partnerKey, signType); return sign.equals(localSign); }
微信支付結果異步通知業(yè)務處理邏輯的偽代碼
/** * 異步通知 */ @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String payNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("支付通知=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // 注意重復通知的情況,同一訂單號可能收到多次通知,請注意一定先判斷訂單狀態(tài) // 注意此處簽名方式需與統(tǒng)一下單的簽名類型一致 if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) { if (WxPayKit.codeIsOk(returnCode)) { // 更新訂單信息 // 發(fā)送通知等 Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } } return null; }
微信退款數(shù)據解密詳細步驟請參考官方文檔,以下是使用 Hutool 提供 SecureUtil 實現(xiàn)
/** * AES 解密 * * @param base64Data 需要解密的數(shù)據 * @param key 密鑰 * @return 解密后的數(shù)據 */ public static String decryptData(String base64Data, String key) { return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data); }
微信退款通知業(yè)務處理邏輯的偽代碼
/** * 退款通知 */ @RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String refundNotify(HttpServletRequest request) { String xmlMsg = HttpKit.readData(request); log.info("退款通知=" + xmlMsg); Map<String, String> params = WxPayKit.xmlToMap(xmlMsg); String returnCode = params.get("return_code"); // 注意重復通知的情況,同一訂單號可能收到多次通知,請注意一定先判斷訂單狀態(tài) if (WxPayKit.codeIsOk(returnCode)) { String reqInfo = params.get("req_info"); String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey()); log.info("退款通知解密后的數(shù)據=" + decryptData); // 更新訂單信息 // 發(fā)送通知等 Map<String, String> xml = new HashMap<String, String>(2); xml.put("return_code", "SUCCESS"); xml.put("return_msg", "OK"); return WxPayKit.toXml(xml); } return null; }
到此,相信大家對“微信支付接入步驟”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!
當前名稱:微信支付接入步驟
網站鏈接:http://jinyejixie.com/article4/gdphoe.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供域名注冊、定制開發(fā)、標簽優(yōu)化、企業(yè)網站制作、、ChatGPT
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)