原文链接:使用wechatpay-apache-httpclient接入微信ApiV3详细步骤
接入微信支付,要有微信商家平台账号(登录注册地址),微信公众平台账号(登录注册地址),本文使用微信小程序完成接入。
一、生成商家证书
首先登录微信商家平台,进入"账户中心-->账户设置-->API安全",申请API证书(此证书为商户证书,跟下文的APIV3支付证书不一样),下载安装方式见官方文档:什么是商户API证书?如何获取商户API证书? (qq.com)
经过上面链接中的教程,你将会在本地得到如下三个文件:
我们将在下面用到这几个文件中的apiclient_key.pem
二、生成APIV3支付证书
这一步至关重要,因为很多人接入的时候由于官方文档写的很笼统而忽略此步,再调用API的时候错误的使用第一步中生成的证书,导致签名验证微信返回的内容时不成功,而爆出如下的错误:应答的微信支付签名验证失败
关于这个错误,其实只需要按照本文的此步生成APIV3的支付证书即可。
1、下载APIV3证书生成工具
在这里下载jar包
2、执行命令生成V3证书
执行:“java -jar CertificateDownloader-1.1.jar -f 商户私钥文件路径 -k 证书解密的密钥 -m 商户号 -o 证书保存路径 -s 商户证书序列号”就行了。
这条命令的参数搞清楚3点:
a)“商户私钥文件路径”是账号中心->API安全->API证书中设置并下载的证书(就是其中的apiclient_key.pem,下载还会获得apiclient_cert.pem,我之前把这个当做支付证书了,其实不是,apiclient_cert.pem这用不着)
b)“商户证书序列号”这个东西也是设置API证书那里知道;
c)“证书解密的密钥”在账号中心->API安全->APIv3密钥中设置的(注意api密钥和apiv3密钥是2个东西)。
执行完了是个类似wechatpay_267E31F15F097EC70CC6B6C56919D2605966123D.pem的文件。
三、Java接入实现预订单生成
1、将wechatpay-apache-httpclient引入maven
<!-- 微信支付API -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.4</version>
</dependency>
其他方式引入方式以及最新版本的依赖参见官方仓库
2、自己创建一个微信支付工具类
package com.xxx.xxxx.utils.pay.wechat;
import com.alibaba.fastjson.JSONObject;
import com.xxx.xxxx.config.wechat.WeChatConfig;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@Component
public class WXPayUtils {
@Autowired
private WeChatConfig weChatConfig;
private static final String APPLICATION_JSON = "application/json";
private static final String mchId = "商户号"; // 商户号
private static final String mchSerialNo = "第一步申请完证书后,在API证书哪里点击管理证书就能看到"; // 商户证书序列号
private static final String requestBody = "{\n"
+ " \"stock_id\": \"9433645\",\n"
+ " \"stock_creator_mchid\": \"1900006511\",\n"
+ " \"out_request_no\": \"20190522_001中文11\",\n"
+ " \"appid\": \"wxab8acb865bb1637e\"\n"
+ "}";
// 你的商户私钥
private static final String privateKey = "第一步中生成的apiclient_key.pem内容";
// 你的微信支付平台证书
private static final String certificate = "第二步中生成的wechatpay_267E31F15F097EC70CC6B6C56919D2605966123D.pem内容";
private CloseableHttpClient httpClient;
public void setup() {
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
X509Certificate wechatPayCertificate = PemUtil.loadCertificate(
new ByteArrayInputStream(certificate.getBytes(StandardCharsets.UTF_8)));
ArrayList<X509Certificate> listCertificates = new ArrayList<>();
listCertificates.add(wechatPayCertificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchId,mchSerialNo, PemUtil.loadPrivateKey(privateKey))
.withWechatPay(listCertificates);
httpClient = builder.build();
}
/**
*wxMchid商户号
*wxCertno证书编号
*wxCertPath证书地址
*wxPaternerKey v3秘钥
*url jsapi下单地址
*body 构造好的消息体
*/
public JSONObject doPostWexinV3(String url, String body) {
if (httpClient == null) {
setup();
}
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type","application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
try{
if(body==null){
throw new IllegalArgumentException("data参数不能为空");
}
StringEntity stringEntity = new StringEntity(body,"utf-8");
httpPost.setEntity(stringEntity);
// 直接执行execute方法,官方会自动处理签名和验签,并进行证书自动更新
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if(httpResponse.getStatusLine().getStatusCode() == 200){
String jsonResult = EntityUtils.toString(httpEntity);
return JSONObject.parseObject(jsonResult);
}else{
System.err.println("微信支付错误信息"+EntityUtils.toString(httpEntity));
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
3、编写测试方法,调用微信V3接口生成预支付订单号
package com.xxx.xxx;
import com.alibaba.fastjson.JSONObject;
import com.xxxx.x.utils.pay.wechat.WXPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* 参考文档: https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao
* 小程序支付: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
*/
@SpringBootTest
@Slf4j
public class TestWXOrderClass {
@Autowired
private WXPayUtils wxPayUtils;
@Test
public void testPay() {
JSONObject jsonObject = buildWxJsApiPayJson('你的公众平台小程序等appid', '商户id', "测试商品描述",
"20220304215501111", "https://www.baidu.com", "2",
"用户在你的公众平台下的唯一标识,登录后能获取");
JSONObject jsonObject1 = wxPayUtils.doPostWexinV3("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi", jsonObject.toJSONString());
System.out.println(jsonObject1.toJSONString());
}
/**
* 构造微信JsApi付款的json
* @param appid
* @param mchid
* @param description
* @param out_trade_no
* @param notify_url
* @param amount
* @return
*/
public JSONObject buildWxJsApiPayJson(String appid , String mchid ,
String description ,
String out_trade_no ,
String notify_url ,
String amount,
String openId){
//订单金额json
JSONObject amountJson = new JSONObject();
amountJson.put("total",Integer.valueOf(amount));
amountJson.put("currency","CNY");
//支付者json
JSONObject payerJson = new JSONObject();
payerJson.put("openid",openId);
//基础信息json
JSONObject json = new JSONObject();
json.put("appid",appid);
json.put("mchid",mchid);
json.put("description",description);
json.put("out_trade_no",out_trade_no);
json.put("notify_url",notify_url);
json.put("amount",amountJson);
json.put("payer",payerJson);
return json;
}
}
好了,通过上面步骤就能完整生成微信预支付订单,如果有问题请下面留言,或者加我微信号:gpf_18253
补充:漏掉了一个config类,在此补上:
package com.****.****.config.wechat;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
/**
* 微信相关配置类
*/
@Data
@Slf4j
@Configuration
public class WeChatConfig {
/**
* 预支付订单url
*/
private String preOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
/**
* 商户号id
*/
@Value("${pay.wechat.mchId}")
private String mchId;
/**
* 微信支付回调url
*/
@Value("${pay.wechat.payCallbackUrl}")
private String payCallbackUrl;
/**
* 微信appid
*/
@Value("${pay.wechat.appId}")
private String appid;
/**
* 微信APIV3支付证书
*/
@Value("${pay.wechat.certUrl}")
private String certUrl;
/**
* 商家密钥
*/
@Value("${pay.wechat.privateKeyUrl}")
private String privateKeyUrl;
/**
* 商家密钥
*/
@Value("${pay.wechat.mchSerialNo}")
private String mchSerialNo;
/**
* appV3 key
*/
@Value("${pay.wechat.appV3Key}")
private String appV3Key;
/**
* 获取微信支付api V3支付证书
* @return
*/
public X509Certificate getCertificate() {
try {
return PemUtil.loadCertificate(new FileInputStream(certUrl));
} catch (FileNotFoundException e) {
log.error("加载微信支付APIv3支付证书失败{}", e.getMessage(), e);
}
return null;
}
public PrivateKey getPrivateKey() {
try {
return PemUtil.loadPrivateKey(new FileInputStream(privateKeyUrl));
} catch (FileNotFoundException e) {
log.error("加载微信支付APIv3支付证书失败{}", e.getMessage(), e);
}
return null;
}
}
下面连接为微信支付接入前后端完整步骤(三篇文章)超级IT人生https://mp.weixin.qq.com/s/DFXwevYIQJA0ki5MYGtArg