提交修改

This commit is contained in:
quyixiao 2025-11-07 13:17:20 +08:00
parent 42f8b98350
commit 6ad4cccb2a
5 changed files with 362 additions and 3 deletions

View File

@ -6,16 +6,21 @@ 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下单
@ -59,6 +64,15 @@ public class JsapiPrepay {
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,

View File

@ -0,0 +1,20 @@
package com.heyu.api.jsapi.dto;
import lombok.Data;
@Data
public class WxPayVO {
// 预支付交易会话标识小程序下单接口返回的prepay_id参数值
private String prepayId;
// 随机字符串
private String nonceStr;
// 时间戳
private Long timeStamp;
// 签名
private String paySign;
// 商户号
private String mchid;
}

View File

@ -0,0 +1,60 @@
package com.heyu.api.jsapi.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
/** I/O工具 */
public class IOUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192;
private IOUtil() {}
/**
* 转换输入流为字节数组
*
* @param inputStream 输入流
* @return 字节数组
* @throws IOException 读取字节失败关闭流失败等
*/
public static byte[] toByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[DEFAULT_BUFFER_SIZE];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}
/**
* 转换输入流为字符串
*
* @param inputStream 输入流
* @return UTF-8编码的字符串
* @throws IOException 读取字节失败关闭流失败等
*/
public static String toString(InputStream inputStream) throws IOException {
return new String(toByteArray(inputStream), StandardCharsets.UTF_8);
}
/**
* 从文件路径中读取字符串
*
* @param path 文件路径
* @return UTF-8编码的字符串
* @throws IOException 读取字节失败关闭流失败等
*/
public static String loadStringFromPath(String path) throws IOException {
try (InputStream inputStream = Files.newInputStream(Paths.get(path))) {
return toString(inputStream);
}
}
}

View File

@ -0,0 +1,227 @@
package com.heyu.api.jsapi.utils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/** PEM工具 */
public class PemUtil {
public static final int HEX = 16;
private PemUtil() {}
/**
* 从字符串中加载RSA私钥
*
* @param keyString 私钥字符串
* @return RSA私钥
*/
public static PrivateKey loadPrivateKeyFromString(String keyString) {
try {
keyString =
keyString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 从字符串中加载指定算法的私钥
*
* @param keyString 私钥字符串
* @param algorithm 私钥算法
* @param provider the provider
* @return 私钥
*/
public static PrivateKey loadPrivateKeyFromString(
String keyString, String algorithm, String provider) {
try {
keyString =
keyString
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance(algorithm, provider)
.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException | NoSuchProviderException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 从字符串中加载RSA公钥
*
* @param keyString 公钥字符串
* @return RSA公钥
*/
public static PublicKey loadPublicKeyFromString(String keyString) {
try {
keyString =
keyString
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 从文件路径加载RSA私钥
*
* @param keyPath 私钥路径
* @return RSA私钥
*/
public static PrivateKey loadPrivateKeyFromPath(String keyPath) {
return loadPrivateKeyFromString(readKeyStringFromPath(keyPath));
}
/**
* 从文件路径加载指定算法的私钥
*
* @param keyPath 私钥路径
* @param algorithm 私钥算法
* @param provider the provider
* @return 私钥
*/
public static PrivateKey loadPrivateKeyFromPath(
String keyPath, String algorithm, String provider) {
return loadPrivateKeyFromString(readKeyStringFromPath(keyPath), algorithm, provider);
}
/**
* 从文件路径加载RSA公钥
*
* @param keyPath 公钥路径
* @return RSA公钥
*/
public static PublicKey loadPublicKeyFromPath(String keyPath) {
return loadPublicKeyFromString(readKeyStringFromPath(keyPath));
}
private static String readKeyStringFromPath(String keyPath) {
try (FileInputStream inputStream = new FileInputStream(keyPath)) {
return IOUtil.toString(inputStream);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 从输入流加载X.509证书
*
* @param inputStream 私钥输入流
* @return X.509证书
*/
public static X509Certificate loadX509FromStream(InputStream inputStream) {
try {
return (X509Certificate)
CertificateFactory.getInstance("X.509").generateCertificate(inputStream);
} catch (CertificateException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 从输入流加载X.509证书
*
* @param inputStream 私钥输入流
* @param provider the provider
* @return X.509证书
*/
public static X509Certificate loadX509FromStream(InputStream inputStream, String provider) {
try {
return (X509Certificate)
CertificateFactory.getInstance("X.509", provider).generateCertificate(inputStream);
} catch (CertificateException | NoSuchProviderException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 从文件路径加载X.509证书
*
* @param certificatePath 证书文件路径
* @return X.509证书
*/
public static X509Certificate loadX509FromPath(String certificatePath) {
try (FileInputStream inputStream = new FileInputStream(certificatePath)) {
return loadX509FromStream(inputStream);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 从文件路径加载X.509证书
*
* @param certificatePath 证书文件路径
* @param provider the provider
* @return X.509证书
*/
public static X509Certificate loadX509FromPath(String certificatePath, String provider) {
try (FileInputStream inputStream = new FileInputStream(certificatePath)) {
return loadX509FromStream(inputStream, provider);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 从字符串加载X.509证书
*
* @param certificateString 证书字符串
* @return X.509证书
*/
public static X509Certificate loadX509FromString(String certificateString) {
try (ByteArrayInputStream inputStream =
new ByteArrayInputStream(certificateString.getBytes(StandardCharsets.UTF_8))) {
return loadX509FromStream(inputStream);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 从字符串加载X.509证书
*
* @param certificateString 证书字符串
* @param provider the provider
* @return X.509证书
*/
public static X509Certificate loadX509FromString(String certificateString, String provider) {
try (ByteArrayInputStream inputStream =
new ByteArrayInputStream(certificateString.getBytes(StandardCharsets.UTF_8))) {
return loadX509FromStream(inputStream, provider);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static String getSerialNumber(X509Certificate certificate) {
return certificate.getSerialNumber().toString(HEX).toUpperCase();
}
}

View File

@ -17,6 +17,7 @@ import com.heyu.api.data.enums.RoleEnums;
import com.heyu.api.data.utils.*;
import com.heyu.api.jsapi.JsapiPrepay;
import com.heyu.api.jsapi.dto.DirectAPIv3JsapiPrepayResponse;
import com.heyu.api.jsapi.dto.WxPayVO;
import com.heyu.api.utils.ISelect;
import com.heyu.api.utils.PPageUtils;
import lombok.extern.slf4j.Slf4j;
@ -31,6 +32,8 @@ import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
@ -78,6 +81,19 @@ public class AppOrderController {
@Value("${eb.config.rabbitQueue.delayExchangeName}")
private String delayExchangeName;
@Value("${eb.config.weixin.pay.appid}")
private String appid;
@Value("${eb.config.weixin.pay.mchid}")
private String mchid;
@Value("${eb.config.weixin.pay.privateKeyFilePath}")
private String privateKey;
/***
* https://api.1024api.com/api-interface/app/order/list
@ -347,12 +363,34 @@ public class AppOrderController {
});
}
Map<String,Object> map = new HashMap<>();
map.put("prepay_id",prepay_id);
return R.ok().setData(map);
WxPayVO vo = new WxPayVO();
Long timeStamp = System.currentTimeMillis() / 1000;
String nonceStr = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
String signatureStr = Stream.of(appid, String.valueOf(timeStamp), nonceStr, "prepay_id=" + prepay_id)
.collect(Collectors.joining("\n", "", "\n"));
// "timeStamp": "1414561699",
// "nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
// "package": "prepay_id=wx201410272009395522657a690389285100",
// "signType": "RSA",
// "paySign": "oR9d",
String sign = JsapiPrepay.getSign(signatureStr, privateKey);
vo.setNonceStr(nonceStr);
vo.setTimeStamp(timeStamp);
vo.setMchid(mchid);
vo.setPaySign(sign);
vo.setPrepayId("prepay_id=" + prepay_id);
return R.ok().setData(vo);
}
@Describe("删除订单")
@RequestMapping("/delete")
public R add(@RequestBody VvTradeOrderDeleteDTO vvOrderRequest) {