| @@ -21,7 +21,6 @@ import java.io.Serializable; | |||||
| @NoArgsConstructor | @NoArgsConstructor | ||||
| @XStreamAlias("xml") | @XStreamAlias("xml") | ||||
| public class WxPayFaceAuthInfoResult extends BaseWxPayResult implements Serializable { | public class WxPayFaceAuthInfoResult extends BaseWxPayResult implements Serializable { | ||||
| private static final long serialVersionUID = -65138145275211272L; | private static final long serialVersionUID = -65138145275211272L; | ||||
| /** | /** | ||||
| @@ -1,12 +1,13 @@ | |||||
| package com.github.binarywang.wxpay.config; | package com.github.binarywang.wxpay.config; | ||||
| import com.github.binarywang.wxpay.exception.WxPayException; | import com.github.binarywang.wxpay.exception.WxPayException; | ||||
| import com.github.binarywang.wxpay.v3.WechatPayHttpClientBuilder; | |||||
| import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder; | |||||
| import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier; | import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier; | ||||
| import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner; | import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner; | ||||
| import com.github.binarywang.wxpay.v3.auth.WechatPay2Credentials; | import com.github.binarywang.wxpay.v3.auth.WechatPay2Credentials; | ||||
| import com.github.binarywang.wxpay.v3.auth.WechatPay2Validator; | import com.github.binarywang.wxpay.v3.auth.WechatPay2Validator; | ||||
| import com.github.binarywang.wxpay.v3.util.PemUtils; | import com.github.binarywang.wxpay.v3.util.PemUtils; | ||||
| import jodd.util.ResourcesUtil; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import org.apache.commons.io.IOUtils; | import org.apache.commons.io.IOUtils; | ||||
| import org.apache.commons.lang3.RegExUtils; | import org.apache.commons.lang3.RegExUtils; | ||||
| @@ -20,8 +21,7 @@ import java.net.URL; | |||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
| import java.security.KeyStore; | import java.security.KeyStore; | ||||
| import java.security.PrivateKey; | import java.security.PrivateKey; | ||||
| import java.security.cert.X509Certificate; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Collections; | |||||
| /** | /** | ||||
| * 微信支付配置 | * 微信支付配置 | ||||
| @@ -31,6 +31,8 @@ import java.util.ArrayList; | |||||
| @Data | @Data | ||||
| public class WxPayConfig { | public class WxPayConfig { | ||||
| private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com"; | ||||
| private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!"; | |||||
| private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!"; | |||||
| /** | /** | ||||
| * 微信支付接口请求地址域名部分. | * 微信支付接口请求地址域名部分. | ||||
| @@ -184,17 +186,20 @@ public class WxPayConfig { | |||||
| } | } | ||||
| final String prefix = "classpath:"; | final String prefix = "classpath:"; | ||||
| String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题,请核实!"; | |||||
| String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在,请核实!"; | |||||
| String fileHasProblemMsg = String.format(PROBLEM_MSG, this.getKeyPath()); | |||||
| String fileNotFoundMsg = String.format(NOT_FOUND_MSG, this.getKeyPath()); | |||||
| if (this.getKeyPath().startsWith(prefix)) { | if (this.getKeyPath().startsWith(prefix)) { | ||||
| String path = RegExUtils.removeFirst(this.getKeyPath(), prefix); | String path = RegExUtils.removeFirst(this.getKeyPath(), prefix); | ||||
| if (!path.startsWith("/")) { | if (!path.startsWith("/")) { | ||||
| path = "/" + path; | path = "/" + path; | ||||
| } | } | ||||
| inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); | |||||
| if (inputStream == null) { | |||||
| throw new WxPayException(fileNotFoundMsg); | |||||
| try { | |||||
| inputStream = ResourcesUtil.getResourceAsStream(path); | |||||
| if (inputStream == null) { | |||||
| throw new WxPayException(fileNotFoundMsg); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| throw new WxPayException(fileNotFoundMsg, e); | |||||
| } | } | ||||
| } else if (this.getKeyPath().startsWith("http://") || this.getKeyPath().startsWith("https://")) { | } else if (this.getKeyPath().startsWith("http://") || this.getKeyPath().startsWith("https://")) { | ||||
| try { | try { | ||||
| @@ -232,7 +237,6 @@ public class WxPayConfig { | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * 初始化api v3请求头 自动签名验签 | * 初始化api v3请求头 自动签名验签 | ||||
| * 方法参照微信官方https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient | * 方法参照微信官方https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient | ||||
| @@ -266,9 +270,13 @@ public class WxPayConfig { | |||||
| if (!keypath.startsWith("/")) { | if (!keypath.startsWith("/")) { | ||||
| keypath = "/" + keypath; | keypath = "/" + keypath; | ||||
| } | } | ||||
| keyInputStream = WxPayConfig.class.getResourceAsStream(keypath); | |||||
| if (keyInputStream == null) { | |||||
| throw new WxPayException("证书文件【" + this.getPrivateKeyPath() + "】不存在,请核实!"); | |||||
| try { | |||||
| keyInputStream = ResourcesUtil.getResourceAsStream(keypath); | |||||
| if (keyInputStream == null) { | |||||
| throw new WxPayException(String.format(NOT_FOUND_MSG, this.getPrivateKeyPath())); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| throw new WxPayException(String.format(NOT_FOUND_MSG, this.getPrivateKeyPath()), e); | |||||
| } | } | ||||
| } | } | ||||
| @@ -277,32 +285,29 @@ public class WxPayConfig { | |||||
| if (!certpath.startsWith("/")) { | if (!certpath.startsWith("/")) { | ||||
| certpath = "/" + certpath; | certpath = "/" + certpath; | ||||
| } | } | ||||
| certInputStream = WxPayConfig.class.getResourceAsStream(certpath); | |||||
| if (certInputStream == null) { | |||||
| throw new WxPayException("证书文件【" + this.getPrivateCertPath() + "】不存在,请核实!"); | |||||
| try { | |||||
| certInputStream = ResourcesUtil.getResourceAsStream(certpath); | |||||
| if (certInputStream == null) { | |||||
| throw new WxPayException(String.format(NOT_FOUND_MSG, this.getPrivateCertPath())); | |||||
| } | |||||
| } catch (Exception e) { | |||||
| throw new WxPayException(String.format(NOT_FOUND_MSG, this.getPrivateCertPath()), e); | |||||
| } | } | ||||
| } | } | ||||
| CloseableHttpClient httpClient; | |||||
| try { | try { | ||||
| WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create(); | |||||
| PrivateKey merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); | PrivateKey merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); | ||||
| X509Certificate x509Certificate = PemUtils.loadCertificate(certInputStream); | |||||
| ArrayList<X509Certificate> certificates = new ArrayList<>(); | |||||
| certificates.add(x509Certificate); | |||||
| builder.withMerchant(mchId, certSerialNo, merchantPrivateKey); | |||||
| builder.withWechatpay(certificates); | |||||
| AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier( | |||||
| new WechatPay2Credentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), | |||||
| apiV3Key.getBytes(StandardCharsets.UTF_8)); | |||||
| builder.withValidator(new WechatPay2Validator(verifier)); | |||||
| httpClient = builder.build(); | |||||
| CloseableHttpClient httpClient = WxPayV3HttpClientBuilder.create() | |||||
| .withMerchant(mchId, certSerialNo, merchantPrivateKey) | |||||
| .withWechatpay(Collections.singletonList(PemUtils.loadCertificate(certInputStream))) | |||||
| .withValidator(new WechatPay2Validator(new AutoUpdateCertificatesVerifier( | |||||
| new WechatPay2Credentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), | |||||
| apiV3Key.getBytes(StandardCharsets.UTF_8)))) | |||||
| .build(); | |||||
| this.apiV3HttpClient = httpClient; | this.apiV3HttpClient = httpClient; | ||||
| return httpClient; | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| throw new WxPayException("v3请求构造异常!", e); | throw new WxPayException("v3请求构造异常!", e); | ||||
| } | } | ||||
| return httpClient; | |||||
| } | } | ||||
| } | } | ||||
| @@ -4,10 +4,6 @@ import java.net.URI; | |||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
| import javax.net.ssl.SSLContext; | import javax.net.ssl.SSLContext; | ||||
| import com.github.binarywang.wxpay.bean.request.WxPayQueryCommentRequest; | |||||
| import com.github.binarywang.wxpay.bean.request.WxPayRedpackQueryRequest; | |||||
| import com.github.binarywang.wxpay.bean.result.WxPayCommonResult; | |||||
| import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult; | |||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import com.github.binarywang.wxpay.bean.WxPayApiData; | import com.github.binarywang.wxpay.bean.WxPayApiData; | ||||
| @@ -20,10 +16,6 @@ import jodd.http.ProxyInfo.ProxyType; | |||||
| import jodd.http.net.SSLSocketHttpConnectionProvider; | import jodd.http.net.SSLSocketHttpConnectionProvider; | ||||
| import jodd.http.net.SocketHttpConnectionProvider; | import jodd.http.net.SocketHttpConnectionProvider; | ||||
| import jodd.util.Base64; | import jodd.util.Base64; | ||||
| import org.apache.commons.lang3.StringUtils; | |||||
| import javax.net.ssl.SSLContext; | |||||
| import java.nio.charset.StandardCharsets; | |||||
| /** | /** | ||||
| * 微信支付请求实现类,jodd-http实现. | * 微信支付请求实现类,jodd-http实现. | ||||
| @@ -13,45 +13,45 @@ import org.apache.http.impl.client.CloseableHttpClient; | |||||
| import org.apache.http.impl.client.HttpClientBuilder; | import org.apache.http.impl.client.HttpClientBuilder; | ||||
| import org.apache.http.impl.execchain.ClientExecChain; | import org.apache.http.impl.execchain.ClientExecChain; | ||||
| public class WechatPayHttpClientBuilder extends HttpClientBuilder { | |||||
| public class WxPayV3HttpClientBuilder extends HttpClientBuilder { | |||||
| private Credentials credentials; | private Credentials credentials; | ||||
| private Validator validator; | private Validator validator; | ||||
| static final String os = System.getProperty("os.name") + "/" + System.getProperty("os.version"); | |||||
| static final String version = System.getProperty("java.version"); | |||||
| static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version"); | |||||
| static final String VERSION = System.getProperty("java.version"); | |||||
| private WechatPayHttpClientBuilder() { | |||||
| private WxPayV3HttpClientBuilder() { | |||||
| super(); | super(); | ||||
| String userAgent = String.format( | String userAgent = String.format( | ||||
| "WechatPay-Apache-HttpClient/%s (%s) Java/%s", | "WechatPay-Apache-HttpClient/%s (%s) Java/%s", | ||||
| getClass().getPackage().getImplementationVersion(), | getClass().getPackage().getImplementationVersion(), | ||||
| os, | |||||
| version == null ? "Unknown" : version); | |||||
| OS, | |||||
| VERSION == null ? "Unknown" : VERSION); | |||||
| setUserAgent(userAgent); | setUserAgent(userAgent); | ||||
| } | } | ||||
| public static WechatPayHttpClientBuilder create() { | |||||
| return new WechatPayHttpClientBuilder(); | |||||
| public static WxPayV3HttpClientBuilder create() { | |||||
| return new WxPayV3HttpClientBuilder(); | |||||
| } | } | ||||
| public WechatPayHttpClientBuilder withMerchant(String merchantId, String serialNo, PrivateKey privateKey) { | |||||
| public WxPayV3HttpClientBuilder withMerchant(String merchantId, String serialNo, PrivateKey privateKey) { | |||||
| this.credentials = | this.credentials = | ||||
| new WechatPay2Credentials(merchantId, new PrivateKeySigner(serialNo, privateKey)); | new WechatPay2Credentials(merchantId, new PrivateKeySigner(serialNo, privateKey)); | ||||
| return this; | return this; | ||||
| } | } | ||||
| public WechatPayHttpClientBuilder withCredentials(Credentials credentials) { | |||||
| public WxPayV3HttpClientBuilder withCredentials(Credentials credentials) { | |||||
| this.credentials = credentials; | this.credentials = credentials; | ||||
| return this; | return this; | ||||
| } | } | ||||
| public WechatPayHttpClientBuilder withWechatpay(List<X509Certificate> certificates) { | |||||
| public WxPayV3HttpClientBuilder withWechatpay(List<X509Certificate> certificates) { | |||||
| this.validator = new WechatPay2Validator(new CertificatesVerifier(certificates)); | this.validator = new WechatPay2Validator(new CertificatesVerifier(certificates)); | ||||
| return this; | return this; | ||||
| } | } | ||||
| public WechatPayHttpClientBuilder withValidator(Validator validator) { | |||||
| public WxPayV3HttpClientBuilder withValidator(Validator validator) { | |||||
| this.validator = validator; | this.validator = validator; | ||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -3,7 +3,7 @@ package com.github.binarywang.wxpay.v3.auth; | |||||
| import com.fasterxml.jackson.databind.JsonNode; | import com.fasterxml.jackson.databind.JsonNode; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import com.github.binarywang.wxpay.v3.Credentials; | import com.github.binarywang.wxpay.v3.Credentials; | ||||
| import com.github.binarywang.wxpay.v3.WechatPayHttpClientBuilder; | |||||
| import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder; | |||||
| import com.github.binarywang.wxpay.v3.util.AesUtils; | import com.github.binarywang.wxpay.v3.util.AesUtils; | ||||
| import com.github.binarywang.wxpay.v3.util.PemUtils; | import com.github.binarywang.wxpay.v3.util.PemUtils; | ||||
| import lombok.Getter; | import lombok.Getter; | ||||
| @@ -115,7 +115,7 @@ public class AutoUpdateCertificatesVerifier implements Verifier { | |||||
| } | } | ||||
| private void autoUpdateCert() throws IOException, GeneralSecurityException { | private void autoUpdateCert() throws IOException, GeneralSecurityException { | ||||
| CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create() | |||||
| CloseableHttpClient httpClient = WxPayV3HttpClientBuilder.create() | |||||
| .withCredentials(credentials) | .withCredentials(credentials) | ||||
| .withValidator(verifier == null ? (response) -> true : new WechatPay2Validator(verifier)) | .withValidator(verifier == null ? (response) -> true : new WechatPay2Validator(verifier)) | ||||
| .build(); | .build(); | ||||
| @@ -2,8 +2,6 @@ package com.github.binarywang.wxpay.config; | |||||
| import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
| import static org.testng.Assert.*; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * Created by BinaryWang on 2017/6/18. | * Created by BinaryWang on 2017/6/18. | ||||
| @@ -12,12 +10,12 @@ import static org.testng.Assert.*; | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class WxPayConfigTest { | public class WxPayConfigTest { | ||||
| private WxPayConfig payConfig = new WxPayConfig(); | |||||
| private final WxPayConfig payConfig = new WxPayConfig(); | |||||
| @Test | @Test | ||||
| public void testInitSSLContext_classpath() throws Exception { | public void testInitSSLContext_classpath() throws Exception { | ||||
| payConfig.setMchId("123"); | payConfig.setMchId("123"); | ||||
| payConfig.setKeyPath("classpath:/abc.p12"); | |||||
| payConfig.setKeyPath("classpath:/dlt.p12"); | |||||
| payConfig.initSSLContext(); | payConfig.initSSLContext(); | ||||
| } | } | ||||
| @@ -28,4 +26,9 @@ public class WxPayConfigTest { | |||||
| payConfig.initSSLContext(); | payConfig.initSSLContext(); | ||||
| } | } | ||||
| @Test | |||||
| public void testInitSSLContext() throws Exception { | |||||
| this.testInitSSLContext_classpath(); | |||||
| this.testInitSSLContext_http(); | |||||
| } | |||||
| } | } | ||||