|
|
@@ -0,0 +1,177 @@
|
|
|
+package com.dataeasy.server.core.config;
|
|
|
+
|
|
|
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
|
|
|
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
|
|
|
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
|
|
+import com.github.binarywang.wxpay.config.WxPayConfig;
|
|
|
+import com.github.binarywang.wxpay.exception.WxPayException;
|
|
|
+import com.github.binarywang.wxpay.service.WxPayService;
|
|
|
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
|
|
+import com.google.gson.Gson;
|
|
|
+import com.google.gson.GsonBuilder;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
+import com.google.gson.JsonObject;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import me.chanjar.weixin.common.util.json.GsonParser;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.http.HttpEntity;
|
|
|
+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 org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
|
+import org.springframework.context.annotation.Bean;
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
+
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author tyuio
|
|
|
+ * @version 1.0.0
|
|
|
+ * @description 微信支付配置
|
|
|
+ * @date 2025/3/5 8:50
|
|
|
+ */
|
|
|
+@Configuration
|
|
|
+@EnableConfigurationProperties(WxPayProperties.class)
|
|
|
+public class WxPayConfiguration {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WxPayProperties properties;
|
|
|
+
|
|
|
+ @Bean
|
|
|
+ public WxPayService wxPayService() {
|
|
|
+ final MyWxPayServiceImpl wxPayService = new MyWxPayServiceImpl();
|
|
|
+ WxPayConfig payConfig = new WxPayConfig();
|
|
|
+ payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
|
|
|
+ payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
|
|
|
+ payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
|
|
|
+ payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
|
|
|
+ payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
|
|
|
+ //以下是apiv3以及支付分相关
|
|
|
+ payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));
|
|
|
+ payConfig.setPublicKeyId(StringUtils.trimToNull(this.properties.getPublicKeyId()));
|
|
|
+ payConfig.setPublicKeyPath(StringUtils.trimToNull(this.properties.getPublicKeyPath()));
|
|
|
+ wxPayService.setConfig(payConfig);
|
|
|
+ return wxPayService;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO 代码有bug需要手动设置Wechatpay-Serial,最新的正式版(4.7.0)还没有修复该问题,
|
|
|
+ // 临时实现一个, 等待修复该bug
|
|
|
+ @Slf4j
|
|
|
+ public static class MyWxPayServiceImpl extends WxPayServiceImpl {
|
|
|
+
|
|
|
+ private static final Gson GSON = new GsonBuilder().create();
|
|
|
+ private static final String ACCEPT = "Accept";
|
|
|
+ private static final String CONTENT_TYPE = "Content-Type";
|
|
|
+ private static final String APPLICATION_JSON = "application/json";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException {
|
|
|
+ if (StringUtils.isBlank(request.getAppid())) {
|
|
|
+ request.setAppid(this.getConfig().getAppId());
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(request.getMchid())) {
|
|
|
+ request.setMchid(this.getConfig().getMchId());
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(request.getNotifyUrl())) {
|
|
|
+ request.setNotifyUrl(this.getConfig().getNotifyUrl());
|
|
|
+ }
|
|
|
+
|
|
|
+ String url = this.getPayBaseUrl() + tradeType.getPartnerUrl();
|
|
|
+ String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
|
|
|
+ return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String postV3WithWechatpaySerial(String url, String requestStr) throws WxPayException {
|
|
|
+ CloseableHttpClient httpClient = this.createApiV3HttpClient();
|
|
|
+ HttpPost httpPost = this.createHttpPost(url, requestStr);
|
|
|
+ httpPost.addHeader(ACCEPT, APPLICATION_JSON);
|
|
|
+ httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
|
|
|
+ // 微信支付 平台证书切换微信支付公钥模式过程中(两种模式并存)Wechatpay-Serial 需要传完整的公钥id给微信标识使用什么签名方式
|
|
|
+ String serialNumber = StringUtils.isEmpty(getConfig().getPublicKeyId()) ?
|
|
|
+ getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase() :
|
|
|
+ getConfig().getPublicKeyId();
|
|
|
+ httpPost.addHeader("Wechatpay-Serial", serialNumber);
|
|
|
+ try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
|
|
+ //v3已经改为通过状态码判断200 204 成功
|
|
|
+ int statusCode = response.getStatusLine().getStatusCode();
|
|
|
+ String responseString = "{}";
|
|
|
+ HttpEntity entity = response.getEntity();
|
|
|
+ if (entity != null) {
|
|
|
+ responseString = EntityUtils.toString(entity, StandardCharsets.UTF_8);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
|
|
|
+ this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据】:{}", url, requestStr, responseString);
|
|
|
+ return responseString;
|
|
|
+ }
|
|
|
+
|
|
|
+ //有错误提示信息返回
|
|
|
+ JsonObject jsonObject = GsonParser.parse(responseString);
|
|
|
+ throw convertException(jsonObject);
|
|
|
+ } catch (Exception e) {
|
|
|
+ this.log.error("\n【请求地址】:{}\n【请求数据】:{}\n【异常信息】:{}", url, requestStr, e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
|
|
|
+ } finally {
|
|
|
+ httpPost.releaseConnection();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getV3WithWechatPaySerial(String url) throws WxPayException {
|
|
|
+ HttpGet httpGet = new HttpGet(url);
|
|
|
+ httpGet.addHeader(ACCEPT, APPLICATION_JSON);
|
|
|
+ httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
|
|
|
+ // 微信支付 平台证书切换微信支付公钥模式过程中(两种模式并存)Wechatpay-Serial 需要传完整的公钥id给微信标识使用什么签名方式
|
|
|
+ String serialNumber = StringUtils.isEmpty(getConfig().getPublicKeyId()) ?
|
|
|
+ getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase() :
|
|
|
+ getConfig().getPublicKeyId();
|
|
|
+ httpGet.addHeader("Wechatpay-Serial", serialNumber);
|
|
|
+ return this.requestV3(url, httpGet);
|
|
|
+ }
|
|
|
+
|
|
|
+ private WxPayException convertException(JsonObject jsonObject) {
|
|
|
+ //todo 这里考虑使用新的适用于V3的异常
|
|
|
+ JsonElement codeElement = jsonObject.get("code");
|
|
|
+ String code = codeElement == null ? null : codeElement.getAsString();
|
|
|
+ String message = jsonObject.get("message").getAsString();
|
|
|
+ WxPayException wxPayException = new WxPayException(message);
|
|
|
+ wxPayException.setErrCode(code);
|
|
|
+ wxPayException.setErrCodeDes(message);
|
|
|
+ return wxPayException;
|
|
|
+ }
|
|
|
+
|
|
|
+ private HttpPost createHttpPost(String url, String requestStr) {
|
|
|
+ HttpPost httpPost = new HttpPost(url);
|
|
|
+ httpPost.setEntity(this.createEntry(requestStr));
|
|
|
+
|
|
|
+ httpPost.setConfig(RequestConfig.custom()
|
|
|
+ .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
|
|
|
+ .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
|
|
|
+ .setSocketTimeout(this.getConfig().getHttpTimeout())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ return httpPost;
|
|
|
+ }
|
|
|
+
|
|
|
+ private StringEntity createEntry(String requestStr) {
|
|
|
+ return new StringEntity(requestStr, ContentType.create(APPLICATION_JSON, "utf-8"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private CloseableHttpClient createApiV3HttpClient() throws WxPayException {
|
|
|
+ CloseableHttpClient apiV3HttpClient = this.getConfig().getApiV3HttpClient();
|
|
|
+ if (null == apiV3HttpClient) {
|
|
|
+ return this.getConfig().initApiV3HttpClient();
|
|
|
+ }
|
|
|
+ return apiV3HttpClient;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|