项目是 H5 项目,这里踩坑了,以为接入 H5 支付就可以了,后面发现 H5 支付只能在微信外调用,后面连忙加入 JSAPI支付。H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。
说明:要求商户已有H5商城网站,并且已经过ICP备案,即可申请接入。
申请开通需要3-5天
JSAPI支付
JSAPI支付是指商户通过调用微信支付提供的JSAPI接口,商户的支付场景是在微信内置浏览器打开调起支付完成收款。
接入前准备
微信支付官方的文档已经比较详细了,可以先从指引文档,基础支付入手
需要用到 appid,具体参考文档,有个公众号就可以了
就是关于商户的一些信息及证书(参考文档)
对于 JSAPI 接入,需要用到用户的 openid,需要在公众号内配置
公众号 -> 设置与开发 -> 公众号设置 -> 功能设置 -> 网页授权域名
JSAPI是在 js内调起支付,这个地方域名填写前端域名就可以了(基本上配置域名配置前端域名就可以了),配置的时候要将txt文件放到前端服务器的根目录才可以确认
需要注意的是,目前这个域名配置只能配置两个,网上的解决办法是搭个反向代理服务器
选择 SDK
在微信官方文档的指引文档中的开发指引,选择对应的 SDK
我使用的 Java 直接用第一个就可以了
Maven方式引入
初始化
需要加载商户私钥,平台证书,初始化 httpClient …
关于证书,大概有三个文件
apiclient_cert.p12
apiclient_cert.pem
apiclient_key.pem
要安装证书,windows下直接双击 apiclient_cert.p12即可,剩下的自己看需求操作,Linux自行百度
其中 apiclient_key.pem 是商户私钥
获取私钥的代码封装
/**
* 获取私钥。
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String filename) throwsIOException {
String content = newString(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGINPRIVATE KEY-----", "")
.replace("-----END PRIVATEKEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(newPKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
初始化代码如下
/** 平台证书管理器 */
private static CertificatesManager certificatesManager;
/** 商户私钥 */
private static PrivateKey privateKey;
/** 如果你是使用ApacheHttpClient的商户开发者,可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息,并检查应答的微信支付签名。*/
private static CloseableHttpClient httpClient = null;
//--- 此处参数根据自己的内容赋值
/** 商户id */
private String mchId;
/** 商户序列号 */
private String mchSerialNo;
/** api_v3_key */
private String apiV3Key;
public static void init() {
// 加载商户私钥(privateKey:私钥字符串)
privateKey = getPrivateKey("apiclient_key.pem文件地址"));
// 获取证书管理器实例
certificatesManager = CertificatesManager.getInstance();
// 向证书管理器增加需要自动更新平台证书的商户信息
certificatesManager.putMerchant(mchId, newWechatPay2Credentials(mchId,
new PrivateKeySigner(mchSerialNo, privateKey)),
apiV3Key.getBytes(StandardCharsets.UTF_8));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, privateKey)
.withValidator(newWechatPay2Validator(certificatesManager.getVerifier(mchId))).build();
}
在项目启动的时候执行 init() 初始化就可以了
不同的地方
对于后端来说,H5支付和JSAPI支付不同的地方差不多只有下单部分
下单部分有些参数不一样,以及返回不一样,还有 url 不一样,以及前端调起支付的方式不一样
查询订单,退款,支付通知这些一模一样,可以通用
下单
H5支付或者JSAPI支付,第一步是下单,下单在指引文档中都有代码示例,这里多阐述。文档内使用的是字符串追加形式拼接的参数,我们可以改为JSONObject
H5 下单比较简单,服务端下单后,响应一串 url,将这串 url 给前端,让前端跳转到此 url即可完成调用微信支付,付款
JSAPI 则需要先获取到用户 openid,带上 openid 下单