mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-10-31 10:38:42 +08:00 
			
		
		
		
	| @ -2,6 +2,8 @@ package me.chanjar.weixin.mp.api; | |||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
|  |  | ||||||
|  | import javax.net.ssl.SSLContext; | ||||||
|  |  | ||||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -74,4 +76,5 @@ public interface WxMpConfigStorage { | |||||||
|    |    | ||||||
|   public File getTmpDirFile(); |   public File getTmpDirFile(); | ||||||
|  |  | ||||||
|  |   public SSLContext getSSLContext(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,6 +2,8 @@ package me.chanjar.weixin.mp.api; | |||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
|  |  | ||||||
|  | import javax.net.ssl.SSLContext; | ||||||
|  |  | ||||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -35,6 +37,8 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||||
|    */ |    */ | ||||||
|   protected volatile File tmpDirFile; |   protected volatile File tmpDirFile; | ||||||
|    |    | ||||||
|  |   protected volatile SSLContext sslContext; | ||||||
|  |    | ||||||
|   public String getAccessToken() { |   public String getAccessToken() { | ||||||
|     return this.accessToken; |     return this.accessToken; | ||||||
|   } |   } | ||||||
| @ -219,4 +223,13 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||||||
|     this.tmpDirFile = tmpDirFile; |     this.tmpDirFile = tmpDirFile; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public SSLContext getSSLContext() { | ||||||
|  |     return sslContext; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   public void setSSLContext(SSLContext context) { | ||||||
|  |     sslContext = context; | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -748,4 +748,12 @@ public interface WxMpService { | |||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature); |     public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature); | ||||||
|  |      | ||||||
|  |    /** | ||||||
|  |     * 发送微信红包给个人用户 | ||||||
|  |     * @param parameters | ||||||
|  |     * @return | ||||||
|  |     * @throws WxErrorException | ||||||
|  |     */ | ||||||
|  |     public WxRedpackResult sendRedpack(Map<String, String> parameters) throws WxErrorException; | ||||||
| } | } | ||||||
|  | |||||||
| @ -66,6 +66,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpUser; | |||||||
| import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; | import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; | ||||||
| import me.chanjar.weixin.mp.bean.result.WxMpUserList; | import me.chanjar.weixin.mp.bean.result.WxMpUserList; | ||||||
| import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; | import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; | ||||||
|  | import me.chanjar.weixin.mp.bean.result.WxRedpackResult; | ||||||
| import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; | import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor; | ||||||
| import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; | import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor; | ||||||
| import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; | import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor; | ||||||
| @ -84,13 +85,16 @@ import org.apache.http.client.config.RequestConfig; | |||||||
| import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||||
| import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||||
| import org.apache.http.client.methods.HttpPost; | import org.apache.http.client.methods.HttpPost; | ||||||
|  | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | ||||||
| import org.apache.http.entity.StringEntity; | import org.apache.http.entity.StringEntity; | ||||||
| import org.apache.http.impl.client.BasicCredentialsProvider; | import org.apache.http.impl.client.BasicCredentialsProvider; | ||||||
| import org.apache.http.impl.client.BasicResponseHandler; | import org.apache.http.impl.client.BasicResponseHandler; | ||||||
| import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||||
|  | import org.apache.http.impl.client.HttpClientBuilder; | ||||||
| import org.apache.http.impl.client.HttpClients; | import org.apache.http.impl.client.HttpClients; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  | import org.slf4j.helpers.MessageFormatter; | ||||||
|  |  | ||||||
| import com.google.gson.JsonArray; | import com.google.gson.JsonArray; | ||||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||||
| @ -743,6 +747,7 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|     String http_proxy_username = wxMpConfigStorage.getHttp_proxy_username(); |     String http_proxy_username = wxMpConfigStorage.getHttp_proxy_username(); | ||||||
|     String http_proxy_password = wxMpConfigStorage.getHttp_proxy_password(); |     String http_proxy_password = wxMpConfigStorage.getHttp_proxy_password(); | ||||||
|  |  | ||||||
|  |     final HttpClientBuilder builder = HttpClients.custom(); | ||||||
|     if (StringUtils.isNotBlank(http_proxy_host)) { |     if (StringUtils.isNotBlank(http_proxy_host)) { | ||||||
|       // 使用代理服务器 |       // 使用代理服务器 | ||||||
|       if (StringUtils.isNotBlank(http_proxy_username)) { |       if (StringUtils.isNotBlank(http_proxy_username)) { | ||||||
| @ -751,18 +756,22 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|         credsProvider.setCredentials( |         credsProvider.setCredentials( | ||||||
|             new AuthScope(http_proxy_host, http_proxy_port), |             new AuthScope(http_proxy_host, http_proxy_port), | ||||||
|             new UsernamePasswordCredentials(http_proxy_username, http_proxy_password)); |             new UsernamePasswordCredentials(http_proxy_username, http_proxy_password)); | ||||||
|         httpClient = HttpClients |         builder | ||||||
|             .custom() |             .setDefaultCredentialsProvider(credsProvider); | ||||||
|             .setDefaultCredentialsProvider(credsProvider) |  | ||||||
|             .build(); |  | ||||||
|       } else { |       } else { | ||||||
|         // 无需用户认证的代理服务器 |         // 无需用户认证的代理服务器 | ||||||
|         httpClient = HttpClients.createDefault(); |  | ||||||
|       } |       } | ||||||
|       httpProxy = new HttpHost(http_proxy_host, http_proxy_port); |       httpProxy = new HttpHost(http_proxy_host, http_proxy_port); | ||||||
|     } else { |  | ||||||
|       httpClient = HttpClients.createDefault(); |  | ||||||
|     } |     } | ||||||
|  |     if (wxConfigProvider.getSSLContext() != null){ | ||||||
|  |       SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( | ||||||
|  |           wxConfigProvider.getSSLContext(), | ||||||
|  |           new String[] { "TLSv1" }, | ||||||
|  |           null, | ||||||
|  |           SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); | ||||||
|  |       builder.setSSLSocketFactory(sslsf); | ||||||
|  |     } | ||||||
|  |     httpClient = builder.build(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
| @ -941,4 +950,45 @@ public class WxMpServiceImpl implements WxMpService { | |||||||
|   public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) { |   public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) { | ||||||
| 	  return signature.equals(WxCryptUtil.createSign(kvm, wxMpConfigStorage.getPartnerKey())); | 	  return signature.equals(WxCryptUtil.createSign(kvm, wxMpConfigStorage.getPartnerKey())); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public WxRedpackResult sendRedpack(Map<String, String> parameters) throws WxErrorException { | ||||||
|  |     String nonce_str = System.currentTimeMillis() + ""; | ||||||
|  |  | ||||||
|  |     SortedMap<String, String> packageParams = new TreeMap<String, String>(parameters); | ||||||
|  |     packageParams.put("wxappid", wxMpConfigStorage.getAppId()); | ||||||
|  |     packageParams.put("mch_id", wxMpConfigStorage.getPartnerId()); | ||||||
|  |     packageParams.put("nonce_str", nonce_str); | ||||||
|  |  | ||||||
|  |     String sign = WxCryptUtil.createSign(packageParams, wxMpConfigStorage.getPartnerKey()); | ||||||
|  |     packageParams.put("sign", sign); | ||||||
|  |      | ||||||
|  |     StringBuilder request = new StringBuilder("<xml>"); | ||||||
|  |     for (Entry<String, String> para : packageParams.entrySet()) { | ||||||
|  |       request.append(String.format("<%s>%s</%s>", para.getKey(), para.getValue(), para.getKey())); | ||||||
|  |     } | ||||||
|  |     request.append("</xml>"); | ||||||
|  |      | ||||||
|  |     HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"); | ||||||
|  |     if (httpProxy != null) { | ||||||
|  |       RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build(); | ||||||
|  |       httpPost.setConfig(config); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); | ||||||
|  |     httpPost.setEntity(entity); | ||||||
|  |     try { | ||||||
|  |       CloseableHttpResponse response = getHttpclient().execute(httpPost); | ||||||
|  |       String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); | ||||||
|  |       XStream xstream = XStreamInitializer.getInstance(); | ||||||
|  |       xstream.processAnnotations(WxRedpackResult.class); | ||||||
|  |       WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(responseContent); | ||||||
|  |       return wxMpRedpackResult; | ||||||
|  |     } catch (IOException e) { | ||||||
|  |       log.error(MessageFormatter.format("The exception was happened when sending redpack '{}'.", request.toString()).getMessage(), e); | ||||||
|  |       WxError error = new WxError(); | ||||||
|  |       error.setErrorCode(-1); | ||||||
|  |       throw new WxErrorException(error); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,118 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.result; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | import com.thoughtworks.xstream.annotations.XStreamAlias; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 向微信用户个人发现金红包返回结果 | ||||||
|  |  * https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter=13_5 | ||||||
|  |  * @author kane | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | @XStreamAlias("xml") | ||||||
|  | public class WxRedpackResult implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    *  | ||||||
|  |    */ | ||||||
|  |   private static final long serialVersionUID = -4837415036337132073L; | ||||||
|  |  | ||||||
|  |   @XStreamAlias("return_code") | ||||||
|  |   String returnCode; | ||||||
|  |   @XStreamAlias("return_msg") | ||||||
|  |   String returnMsg; | ||||||
|  |   @XStreamAlias("sign") | ||||||
|  |   String sign; | ||||||
|  |   @XStreamAlias("result_code") | ||||||
|  |   String resultCode; | ||||||
|  |    | ||||||
|  |   @XStreamAlias("err_code") | ||||||
|  |   String errCode; | ||||||
|  |   @XStreamAlias("err_code_des") | ||||||
|  |   String errCodeDes; | ||||||
|  |   @XStreamAlias("mch_billno") | ||||||
|  |   String mchBillno; | ||||||
|  |   @XStreamAlias("mch_id") | ||||||
|  |   String mchId; | ||||||
|  |   @XStreamAlias("wxappid") | ||||||
|  |   String wxappid; | ||||||
|  |   @XStreamAlias("re_openid") | ||||||
|  |   String reOpenid; | ||||||
|  |   @XStreamAlias("total_amount") | ||||||
|  |   int totalAmount; | ||||||
|  |   @XStreamAlias("send_time") | ||||||
|  |   String sendTime; | ||||||
|  |   @XStreamAlias("send_listid") | ||||||
|  |   String sendListid; | ||||||
|  |    | ||||||
|  |   public String getErrCode() { | ||||||
|  |     return errCode; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   public String getErrCodeDes() { | ||||||
|  |     return errCodeDes; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getReturnCode() { | ||||||
|  |     return returnCode; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getReturnMsg() { | ||||||
|  |     return returnMsg; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getSign() { | ||||||
|  |     return sign; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getResultCode() { | ||||||
|  |     return resultCode; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getMchBillno() { | ||||||
|  |     return mchBillno; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getMchId() { | ||||||
|  |     return mchId; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getWxappid() { | ||||||
|  |     return wxappid; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getReOpenid() { | ||||||
|  |     return reOpenid; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public int getTotalAmount() { | ||||||
|  |     return totalAmount; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getSendTime() { | ||||||
|  |     return sendTime; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public String getSendListid() { | ||||||
|  |     return sendListid; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   @Override | ||||||
|  |   public String toString() { | ||||||
|  |     return "WxRedpackResult{" + | ||||||
|  |         "returnCode=" + returnCode + | ||||||
|  |         ", returnMsg=" + returnMsg + | ||||||
|  |         ", sign=" + sign + | ||||||
|  |         ", errCode=" + errCode + | ||||||
|  |         ", errCodeDes=" + errCodeDes + | ||||||
|  |         ", mchBillno=" + mchBillno + | ||||||
|  |         ", mchId=" + mchId + | ||||||
|  |         ", wxappid=" + wxappid + | ||||||
|  |         ", reOpenid=" + reOpenid + | ||||||
|  |         ", totalAmount=" + totalAmount + | ||||||
|  |         ", sendTime=" + sendTime + | ||||||
|  |         ", sendListid=" + sendListid + | ||||||
|  |         '}'; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,63 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean; | ||||||
|  |  | ||||||
|  | import static org.junit.Assert.assertEquals; | ||||||
|  |  | ||||||
|  | import org.junit.Before; | ||||||
|  | import org.junit.Test; | ||||||
|  |  | ||||||
|  | import com.thoughtworks.xstream.XStream; | ||||||
|  |  | ||||||
|  | import me.chanjar.weixin.common.util.xml.XStreamInitializer; | ||||||
|  | import me.chanjar.weixin.mp.bean.result.WxRedpackResult; | ||||||
|  |  | ||||||
|  | public class WxRedpackResultTest { | ||||||
|  |  | ||||||
|  |   private XStream xstream; | ||||||
|  |  | ||||||
|  |   @Before | ||||||
|  |   public void setup() { | ||||||
|  |      xstream = XStreamInitializer.getInstance(); | ||||||
|  |      xstream.processAnnotations(WxRedpackResult.class); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   @Test public void loadSuccessResult() { | ||||||
|  |     final String successSample = "<xml>\n" +  | ||||||
|  |         "<return_code><![CDATA[SUCCESS]]></return_code>\n" +  | ||||||
|  |         "<return_msg><![CDATA[发放成功.]]></return_msg>\n" +  | ||||||
|  |         "<result_code><![CDATA[SUCCESS]]></result_code>\n" +  | ||||||
|  |         "<err_code><![CDATA[0]]></err_code>\n" +  | ||||||
|  |         "<err_code_des><![CDATA[发放成功.]]></err_code_des>\n" +  | ||||||
|  |         "<mch_billno><![CDATA[0010010404201411170000046545]]></mch_billno>\n" +  | ||||||
|  |         "<mch_id>10010404</mch_id>\n" +  | ||||||
|  |         "<wxappid><![CDATA[wx6fa7e3bab7e15415]]></wxappid>\n" +  | ||||||
|  |         "<re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid>\n" +  | ||||||
|  |         "<total_amount>1</total_amount>\n" +  | ||||||
|  |         "<send_listid>100000000020150520314766074200</send_listid>\n" +  | ||||||
|  |         "<send_time>20150520102602</send_time>\n" +  | ||||||
|  |         "</xml>"; | ||||||
|  |     WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(successSample); | ||||||
|  |     assertEquals("SUCCESS", wxMpRedpackResult.getReturnCode()); | ||||||
|  |     assertEquals("SUCCESS", wxMpRedpackResult.getResultCode()); | ||||||
|  |     assertEquals("20150520102602", wxMpRedpackResult.getSendTime()); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   @Test public void loadFailureResult() { | ||||||
|  |     final String failureSample = "<xml>\n" +  | ||||||
|  |         "<return_code><![CDATA[FAIL]]></return_code>\n" +  | ||||||
|  |         "<return_msg><![CDATA[系统繁忙,请稍后再试.]]></return_msg>\n" +  | ||||||
|  |         "<result_code><![CDATA[FAIL]]></result_code>\n" +  | ||||||
|  |         "<err_code><![CDATA[268458547]]></err_code>\n" +  | ||||||
|  |         "<err_code_des><![CDATA[系统繁忙,请稍后再试.]]></err_code_des>\n" +  | ||||||
|  |         "<mch_billno><![CDATA[0010010404201411170000046542]]></mch_billno>\n" +  | ||||||
|  |         "<mch_id>10010404</mch_id>\n" +  | ||||||
|  |         "<wxappid><![CDATA[wx6fa7e3bab7e15415]]></wxappid>\n" +  | ||||||
|  |         "<re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid>\n" +  | ||||||
|  |         "<total_amount>1</total_amount>\n" +  | ||||||
|  |         "</xml>"; | ||||||
|  |     WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(failureSample); | ||||||
|  |     assertEquals("FAIL", wxMpRedpackResult.getReturnCode()); | ||||||
|  |     assertEquals("FAIL", wxMpRedpackResult.getResultCode()); | ||||||
|  |     assertEquals("onqOjjmM1tad-3ROpncN-yUfa6uI", wxMpRedpackResult.getReOpenid()); | ||||||
|  |     assertEquals(1, wxMpRedpackResult.getTotalAmount()); | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Daniel Qian
					Daniel Qian