简述
相信很多小伙伴都对接过支付,最常见的莫过于支付宝支付和微信支付,但二者相差的不是一星半点;两个平台对接下来,给我的感觉就是,支付宝在想办法让我们开发变得简单;而微信似乎怕我们盗取了它的技术一样,把各种事弄得复杂,找技术客服问就是各种给人发文档;虽然微信已经提供了sdk,但是官网demo有些示例是错的,有些东西也不告诉你怎么用,这不,我这付款是正常的,退款就报错,关键是钱还给退了,回调也是退款成功,虽然说事儿是干成了,但咱身为程序猿,总不能放着异常不管吧,这不,绞尽脑汁,终于解决了报错。特此分享,让后面的小伙伴们少走弯路。
话不多说,咱们直接开始!
- 我的退款代码(参照官方demo):
// 初始化商户配置
RSAConfig config = new RSAConfig.Builder()
.merchantId(MCHID) // 商户id
.privateKeyFromPath(PRIVATE_KEY_PATH) // 商户私钥文件路径
.merchantSerialNumber(SERIAL_NO) // 商户证书序列号
.wechatPayCertificatesFromPath(APICLIENT_CERT_PATH) // 商户证书路径
.build();
// 初始化服务
refundService = new RefundService.Builder().config(config).build();
CreateRequest createRequest = new CreateRequest();
.
. // 业务参数此处省略
.
Refund refundResult = refundService.create(createRequest);
相信很多小伙伴也是像我这么用的,当然这么用常规情况是没问题的,我用的证书和私钥也都是微信商户平台下载的;但问题就是证书现在会过期,需要我们自己去更新(这里可以参考微信官方证书相关文档),不然退款等需要证书的接口调用的时候就会报ValidationException(我就是上了这个鬼当了😭😭):
com.wechat.pay.java.core.exception.ValidationException: Validate response failed,the WechatPay signature is incorrect.
- 获取最新证书,参考微信官方demo
先看官方demo代码:
public static void main(String[] args) {
// 初始化商户配置
RSAConfig rsaConfig =
new RSAConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.wechatPayCertificatesFromPath(wechatPayCertificatePath)
.build();
// 初始化证书服务
service = new CertificateService.Builder().config(rsaConfig).build();
// 设置商户apiV3密钥,apiV3密钥用于解密下载证书
// ... 调用接口
}
/** 下载证书 */
public static List<X509Certificate> downloadCertificate() {
return service.downloadCertificate(apiV3Key.getBytes(StandardCharsets.UTF_8));
}
代码中,RSAConfig需要配置四个参数,其中包含证书文件路径,但我现在证书是过期了的,这样不会报ValidationException吧,然而结果就是该报还是会报😂😂;就微信官方demo都在搞事情呗🤣🤣,于是我就想啊、想啊,查啊、查啊;灵光一闪,既然这里给了证书就报异常,那我不给呢,于是就把RSAConfig换成了RSAAutoCertificateConfig,相比之下后者不需要传入证书路径,但需要传入密钥,这样就能顺利拿到证书了,代码如下:
// 初始化商户配置
Config rsaConfig =
new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 初始化证书服务
service = new CertificateService.Builder().config(rsaConfig).build();
// 设置商户apiV3密钥,apiV3密钥用于解密下载证书
// ... 调用接口
List<X509Certificate> certs = service.downloadCertificate(apiV3Key.getBytes(StandardCharsets.UTF_8));
现在我们拿到证书了,但是X509Certificate这个玩意儿还不能直接用,需要转换为.pem文件才能使用,这里我们可以转换为字符串,之后写入文件保存服务器,官方的建议是定时去更新证书,我问了微信支付客服,客服建议大于12小时更新一次;于是我24小时更新一次。更新代码如下:
StringWriter sw = new StringWriter();
try (PEMWriter pw = new PEMWriter(sw)) {
pw.writeObject(certs.get(0)); // 取接口获取到的证书内容
}
File file = new File(APICLIENT_CERT_PATH); // 服务器存放证书的文件路径
fileWriter = new FileWriter(file);
fileWriter.write(sw.toString());
fileWriter.flush();
fileWriter.close();
我的上述代码是放在定时任务中之行,每天执行一次更新证书,做完这些,退款等需要证书的接口就能恢复正常啦🥳🥳