可能会遇到的问题:
1.apiclient_key.pem (No such file or directory)
2.apiclient_key.pem] cannot be resolved to URL because it does not exist
3.Illegal key size (javaSDK的版本问题,文章末尾)
1. 支付前各种账号准备参考官方文档
2.使用官方推荐的wechatpay-java
3.wechatpat-java地址是github项目,内包含Maven依赖
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.10</version>
</dependency>
4.官方示例是以 Native 支付为例,我已小程序为例吧。
5.自动更新微信支付平台证书
官方提供使用自动更新和使用本地证书,但本地证书使用不当会出现证书对不上,抛异常,无法支付,所以这里推荐使用自动更新,为了提高性能,建议将配置类作为全局变量,但要慎重,这个操作有难度,初期对接先不要考虑。(最下面注意事项有本地证书使用的官方文档链接)
Config config =
new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
6.现在java环境下大家都是打jar包,大多数人会把密钥放到项目下,最常见的就是在服务器无法获得密钥文件,解决方法:
获取文件(方式多种,此次提供一种),通过文件流创建临时文件。
注意:如果你是本地文件,那么其实主要是参数.apiV3Key 与.wechatPayCertificatesFromPath的差异,我这里的拷贝文件其实是多余的。
public JsapiService init(){
JsapiService service = null;
try {
ClassPathResource keyPath = new ClassPathResource("cert/apiclient_key.pem");
File keyFile = new File("apiclient_key.pem");
FileUtils.copyInputStreamToFile(keyPath.getInputStream(),keyFile);
Config config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath("apiclient_key.pem")
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
service = new JsapiService.Builder().config(config).build();
} catch (HttpException e) { // 发送HTTP请求失败
// 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
} catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
// 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
} catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
// 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
} catch (IOException e) {
throw new RuntimeException(e);
}
return service;
}
7.定义了JsapiService其实就可以通过调用SDK里面的prepay进行统一下单了。
public String prepay(BigDecimal price, String orderId,String openId) {
PrepayRequest request = new PrepayRequest();
request.setAppid(appID);
request.setMchid(merchantId);
request.setDescription("商城");
request.setOutTradeNo(orderId);
request.setNotifyUrl("https://");
// 订单金额
Amount amount = new Amount();
BigDecimal total = price.multiply(new BigDecimal(100));
amount.setTotal(total.intValue());
amount.setCurrency("CNY");
request.setAmount(amount);
//支付者
Payer payer = new Payer();
payer.setOpenid(openId);
request.setPayer(payer);
return init().prepay(request).getPrepayId();
}
关闭订单,查询订单都类似。
8.接下来是前端调起支付的签名问题。
我这里写了个小程序的,其他的也都很类似,jsapi支付可直接使用。
按官方签名规则进行RSA和Base64。
public RequestPaymentVo getSigner(RequestPaymentVo requestPaymentVo) {
try{
ClassPathResource keyPath = new ClassPathResource("cert/apiclient_key.pem");
File keyFile = new File("apiclient_key.pem");
FileUtils.copyInputStreamToFile(keyPath.getInputStream(),keyFile);
PrivateKey privateKeyPath = PemUtil.loadPrivateKeyFromPath("apiclient_key.pem");
String message = requestPaymentVo.getAppId() + "\n"
+ requestPaymentVo.getTimeStamp() + "\n"
+ requestPaymentVo.getNonceStr() + "\n"
+ requestPaymentVo.getPrepayId() + "\n";
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privateKeyPath);
sign.update(message.getBytes());
requestPaymentVo.setPaySign(Base64.getEncoder().encodeToString(sign.sign()));
} catch (Exception e) {
e.printStackTrace();
}
return requestPaymentVo;
}
9.接下来就是注意事项,由于加密方式不同,所以对官方在文档最后是有提示的。
https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay7_2.shtml
接下来是遇到的问题:
1.社区有朋友针对提出下载与本地证书,评论区有沟通方式及官方地址,大家可以做参考
2.本地证书会涉及解密保存,官方文档解密内容
https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml
3.找不到证书文件的社区提问
https://developers.weixin.qq.com/community/pay/doc/00022cac9fc940656b20bab8a61000