From ec0d1740e35d8ae6df660280344cd431406ddda2 Mon Sep 17 00:00:00 2001 From: "408033187@qq.com" Date: Sun, 25 Dec 2016 17:56:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8=E5=8E=9F=E6=9D=A5=E7=9A=84=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E4=B8=8A=E5=88=9B=E5=BB=BA=E6=9B=B4=E7=AE=80=E6=B4=81?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E7=94=A8=E7=BA=A2=E5=8C=85=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E8=AF=B7=E5=9C=A8=E8=BF=99=E4=B9=8B=E5=89=8D=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=85=8D=E7=BD=AE=E4=B8=AD=E7=9A=84SslContex?= =?UTF-8?q?t=EF=BC=8C=E6=96=B0=E5=A2=9ESslContext=E7=9A=84get|set=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E6=96=B9=E4=BE=BFspring=E6=B3=A8=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/mp/api/WxMpConfigStorage.java | 13 ++++ .../mp/api/WxMpInMemoryConfigStorage.java | 43 +++++++++-- .../chanjar/weixin/mp/api/WxMpPayService.java | 31 ++++++++ .../mp/api/impl/WxMpPayServiceImpl.java | 76 ++++++++++++++++++- .../weixin/mp/api/impl/WxMpServiceImpl.java | 18 ++--- 5 files changed, 163 insertions(+), 18 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index d93c3080..b9b11fd7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -118,7 +118,20 @@ public interface WxMpConfigStorage { File getTmpDirFile(); + @Deprecated SSLContext getSSLContext(); + + SSLContext getSslContext(); + + void setSslContext(SSLContext sslContext); + + /** + * 在此之前,必须将partnerId进行赋值 + * + * @param filePath + * apiclient_cert.p12的文件的绝对路径 + */ + void setSslContextFilePath(String filePath) throws Exception; /** * http client builder diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index 61b75fbb..9fec33f8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -1,14 +1,19 @@ package me.chanjar.weixin.mp.api; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.ToStringUtils; -import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; - -import javax.net.ssl.SSLContext; import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import javax.net.ssl.SSLContext; + +import org.apache.http.ssl.SSLContexts; + +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder; + /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化 * @author chanjarster @@ -300,11 +305,33 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { public SSLContext getSSLContext() { return this.sslContext; } - - public void setSSLContext(SSLContext context) { - this.sslContext = context; + + @Override + public SSLContext getSslContext() { + return this.sslContext; } + @Override + public void setSslContextFilePath(String filePath) throws Exception { + if (null == partnerId) { + throw new Exception("请先将partnerId进行赋值"); + } + File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException(file.getPath() + ":文件不存在!在设置SSLContext的时候"); + } + FileInputStream inputStream = new FileInputStream(file); + KeyStore keystore = KeyStore.getInstance("PKCS12"); + char[] partnerId2charArray = partnerId.toCharArray(); + keystore.load(inputStream, partnerId2charArray); + this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); + } + + @Override + public void setSslContext(SSLContext context) { + this.sslContext = context; + } + @Override public ApacheHttpClientBuilder getApacheHttpClientBuilder() { return this.apacheHttpClientBuilder; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java index afe888f8..b4dd3b29 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java @@ -197,8 +197,24 @@ public interface WxMpPayService { * @param request 请求对象 * @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) */ + @Deprecated WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile) throws WxErrorException; + /** + * 发送微信红包给个人用户 + *
+   * 文档详见:
+   * 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
+   *  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
+   * 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
+   *  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
+   * 
+ * + * @param request 请求对象 + * @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) + */ + WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException; + /** *
    *   查询红包记录
@@ -211,7 +227,22 @@ public interface WxMpPayService {
    * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
    * @param keyFile   证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3)
    */
+  @Deprecated
   WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException;
+  
+  /**
+   * 
+   *   查询红包记录
+   *   用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
+   *   请求Url	https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
+   *   是否需要证书	是(证书及使用说明详见商户证书)
+   *   请求方式	POST
+   * 
+ * + * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890 + * @param keyFile 证书文件对象(即apiclient_cert.p12 商户证书文件,详细参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3) + */ + WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException; /** *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
index 9bd4dad2..8751fc6c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java
@@ -160,6 +160,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
 
 
   @Override
+  @Deprecated
   public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request, File keyFile)
     throws WxErrorException {
     XStream xstream = XStreamInitializer.getInstance();
@@ -179,8 +180,30 @@ public class WxMpPayServiceImpl implements WxMpPayService {
     this.checkResult(result);
     return result;
   }
+  
+  @Override
+  public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request)
+  		throws WxErrorException {
+  	XStream xstream = XStreamInitializer.getInstance();
+  	xstream.processAnnotations(WxPaySendRedpackRequest.class);
+  	xstream.processAnnotations(WxPaySendRedpackResult.class);
+  	
+  	initRequest(request);
+  	request.setSign(this.createSign(request));
+  	
+  	String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack";
+  	if (request.getAmtType() != null) {
+  		//裂变红包
+  		url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack";
+  	}
+  	String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request));
+  	WxPaySendRedpackResult result = (WxPaySendRedpackResult) xstream.fromXML(responseContent);
+  	this.checkResult(result);
+  	return result;
+  }
 
   @Override
+  @Deprecated
   public WxPayRedpackQueryResult queryRedpack(String mchBillNo, File keyFile) throws WxErrorException {
     XStream xstream = XStreamInitializer.getInstance();
     xstream.processAnnotations(WxPayRedpackQueryRequest.class);
@@ -198,6 +221,25 @@ public class WxMpPayServiceImpl implements WxMpPayService {
     this.checkResult(result);
     return result;
   }
+  
+  @Override
+  public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException {
+  	XStream xstream = XStreamInitializer.getInstance();
+  	xstream.processAnnotations(WxPayRedpackQueryRequest.class);
+  	xstream.processAnnotations(WxPayRedpackQueryResult.class);
+  	
+  	WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
+  	request.setMchBillNo(mchBillNo);
+  	request.setBillType("MCHT");
+  	initRequest(request);
+  	request.setSign(this.createSign(request));
+  	
+  	String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo";
+  	String responseContent = this.executeRequestWithKeyFile(url, xstream.toXML(request));
+  	WxPayRedpackQueryResult result = (WxPayRedpackQueryResult) xstream.fromXML(responseContent);
+  	this.checkResult(result);
+  	return result;
+  }
 
   @Override
   public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException {
@@ -383,7 +425,8 @@ public class WxMpPayServiceImpl implements WxMpPayService {
       httpPost.releaseConnection();
     }
   }
-
+  
+  @Deprecated
   private String executeRequestWithKeyFile(String url, File keyFile, String requestStr, String mchId) throws WxErrorException {
     try (FileInputStream inputStream = new FileInputStream(keyFile)) {
       KeyStore keyStore = KeyStore.getInstance("PKCS12");
@@ -414,6 +457,37 @@ public class WxMpPayServiceImpl implements WxMpPayService {
     }
   }
   
+  private String executeRequestWithKeyFile(String url, String requestStr) throws WxErrorException {
+  	try {
+  		
+  		SSLContext sslcontext = getConfig().getSSLContext();
+  		if(null==sslcontext){
+  			throw new Exception("请将配置类(WxMpInMemoryConfigStorage)中的SSLContext初始化");
+  		}
+  		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
+  				new DefaultHostnameVerifier());
+  		
+  		HttpPost httpPost = new HttpPost(url);
+  		if (this.wxMpService.getHttpProxy() != null) {
+  			httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build());
+  		}
+  		
+  		try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) {
+  			httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1")));
+  			try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
+  				String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
+  				this.log.debug("\n[URL]:  {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result);
+  				return result;
+  			}
+  		} finally {
+  			httpPost.releaseConnection();
+  		}
+  	} catch (Exception e) {
+  		this.log.error("\n[URL]:  {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage());
+  		throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e);
+  	}
+  }
+  
   @Override
   public String createSign(Object xmlBean) {
     return createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
index ccb0bd2e..0008e20d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
@@ -20,8 +20,8 @@ import org.apache.http.HttpHost;
 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.conn.ssl.DefaultHostnameVerifier;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+//import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+//import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.slf4j.Logger;
@@ -33,7 +33,7 @@ import java.util.concurrent.locks.Lock;
 public class WxMpServiceImpl implements WxMpService {
 
   private static final JsonParser JSON_PARSER = new JsonParser();
-
+  
   protected final Logger log = LoggerFactory.getLogger(this.getClass());
 
   private WxMpConfigStorage configStorage;
@@ -459,12 +459,12 @@ public class WxMpServiceImpl implements WxMpService {
         .httpProxyUsername(this.configStorage.getHttpProxyUsername())
         .httpProxyPassword(this.configStorage.getHttpProxyPassword());
 
-    if (this.configStorage.getSSLContext() != null) {
-      SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
-          this.configStorage.getSSLContext(), new String[] { "TLSv1" }, null,
-          new DefaultHostnameVerifier());
-      apacheHttpClientBuilder.sslConnectionSocketFactory(sslsf);
-    }
+		// if (this.configStorage.getSSLContext() != null) {
+		// SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
+		// this.configStorage.getSSLContext(), new String[] { "TLSv1" }, null,
+		// new DefaultHostnameVerifier());
+		// apacheHttpClientBuilder.sslConnectionSocketFactory(sslsf);
+		// }
 
     if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
       this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());