no message
This commit is contained in:
244
src/main/java/com/sczx/pay/sdk/WXPay.java
Normal file
244
src/main/java/com/sczx/pay/sdk/WXPay.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/main/java/com/sczx/pay/sdk/WXPayConfig.java
Normal file
43
src/main/java/com/sczx/pay/sdk/WXPayConfig.java
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user