2025-11-07 13:17:20 +08:00

137 lines
5.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.heyu.api.jsapi;
// 引用微信支付工具库参考https://pay.weixin.qq.com/doc/v3/merchant/4014931831
import com.heyu.api.jsapi.dto.CommonAmountInfo;
import com.heyu.api.jsapi.dto.DirectAPIv3JsapiPrepayRequest;
import com.heyu.api.jsapi.dto.DirectAPIv3JsapiPrepayResponse;
import com.heyu.api.jsapi.dto.JsapiReqPayerInfo;
import com.heyu.api.jsapi.utils.PemUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
/**
* JSAPI下单
*/
@Component
@Slf4j
public class JsapiPrepay {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/pay/transactions/jsapi";
@Value("${eb.config.weixin.pay.appid}")
private String appid;
@Value("${eb.config.weixin.pay.mchid}")
private String mchid;
private String certificateSerialNo;
private PrivateKey privateKey;
private String wechatPayPublicKeyId;
private PublicKey wechatPayPublicKey;
@Value("${eb.config.weixin.pay.notifyUrl}")
private String notifyUrl;
public JsapiPrepay() {
}
public JsapiPrepay(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
@SneakyThrows
public static String getSign(String signatureStr, String privateKey) {
String replace = privateKey.replace("\\n", "\n");
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromPath(replace);
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(merchantPrivateKey);
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
public DirectAPIv3JsapiPrepayResponse prePay(Long tradeOrderId,
Long amount,
String openid
) {
DirectAPIv3JsapiPrepayRequest request = new DirectAPIv3JsapiPrepayRequest();
request.setAppid(appid);
request.setMchid(mchid);
request.setNotifyUrl(notifyUrl);
request.setDescription(System.currentTimeMillis() + "");
request.setOutTradeNo(tradeOrderId + "");
request.setTimeExpire(WXPayUtility.generateExpireTime()); // 2025-11-05T21:02:16+08:00
request.setAttach("自定义数据说明");
request.setGoodsTag("WXG");
request.setSupportFapiao(false);
CommonAmountInfo commonAmountInfo = new CommonAmountInfo();
commonAmountInfo.setTotal(amount);
commonAmountInfo.setCurrency("CNY");
request.setAmount(commonAmountInfo);
JsapiReqPayerInfo payer = new JsapiReqPayerInfo();
payer.setOpenid(openid);
request.setPayer(payer);
return doPay(request);
}
public DirectAPIv3JsapiPrepayResponse doPay(DirectAPIv3JsapiPrepayRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo, privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
log.info("JsapiPrepay respBody:{}", respBody);
if (respBody != null) {
}
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功,验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey, httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, DirectAPIv3JsapiPrepayResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
}