/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
*
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.pay.channel.wxpay.kits;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder;
import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier;
import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner;
import com.github.binarywang.wxpay.v3.auth.WxPayCredentials;
import com.github.binarywang.wxpay.v3.auth.WxPayValidator;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: ZhuXiao
* @Description:
* @Date: 15:22 2021/5/26
*/
@Slf4j
public class WxpayV3Util {
private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
public static final Map NORMALMCH_URL_MAP = new HashMap<>();
static {
NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.APP, "/v3/pay/transactions/app");
NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.JSAPI, "/v3/pay/transactions/jsapi");
NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.NATIVE, "/v3/pay/transactions/native");
NORMALMCH_URL_MAP.put(WxPayConstants.TradeType.MWEB, "/v3/pay/transactions/h5");
}
public static final Map ISV_URL_MAP = new HashMap<>();
static {
ISV_URL_MAP.put(WxPayConstants.TradeType.APP, "/v3/pay/partner/transactions/app");
ISV_URL_MAP.put(WxPayConstants.TradeType.JSAPI, "/v3/pay/partner/transactions/jsapi");
ISV_URL_MAP.put(WxPayConstants.TradeType.NATIVE, "/v3/pay/partner/transactions/native");
ISV_URL_MAP.put(WxPayConstants.TradeType.MWEB, "/v3/pay/partner/transactions/h5");
}
public static JSONObject unifiedOrderV3(String url, JSONObject reqJSON, WxPayConfig wxPayConfig) throws WxPayException {
String response = postV3(PAY_BASE_URL + url, reqJSON.toJSONString(), wxPayConfig);
return JSON.parseObject(response);
}
public static JSONObject queryOrderV3(String payOrderId, WxPayConfig wxPayConfig) throws WxPayException {
String url = String.format("%s/v3/pay/transactions/out-trade-no/%s", PAY_BASE_URL, payOrderId);
String response = getV3(url, wxPayConfig);
return JSON.parseObject(response);
}
public static JSONObject refundV3(JSONObject reqJSON, WxPayConfig wxPayConfig) throws WxPayException {
String url = String.format("%s/v3/refund/domestic/refunds", PAY_BASE_URL);
String response = postV3(url, reqJSON.toJSONString(), wxPayConfig);
return JSON.parseObject(response);
}
public static JSONObject refundQueryV3(String refundOrderId, WxPayConfig wxPayConfig) throws WxPayException {
String url = String.format("%s/v3/refund/domestic/refunds/%s", PAY_BASE_URL, refundOrderId);
String response = getV3(url, wxPayConfig);
return JSON.parseObject(response);
}
public static JSONObject refundQueryV3Isv(String refundOrderId, WxPayConfig wxPayConfig) throws WxPayException {
String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", PAY_BASE_URL, refundOrderId, wxPayConfig.getSubMchId());
String response = getV3(url, wxPayConfig);
return JSON.parseObject(response);
}
public static String postV3(String url, String requestStr, WxPayConfig wxPayConfig) throws WxPayException {
CloseableHttpClient httpClient = createApiV3HttpClient(wxPayConfig);
HttpPost httpPost = createHttpPost(url, requestStr);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/json");
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
//v3已经改为通过状态码判断200 204 成功
int statusCode = response.getStatusLine().getStatusCode();
//post方法有可能会没有返回值的情况
String responseString;
if (response.getEntity() == null) {
responseString = null;
} else {
responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
return responseString;
} else {
//有错误提示信息返回
JSONObject jsonObject = JSON.parseObject(responseString);
WxPayException wxPayException = new WxPayException(jsonObject.getString("message"));
wxPayException.setErrCode(jsonObject.getString("code"));
wxPayException.setErrCodeDes(jsonObject.getString("message"));
throw wxPayException;
}
} catch (Exception e) {
log.error("\n【异常信息】:{}", e.getMessage());
throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
} finally {
httpPost.releaseConnection();
}
}
public static String getV3(String url, WxPayConfig wxPayConfig) throws WxPayException {
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-Type", "application/json");
httpGet.setConfig(RequestConfig.custom()
.setConnectionRequestTimeout(5000)
.setConnectTimeout(5000)
.setSocketTimeout(10000)
.build());
CloseableHttpClient httpClient = createApiV3HttpClient(wxPayConfig);
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
//v3已经改为通过状态码判断200 204 成功
int statusCode = response.getStatusLine().getStatusCode();
//post方法有可能会没有返回值的情况
String responseString;
if (response.getEntity() == null) {
responseString = null;
} else {
responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
}
if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
log.info("\n【请求地址】:{}\n【响应数据】:{}", url, responseString);
return responseString;
} else {
//有错误提示信息返回
JSONObject jsonObject = JSON.parseObject(responseString);
WxPayException wxPayException = new WxPayException(jsonObject.getString("message"));
wxPayException.setErrCode(jsonObject.getString("code"));
wxPayException.setErrCodeDes(jsonObject.getString("message"));
throw wxPayException;
}
} catch (Exception e) {
log.error("\n【异常信息】:{}", url, e.getMessage());
throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
} finally {
httpGet.releaseConnection();
}
}
private static CloseableHttpClient createApiV3HttpClient(WxPayConfig wxPayConfig) throws WxPayException {
try {
// 自动获取微信平台证书
PrivateKey privateKey = PemUtils.loadPrivateKey(new FileInputStream(wxPayConfig.getPrivateKeyPath()));
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)),
wxPayConfig.getApiV3Key().getBytes("utf-8"));
WxPayV3HttpClientBuilder builder = WxPayV3HttpClientBuilder.create()
.withMerchant(wxPayConfig.getMchId(), wxPayConfig.getCertSerialNo(), privateKey)
.withValidator(new WxPayValidator(verifier));
CloseableHttpClient apiV3HttpClient = builder.build();
return apiV3HttpClient;
} catch (FileNotFoundException | UnsupportedEncodingException e) {
log.error("", e);
}
CloseableHttpClient apiV3HttpClient = wxPayConfig.getApiV3HttpClient();
if (null == apiV3HttpClient) {
return wxPayConfig.initApiV3HttpClient();
}
return null;
}
private static HttpPost createHttpPost(String url, String requestStr) {
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(requestStr, ContentType.create("application/json", "utf-8")));
httpPost.setConfig(RequestConfig.custom()
.setConnectionRequestTimeout(5000)
.setConnectTimeout(5000)
.setSocketTimeout(10000)
.build());
return httpPost;
}
}