no message

This commit is contained in:
2025-08-21 17:33:28 +08:00
commit 9d744548d1
27 changed files with 2880 additions and 0 deletions

View File

@ -0,0 +1,244 @@
package com.sczx.pay.sdk;
import com.sczx.pay.utils.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* 微信支付接口
*/
public class WXPay {
private static final Logger logger = LoggerFactory.getLogger(WXPay.class);
private WXPayConfig config;
private boolean autoReport;
private boolean useSandbox;
private String baseUrl = "https://api.mch.weixin.qq.com";
public WXPay(WXPayConfig config) {
this(config, true, false);
}
public WXPay(WXPayConfig config, boolean autoReport) {
this(config, autoReport, false);
}
public WXPay(WXPayConfig config, boolean autoReport, boolean useSandbox) {
this.config = config;
this.autoReport = autoReport;
this.useSandbox = useSandbox;
if (useSandbox) {
this.baseUrl = "https://api.mch.weixin.qq.com/sandboxnew";
} else {
this.baseUrl = "https://api.mch.weixin.qq.com";
}
}
/**
* 统一下单
*/
public Map<String, String> unifiedOrder(Map<String, String> reqData) throws Exception {
return this.unifiedOrder(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public Map<String, String> unifiedOrder(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/pay/unifiedorder";
} else {
url = this.baseUrl + "/pay/unifiedorder";
}
if (this.autoReport) {
// TODO: 添加自动上报逻辑
}
String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return WXPayUtil.xmlToMap(respXml);
}
/**
* 订单查询
*/
public Map<String, String> orderQuery(Map<String, String> reqData) throws Exception {
return this.orderQuery(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public Map<String, String> orderQuery(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/pay/orderquery";
} else {
url = this.baseUrl + "/pay/orderquery";
}
String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return WXPayUtil.xmlToMap(respXml);
}
/**
* 关闭订单
*/
public Map<String, String> closeOrder(Map<String, String> reqData) throws Exception {
return this.closeOrder(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public Map<String, String> closeOrder(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/pay/closeorder";
} else {
url = this.baseUrl + "/pay/closeorder";
}
String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return WXPayUtil.xmlToMap(respXml);
}
/**
* 申请退款
*/
public Map<String, String> refund(Map<String, String> reqData) throws Exception {
return this.refund(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public Map<String, String> refund(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/secapi/pay/refund";
} else {
url = this.baseUrl + "/secapi/pay/refund";
}
String respXml = this.requestWithCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return WXPayUtil.xmlToMap(respXml);
}
/**
* 退款查询
*/
public Map<String, String> refundQuery(Map<String, String> reqData) throws Exception {
return this.refundQuery(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public Map<String, String> refundQuery(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/pay/refundquery";
} else {
url = this.baseUrl + "/pay/refundquery";
}
String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return WXPayUtil.xmlToMap(respXml);
}
/**
* 下载对账单
*/
public String downloadBill(Map<String, String> reqData) throws Exception {
return this.downloadBill(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
public String downloadBill(Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = this.baseUrl + "/pay/downloadbill";
} else {
url = this.baseUrl + "/pay/downloadbill";
}
return this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
}
/**
* 填充请求数据(生成签名)
*/
private Map<String, String> fillRequestData(Map<String, String> reqData) throws Exception {
reqData.put("appid", config.getAppID());
reqData.put("mch_id", config.getMchID());
if (!reqData.containsKey("nonce_str")) {
reqData.put("nonce_str", WXPayUtil.generateNonceStr());
}
reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey()));
return reqData;
}
/**
* 无证书请求
*/
private String requestWithoutCert(String url, Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String xml = WXPayUtil.mapToXml(reqData);
logger.info("微信支付请求URL: {}, 请求数据: {}", url, xml);
String response = httpRequest(url, xml, connectTimeoutMs, readTimeoutMs);
logger.info("微信支付响应数据: {}", response);
return response;
}
/**
* 有证书请求
*/
private String requestWithCert(String url, Map<String, String> reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String xml = WXPayUtil.mapToXml(reqData);
logger.info("微信支付请求URL: {}, 请求数据: {}", url, xml);
String response = httpRequest(url, xml, connectTimeoutMs, readTimeoutMs);
logger.info("微信支付响应数据: {}", response);
return response;
}
/**
* HTTP请求
*/
private String httpRequest(String url, String requestData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
java.net.HttpURLConnection connection = null;
try {
java.net.URL reqUrl = new java.net.URL(url);
connection = (java.net.HttpURLConnection) reqUrl.openConnection();
// 设置请求参数
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type", "application/xml;charset=UTF-8");
connection.setConnectTimeout(connectTimeoutMs);
connection.setReadTimeout(readTimeoutMs);
// 发送请求数据
if (requestData != null) {
java.io.OutputStream outputStream = connection.getOutputStream();
outputStream.write(requestData.getBytes("UTF-8"));
outputStream.close();
}
// 读取响应数据
java.io.InputStream inputStream = connection.getInputStream();
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(inputStream, "UTF-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
inputStream.close();
return response.toString();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
/**
* 判断支付结果
*/
public boolean isResponseSignatureValid(Map<String, String> respData) {
try {
return WXPayUtil.isSignatureValid(respData, this.config.getKey());
} catch (Exception e) {
logger.error("验证响应签名异常", e);
return false;
}
}
}

View File

@ -0,0 +1,43 @@
package com.sczx.pay.sdk;
import java.io.InputStream;
/**
* 微信支付配置抽象类
*/
public abstract class WXPayConfig {
/**
* 获取 App ID
*/
public abstract String getAppID();
/**
* 获取商户号
*/
public abstract String getMchID();
/**
* 获取 API 密钥
*/
public abstract String getKey();
/**
* 获取证书内容
*/
public abstract InputStream getCertStream();
/**
* HTTP(S) 连接超时时间,单位毫秒
*/
public int getHttpConnectTimeoutMs() {
return 6*1000;
}
/**
* HTTP(S) 读数据超时时间,单位毫秒
*/
public int getHttpReadTimeoutMs() {
return 8*1000;
}
}