1、需要准备的数据
- 商户号
- 商户API证书的证书序列号
- 商户API私钥,如何加载商户API私钥请看常见问题。
- 微信支付平台证书。你也可以使用后面章节提到的“自动更新证书功能”,而不需要关心平台证书的来龙去脉。
# native模式的统一下单接口
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml
2、添加依赖
<!-- 微信支付 -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.2.2</version>
</dependency>
3、获取订单预付ID
package com.shenmazong.shenmacodeserver.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.*;
import java.security.PrivateKey;
/**
* @author 军哥
* @version 1.0
* @description: TODO
* @date 2021/8/23 20:42
*/
@Configuration
public class WeiXinPayConfig {
/**
* 商户号
*/
@Value("${weixin.merchantId}")
private String merchantId;
/**
* 商户API私钥
*/
@Value("${weixin.merchantSerialNumber}")
private String merchantSerialNumber;
/**
* 微信支付平台证书文件存储路径
*/
@Value("${weixin.privateKeyPath}")
private String privateKeyPath;
/**
* apiV3 的密码
*/
@Value("${weixin.apiV3Key}")
private String apiV3Key;
/**
* APP ID
*/
@Value("${weixin.appId}")
private String appId;
/**
* 回调URL
*/
@Value("${weixin.notifyUrl}")
private String notifyUrl;
@Bean
public WeiXinPayConfig weiXinPayUtil() {
return new WeiXinPayConfig();
}
public String prepayIdByOrderInfo(String orderId, String product, Long amount, String openId) throws IOException {
//--1 读取证书
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(privateKeyPath));
//--2 构建请求
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
apiV3Key.getBytes("utf-8"));
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
//--3 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
HttpClient httpClient = builder.build();
//--4 调用统一下单接口
// https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type","application/json; charset=utf-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("mchid",merchantId)
.put("appid", appId)
.put("description", product)
.put("notify_url", notifyUrl)
.put("out_trade_no", orderId);
rootNode.putObject("amount")
.put("total", amount);
rootNode.putObject("payer")
.put("openid", openId);
objectMapper.writeValue(bos, rootNode);
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
return bodyAsString;
}
}
4、【服务端】接收支付结果通知
步骤说明:当用户完成支付,微信会把相关支付结果将通过异步回调的方式通知商户,商户需要接收处理,并按文档规范返回应答
注意:
- 支付结果通知是以 POST 方法访问商户设置的通知url,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情
- 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考微信支付API v3签名方案
- 支付通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx
- 商户成功接收到回调通知后应返回成功的http应答码为200或204
- 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱
- 对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)
参考文档:
https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml