无论是个人还是企业,业务变现,除了广告最好的方式就是支付收款。我们经常使用的微信支付如何快速完成技术对接呢?如何同时支持国内支付与境外支付呢?如何做跨城冗灾呢?干货多屁话少 ,接下来慢慢聊。

文章目录

  • 接入步骤
  • 获取微信支付接口 URL
    • 微信域名
    • 微信支付常用接口
    • 获取完整URL 方案
  • 构建请求参数
    • Model 构建实现机制
    • 封装 Model 自动生成签名
    • 签名算法实现
    • 通过 Model 构建 xml 数据
  • 发起请求
  • 唤起支付
  • 支付异步通知
    • 验证签名封装
    • 微信退款数据解密

接入步骤

微信支付接入大概步骤如下:
1、获取支付接口 URL
2、构建请求参数
3、发起请求
4、唤起支付
5、支付异步通知处理

步骤一中获取支付接口 URL,需要考虑这几点

1、如何同时支持国内微信支付与境外微信支付
2、如何同时支持普通的商户模式以及服务商模式

步骤二中经常遇到的问题就是参数签名验证问题

1、MD5 加密
2、HMAC-SHA256 加密

步骤三中难点在于微信支付双向证书的处理

步骤四中预付订单二次签名异常以及唤起支付提示各种配置错误

步骤五中异步通知验证签名、订单重复通知以及敏感数据的解密问题

以上接入步骤中,你踩过那些坑呢?欢迎评论区分享交流

Talk is cheap. Show me the code

获取微信支付接口 URL

有人会说「这不很简单么」官方文档接口中就有提供。对你说的没错,那如何做到一套系统同时支持国内微信支付与境外微信支付,又如何做跨城冗灾方案呢?

微信域名

根据业务区域的不同微信提供了不同的域名来支持

  • 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(特殊:仿真测试)

聪明的你,不难就会想到枚举,具体跨城冗灾方案可以参考微信支付商户系统跨城冗灾升级指引

/*** <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>** <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </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支付、小程序支付、红包、企业付款、酒店押金、刷脸支付常用的支付方式以及支付工具不完全统计接口大概有 90+

package com.ijpay.wxpay.enums;/*** <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>** <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>** <p>IJPay 交流群: 723992875</p>** <p>Node.js 版: https://gitee.com/javen205/TNW</p>** <p>微信支付接口枚举</p>** @author Javen*/
public enum WxApiType {/*** 沙箱环境*/SAND_BOX_NEW("/sandboxnew"),/*** 获取沙箱环境验签秘钥*/GET_SIGN_KEY("/sandboxnew/pay/getsignkey"),/*** 统一下单*/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"),/*** 拉取订单评价数据*/BATCH_QUERY_COMMENT("/billcommentsp/batchquerycomment"),/*** 企业付款*/TRANSFER("/mmpaymkttransfers/promotion/transfers"),/*** 查询企业付款*/GET_TRANSFER_INFO("/mmpaymkttransfers/gettransferinfo"),/*** 企业付款到银行卡*/TRANSFER_BANK("/mmpaysptrans/pay_bank"),/*** 查询企业付款到银行卡*/GET_TRANSFER_BANK_INFO("/mmpaysptrans/query_bank"),/*** 获取 RSA 加密公钥*/GET_PUBLIC_KEY("/risk/getpublickey"),/*** 发放红包*/SEND_RED_PACK("/mmpaymkttransfers/sendredpack"),/*** 发放裂变红包*/SEND_GROUP_RED_PACK("/mmpaymkttransfers/sendgroupredpack"),/*** 查询红包记录*/GET_HB_INFO("/mmpaymkttransfers/gethbinfo"),/*** 小程序发红包*/SEND_MINI_PROGRAM_HB("/mmpaymkttransfers/sendminiprogramhb"),/*** 发放代金券*/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/h5entrustweb"),/*** H5纯签约(服务商模式)*/PARTNER_H5_ENTRUST_WEB("/papay/partner/h5entrustweb"),/*** 支付中签约*/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"),/*** 查询申请状态*/GET_MICRO_SUBMIT_STATE("/applyment/micro/getstate"),/*** 提交升级申请*/MICRO_SUBMIT_UPGRADE("/applyment/micro/submitupgrade"),/*** 查询升级申请单状态*/GET_MICRO_UPGRADE_STATE("/applyment/micro/getupgradestate"),/*** 查询提现状态*/QUERY_AUTO_WITH_DRAW_BY_DATE("/fund/queryautowithdrawbydate"),/*** 修改结算银行卡*/MICRO_MODIFY_ARCHIVES("/applyment/micro/modifyarchives"),/*** 重新发起提现*/RE_AUTO_WITH_DRAW_BY_DATE("/fund/reautowithdrawbydate"),/*** 修改联系信息*/MICRO_MODIFY_CONTACT_INFO("/applyment/micro/modifycontactinfo"),/*** 小微商户关注功能配置*/ADD_RECOMMEND_CONF("/secapi/mkt/addrecommendconf"),/*** 小微商户开发配置新增支付目录*/ADD_SUB_DEV_CONFIG("/secapi/mch/addsubdevconfig"),/*** 小微商户开发配置查询*/QUERY_SUB_DEV_CONFIG("/secapi/mch/querysubdevconfig");/*** 类型*/private final String type;WxApiType(String type) {this.type = type;}public String getType() {return type;}
}

获取完整URL 方案

同时支持任意接口任意域名的切换,为跨城冗灾打下良好基础

 /*** 获取接口请求的 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 是否是沙箱环境* @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 是否是沙箱环境* @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());}

构建请求参数

Model 构建实现机制

这里构建请求参数使用的是 Lombok + Java 反射机制来实现。

封装 Model 自动生成签名

BaseModel 实现将 Lombok builder 后对象中的属性以及值转为 Map并提供创建签名的方法自动生成 sign (同时支持 MD5 以及 HMAC-SHA256)。以微信支付中的统一下单为例代码如下

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);}/*** 获取属性名数组** @param obj 对象* @return 返回对象属性名数组*/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 微信统一下单

/*** <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>** <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>** <p>IJPay 交流群: 723992875</p>** <p>Node.js 版: https://gitee.com/javen205/TNW</p>** <p>统一下单 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 不能遵守小驼峰式命名规则。

签名算法实现

MD5 以及 HMAC-SHA256 签名算法实现使用的是 Hutool 提供的工具类来实现

 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     需要签名的参数* @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       需要签名的参数* @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     需要签名的参数* @param partnerKey 密钥* @param signType   签名类型* @return 签名后的数据*/public static String createSign(Map<String, String> params, String partnerKey, SignType signType) {if (signType == null) {signType = SignType.MD5;}// 生成签名前先去除signparams.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();}}

通过 Model 构建 xml 数据

通过上面的封装后不到 20 行代码就可以通过 Model 构建出微信支付接口所需要的 xml 数据

        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>注意此处签名方式需与统一下单的签名类型一致</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>注意此处签名方式需与统一下单的签名类型一致</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>注意此处签名方式需与统一下单的签名类型一致</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、支付结果的异步通知签名方法必须与统一下单的签名方式保持一致
4、微信退款异步通知出现 java.security.InvalidKeyException: Illegal key size 异常 解决方案

验证签名封装

/*** 支付异步通知时校验 sign** @param params     参数* @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);}

微信支付结果异步通知业务处理逻辑的伪代码

 /*** 异步通知*/@RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})@ResponseBodypublic 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");// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态// 注意此处签名方式需与统一下单的签名类型一致if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {if (WxPayKit.codeIsOk(returnCode)) {// 更新订单信息// 发送通知等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;}

微信退款数据解密

微信退款数据解密详细步骤请参考官方文档,以下是使用 Hutool 提供 SecureUtil 实现

 /*** AES 解密** @param base64Data 需要解密的数据* @param key        密钥* @return 解密后的数据*/public static String decryptData(String base64Data, String key) {return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data);}

微信退款通知业务处理逻辑的伪代码

 /*** 退款通知*/@RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})@ResponseBodypublic 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");// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态if (WxPayKit.codeIsOk(returnCode)) {String reqInfo = params.get("req_info");String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());log.info("退款通知解密后的数据=" + decryptData);// 更新订单信息// 发送通知等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;}

个人能力有限如有错误欢迎指正,如有遗漏欢迎补充。如有疑问欢迎留言一起交流讨论。

微信支付,你想知道的一切都在这里相关推荐

  1. 浅析微信支付:微信支付简单介绍(小程序、公众号、App、H5)

    本文是[浅析微信支付]系列文章的第二篇,主要讲解一下普通商户接入的支付方式以及其中的不同之处. 上篇文章讲了本系列的大纲,没有看过的朋友们可以看一下. 浅析微信支付:前篇大纲 微信支付是集成在微信客户 ...

  2. 微信支付横空出世,闲扯一番自我扫盲(转)

    首先是扫盲点: 1.  微信支付自2014年3月5号开始支付接口正式对外开放. 2.  申请者必须是认证服务号(简单来说吧,你必须有实体公司的营业执照) 3.  公司法新政策,大家可以去百度一下自我扫 ...

  3. PHP版本微信支付开发----电脑网站扫码支付(native)(心得、总结)

    早就听说微信支付比支付宝支付的坑多,但还得得该填的填,该绕的绕, 最终我们网站的微信支付功能成功上线啦♪(^ ∇ ^*) 首先自报家门,我的PHP版本是7,微信demo用的是php_sdk_v3.0. ...

  4. 微信公开课(北京站)速记 微信、微信支付、O2O的定义与关联

    本文为4月29日微信公开课(北京站)微信产品部演讲全文速记,讲述了微信官方对微信.微信支付.O2O的定义与关联等问题的看法与观点. 作者:微信产品部 刘涵涛 吴毅 去年夏天有一个全民打飞机的盛况,这实 ...

  5. 微信支付与支付宝钱包的竞争分析

    微信支付与支付宝钱包的竞争分析 NO1: 十九世纪七十年代起,"物竞天择,适者生存,优胜劣汰"已逐渐成为现代生物学的口号.而今,不知不觉中,它似乎也成了当代社会学的口号.罗素说:& ...

  6. 浅析微信支付:商户平台代金券或立减优惠开通、指定用户代金券发放、查询等

    本文是[浅析微信支付]系列文章的第十四篇,主要讲解在如何开通商户平台的代金券或立减优惠功能,商家向指定用户发送代金券,查询发送记录,代金券信息等. 浅析微信支付系列已经更新十四篇了哟-,没有看过的朋友 ...

  7. html如何自动打开手机微信支付,微信支付分正式上线!微信支付分开通教程

    原标题:微信支付分正式上线!微信支付分开通教程 [PConline资讯]腾讯最新功能悄悄上线,开通微信支付分! 相信很多朋友都不知道,微信支付分是怎么回事,更不知道如何去开通.微信支付分怎么开通?今天 ...

  8. 微信支付,JSAPI支付,APP支付,H5支付,Native支付,小程序支付功能详情以及回调处理

    一.支付相关文档地址 支付wiki:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml 支付api: https://pay.weixin.qq. ...

  9. 美团取消支付宝支付引关注,称饿了么也不支持微信支付,饿了么回应绝了

    昨日,有部分用户发现,在使用美团进行支付时已经没有支付宝的选项了.美团月付和银行卡支付占据优先位置,不再显示支付宝支付,而微信支付和Apple Pay还在支付选择列表上. 据悉,这不是美团第一次取消支 ...

  10. 微信支付服务器验证的java_Java中的微信支付(3):API V3对微信服务器响应进行签名验证...

    1. 前言 牢记一句话:公钥加密,私钥解密:私钥加签,公钥验签. 微信支付V3版本前两篇分别讲了如何对请求做签名和如何获取并刷新微信平台公钥,本篇将继续展开如何对微信支付响应结果的验签. 2. 为什么 ...

最新文章

  1. 贪污经费,撤销院士称号!
  2. latex 编译Underfull \hbox (badness 10000) in paragraph警告
  3. C++智能指针及其简单实现
  4. opengl编程从入门到精通-hello,window
  5. 熊猫TV直播H5播放器架构探索
  6. cocos2d-x for android配置 运行 Sample on Linux OS
  7. Java JVM 汇编代码入门 GitChat链接
  8. ThinkPHP6项目基操(4.拦截无效请求 控制器或方法不存在)
  9. activeti user guide 中文_【澳洲大岩石】最好季节发团!省掉800澳币!无比震撼特价 再次应约出发 震撼之旅!一生难忘!全程中文导游!省心放心澳洲青年旅行社...
  10. 如何在yml中加上git用户名和密码的验证_使用Apollo升级一下yml文件管理和发布
  11. 分享几个个人经常用到的js方法
  12. Jquery实现可拖拽的树菜单
  13. react 显示当前时间_React 灵魂 23 问,你能答对几个?
  14. 动易2007后台模板上传任意文件漏洞
  15. cad填充密度怎么调整_CAD填充技巧之填充比例
  16. Redis中的lua脚本
  17. Win7系统用键盘替代鼠标的小技巧
  18. R语言 循环 步长 写法
  19. 计算机初学者先学什么语言,计算机语言入门先学什么?
  20. Could not load the following font :pdfFontName : STSong-Light问题

热门文章

  1. case when和where
  2. 聚焦信息抽取前沿难题,CCKS-千言通用信息抽取竞赛报名启动
  3. 美国打伊拉克获得的好处多!
  4. 手机短视频应用 --用户行为分析和优化指南
  5. 神器更新/上新一款应用,以及更新一款下载神器
  6. js获取当前的年月日时分秒
  7. SAP中重复制造生产计划编制——工作中心能力
  8. 程序设计的思想(结构化编程)
  9. STM32 时钟与外设总线
  10. 二八定律,它是无标度的_第七定律,如果一个接口不能做到,它将模拟它