mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-10-31 18:46:10 +08:00 
			
		
		
		
	| @ -2,6 +2,8 @@ package me.chanjar.weixin.mp.api; | ||||
|  | ||||
| import java.io.File; | ||||
|  | ||||
| import javax.net.ssl.SSLContext; | ||||
|  | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
|  | ||||
| /** | ||||
| @ -74,4 +76,5 @@ public interface WxMpConfigStorage { | ||||
|    | ||||
|   public File getTmpDirFile(); | ||||
|  | ||||
|   public SSLContext getSSLContext(); | ||||
| } | ||||
|  | ||||
| @ -2,6 +2,8 @@ package me.chanjar.weixin.mp.api; | ||||
|  | ||||
| import java.io.File; | ||||
|  | ||||
| import javax.net.ssl.SSLContext; | ||||
|  | ||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
|  | ||||
| /** | ||||
| @ -35,6 +37,8 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | ||||
|    */ | ||||
|   protected volatile File tmpDirFile; | ||||
|    | ||||
|   protected volatile SSLContext sslContext; | ||||
|    | ||||
|   public String getAccessToken() { | ||||
|     return this.accessToken; | ||||
|   } | ||||
| @ -219,4 +223,13 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | ||||
|     this.tmpDirFile = tmpDirFile; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public SSLContext getSSLContext() { | ||||
|     return sslContext; | ||||
|   } | ||||
|    | ||||
|   public void setSSLContext(SSLContext context) { | ||||
|     sslContext = context; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -748,4 +748,12 @@ public interface WxMpService { | ||||
|      * @return | ||||
|      */ | ||||
|     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.WxMpUserList; | ||||
| 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.MaterialNewsInfoRequestExecutor; | ||||
| 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.HttpGet; | ||||
| import org.apache.http.client.methods.HttpPost; | ||||
| import org.apache.http.conn.ssl.SSLConnectionSocketFactory; | ||||
| import org.apache.http.entity.StringEntity; | ||||
| import org.apache.http.impl.client.BasicCredentialsProvider; | ||||
| import org.apache.http.impl.client.BasicResponseHandler; | ||||
| import org.apache.http.impl.client.CloseableHttpClient; | ||||
| import org.apache.http.impl.client.HttpClientBuilder; | ||||
| import org.apache.http.impl.client.HttpClients; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.slf4j.helpers.MessageFormatter; | ||||
|  | ||||
| import com.google.gson.JsonArray; | ||||
| 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_password = wxMpConfigStorage.getHttp_proxy_password(); | ||||
|  | ||||
|     final HttpClientBuilder builder = HttpClients.custom(); | ||||
|     if (StringUtils.isNotBlank(http_proxy_host)) { | ||||
|       // 使用代理服务器 | ||||
|       if (StringUtils.isNotBlank(http_proxy_username)) { | ||||
| @ -751,18 +756,22 @@ public class WxMpServiceImpl implements WxMpService { | ||||
|         credsProvider.setCredentials( | ||||
|             new AuthScope(http_proxy_host, http_proxy_port), | ||||
|             new UsernamePasswordCredentials(http_proxy_username, http_proxy_password)); | ||||
|         httpClient = HttpClients | ||||
|             .custom() | ||||
|             .setDefaultCredentialsProvider(credsProvider) | ||||
|             .build(); | ||||
|         builder | ||||
|             .setDefaultCredentialsProvider(credsProvider); | ||||
|       } else { | ||||
|         // 无需用户认证的代理服务器 | ||||
|         httpClient = HttpClients.createDefault(); | ||||
|       } | ||||
|       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 | ||||
| @ -941,4 +950,45 @@ public class WxMpServiceImpl implements WxMpService { | ||||
|   public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) { | ||||
| 	  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