Skip to content

Commit 27ce2a2

Browse files
committed
Merge pull request #233 from videome/develop
Support sending redpack.
2 parents d0a4529 + 30f2289 commit 27ce2a2

File tree

6 files changed

+262
-7
lines changed

6 files changed

+262
-7
lines changed

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.io.File;
44

5+
import javax.net.ssl.SSLContext;
6+
57
import me.chanjar.weixin.common.bean.WxAccessToken;
68

79
/**
@@ -74,4 +76,5 @@ public interface WxMpConfigStorage {
7476

7577
public File getTmpDirFile();
7678

79+
public SSLContext getSSLContext();
7780
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.io.File;
44

5+
import javax.net.ssl.SSLContext;
6+
57
import me.chanjar.weixin.common.bean.WxAccessToken;
68

79
/**
@@ -35,6 +37,8 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
3537
*/
3638
protected volatile File tmpDirFile;
3739

40+
protected volatile SSLContext sslContext;
41+
3842
public String getAccessToken() {
3943
return this.accessToken;
4044
}
@@ -219,4 +223,13 @@ public void setTmpDirFile(File tmpDirFile) {
219223
this.tmpDirFile = tmpDirFile;
220224
}
221225

226+
@Override
227+
public SSLContext getSSLContext() {
228+
return sslContext;
229+
}
230+
231+
public void setSSLContext(SSLContext context) {
232+
sslContext = context;
233+
}
234+
222235
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,4 +748,12 @@ public interface WxMpService {
748748
* @return
749749
*/
750750
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature);
751+
752+
/**
753+
* 发送微信红包给个人用户
754+
* @param parameters
755+
* @return
756+
* @throws WxErrorException
757+
*/
758+
public WxRedpackResult sendRedpack(Map<String, String> parameters) throws WxErrorException;
751759
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate;
6767
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
6868
import me.chanjar.weixin.mp.bean.result.WxMpUserSummary;
69+
import me.chanjar.weixin.mp.bean.result.WxRedpackResult;
6970
import me.chanjar.weixin.mp.util.http.MaterialDeleteRequestExecutor;
7071
import me.chanjar.weixin.mp.util.http.MaterialNewsInfoRequestExecutor;
7172
import me.chanjar.weixin.mp.util.http.MaterialUploadRequestExecutor;
@@ -84,13 +85,16 @@
8485
import org.apache.http.client.methods.CloseableHttpResponse;
8586
import org.apache.http.client.methods.HttpGet;
8687
import org.apache.http.client.methods.HttpPost;
88+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
8789
import org.apache.http.entity.StringEntity;
8890
import org.apache.http.impl.client.BasicCredentialsProvider;
8991
import org.apache.http.impl.client.BasicResponseHandler;
9092
import org.apache.http.impl.client.CloseableHttpClient;
93+
import org.apache.http.impl.client.HttpClientBuilder;
9194
import org.apache.http.impl.client.HttpClients;
9295
import org.slf4j.Logger;
9396
import org.slf4j.LoggerFactory;
97+
import org.slf4j.helpers.MessageFormatter;
9498

9599
import com.google.gson.JsonArray;
96100
import com.google.gson.JsonElement;
@@ -743,6 +747,7 @@ public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
743747
String http_proxy_username = wxMpConfigStorage.getHttp_proxy_username();
744748
String http_proxy_password = wxMpConfigStorage.getHttp_proxy_password();
745749

750+
final HttpClientBuilder builder = HttpClients.custom();
746751
if (StringUtils.isNotBlank(http_proxy_host)) {
747752
// 使用代理服务器
748753
if (StringUtils.isNotBlank(http_proxy_username)) {
@@ -751,18 +756,22 @@ public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
751756
credsProvider.setCredentials(
752757
new AuthScope(http_proxy_host, http_proxy_port),
753758
new UsernamePasswordCredentials(http_proxy_username, http_proxy_password));
754-
httpClient = HttpClients
755-
.custom()
756-
.setDefaultCredentialsProvider(credsProvider)
757-
.build();
759+
builder
760+
.setDefaultCredentialsProvider(credsProvider);
758761
} else {
759762
// 无需用户认证的代理服务器
760-
httpClient = HttpClients.createDefault();
761763
}
762764
httpProxy = new HttpHost(http_proxy_host, http_proxy_port);
763-
} else {
764-
httpClient = HttpClients.createDefault();
765765
}
766+
if (wxConfigProvider.getSSLContext() != null){
767+
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
768+
wxConfigProvider.getSSLContext(),
769+
new String[] { "TLSv1" },
770+
null,
771+
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
772+
builder.setSSLSocketFactory(sslsf);
773+
}
774+
httpClient = builder.build();
766775
}
767776

768777
@Override
@@ -941,4 +950,45 @@ public WxMpPayCallback getJSSDKCallbackData(String xmlData) {
941950
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature) {
942951
return signature.equals(WxCryptUtil.createSign(kvm, wxMpConfigStorage.getPartnerKey()));
943952
}
953+
954+
@Override
955+
public WxRedpackResult sendRedpack(Map<String, String> parameters) throws WxErrorException {
956+
String nonce_str = System.currentTimeMillis() + "";
957+
958+
SortedMap<String, String> packageParams = new TreeMap<String, String>(parameters);
959+
packageParams.put("wxappid", wxMpConfigStorage.getAppId());
960+
packageParams.put("mch_id", wxMpConfigStorage.getPartnerId());
961+
packageParams.put("nonce_str", nonce_str);
962+
963+
String sign = WxCryptUtil.createSign(packageParams, wxMpConfigStorage.getPartnerKey());
964+
packageParams.put("sign", sign);
965+
966+
StringBuilder request = new StringBuilder("<xml>");
967+
for (Entry<String, String> para : packageParams.entrySet()) {
968+
request.append(String.format("<%s>%s</%s>", para.getKey(), para.getValue(), para.getKey()));
969+
}
970+
request.append("</xml>");
971+
972+
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
973+
if (httpProxy != null) {
974+
RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
975+
httpPost.setConfig(config);
976+
}
977+
978+
StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8);
979+
httpPost.setEntity(entity);
980+
try {
981+
CloseableHttpResponse response = getHttpclient().execute(httpPost);
982+
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
983+
XStream xstream = XStreamInitializer.getInstance();
984+
xstream.processAnnotations(WxRedpackResult.class);
985+
WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(responseContent);
986+
return wxMpRedpackResult;
987+
} catch (IOException e) {
988+
log.error(MessageFormatter.format("The exception was happened when sending redpack '{}'.", request.toString()).getMessage(), e);
989+
WxError error = new WxError();
990+
error.setErrorCode(-1);
991+
throw new WxErrorException(error);
992+
}
993+
}
944994
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package me.chanjar.weixin.mp.bean.result;
2+
3+
import java.io.Serializable;
4+
5+
import com.thoughtworks.xstream.annotations.XStreamAlias;
6+
7+
/**
8+
* 向微信用户个人发现金红包返回结果
9+
* https://pay.weixin.qq.com/wiki/doc/api/cash_coupon.php?chapter=13_5
10+
* @author kane
11+
*
12+
*/
13+
@XStreamAlias("xml")
14+
public class WxRedpackResult implements Serializable {
15+
16+
/**
17+
*
18+
*/
19+
private static final long serialVersionUID = -4837415036337132073L;
20+
21+
@XStreamAlias("return_code")
22+
String returnCode;
23+
@XStreamAlias("return_msg")
24+
String returnMsg;
25+
@XStreamAlias("sign")
26+
String sign;
27+
@XStreamAlias("result_code")
28+
String resultCode;
29+
30+
@XStreamAlias("err_code")
31+
String errCode;
32+
@XStreamAlias("err_code_des")
33+
String errCodeDes;
34+
@XStreamAlias("mch_billno")
35+
String mchBillno;
36+
@XStreamAlias("mch_id")
37+
String mchId;
38+
@XStreamAlias("wxappid")
39+
String wxappid;
40+
@XStreamAlias("re_openid")
41+
String reOpenid;
42+
@XStreamAlias("total_amount")
43+
int totalAmount;
44+
@XStreamAlias("send_time")
45+
String sendTime;
46+
@XStreamAlias("send_listid")
47+
String sendListid;
48+
49+
public String getErrCode() {
50+
return errCode;
51+
}
52+
53+
public String getErrCodeDes() {
54+
return errCodeDes;
55+
}
56+
57+
public String getReturnCode() {
58+
return returnCode;
59+
}
60+
61+
public String getReturnMsg() {
62+
return returnMsg;
63+
}
64+
65+
public String getSign() {
66+
return sign;
67+
}
68+
69+
public String getResultCode() {
70+
return resultCode;
71+
}
72+
73+
public String getMchBillno() {
74+
return mchBillno;
75+
}
76+
77+
public String getMchId() {
78+
return mchId;
79+
}
80+
81+
public String getWxappid() {
82+
return wxappid;
83+
}
84+
85+
public String getReOpenid() {
86+
return reOpenid;
87+
}
88+
89+
public int getTotalAmount() {
90+
return totalAmount;
91+
}
92+
93+
public String getSendTime() {
94+
return sendTime;
95+
}
96+
97+
public String getSendListid() {
98+
return sendListid;
99+
}
100+
101+
@Override
102+
public String toString() {
103+
return "WxRedpackResult{" +
104+
"returnCode=" + returnCode +
105+
", returnMsg=" + returnMsg +
106+
", sign=" + sign +
107+
", errCode=" + errCode +
108+
", errCodeDes=" + errCodeDes +
109+
", mchBillno=" + mchBillno +
110+
", mchId=" + mchId +
111+
", wxappid=" + wxappid +
112+
", reOpenid=" + reOpenid +
113+
", totalAmount=" + totalAmount +
114+
", sendTime=" + sendTime +
115+
", sendListid=" + sendListid +
116+
'}';
117+
}
118+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package me.chanjar.weixin.mp.bean;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import org.junit.Before;
6+
import org.junit.Test;
7+
8+
import com.thoughtworks.xstream.XStream;
9+
10+
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
11+
import me.chanjar.weixin.mp.bean.result.WxRedpackResult;
12+
13+
public class WxRedpackResultTest {
14+
15+
private XStream xstream;
16+
17+
@Before
18+
public void setup() {
19+
xstream = XStreamInitializer.getInstance();
20+
xstream.processAnnotations(WxRedpackResult.class);
21+
}
22+
23+
@Test public void loadSuccessResult() {
24+
final String successSample = "<xml>\n" +
25+
"<return_code><![CDATA[SUCCESS]]></return_code>\n" +
26+
"<return_msg><![CDATA[发放成功.]]></return_msg>\n" +
27+
"<result_code><![CDATA[SUCCESS]]></result_code>\n" +
28+
"<err_code><![CDATA[0]]></err_code>\n" +
29+
"<err_code_des><![CDATA[发放成功.]]></err_code_des>\n" +
30+
"<mch_billno><![CDATA[0010010404201411170000046545]]></mch_billno>\n" +
31+
"<mch_id>10010404</mch_id>\n" +
32+
"<wxappid><![CDATA[wx6fa7e3bab7e15415]]></wxappid>\n" +
33+
"<re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid>\n" +
34+
"<total_amount>1</total_amount>\n" +
35+
"<send_listid>100000000020150520314766074200</send_listid>\n" +
36+
"<send_time>20150520102602</send_time>\n" +
37+
"</xml>";
38+
WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(successSample);
39+
assertEquals("SUCCESS", wxMpRedpackResult.getReturnCode());
40+
assertEquals("SUCCESS", wxMpRedpackResult.getResultCode());
41+
assertEquals("20150520102602", wxMpRedpackResult.getSendTime());
42+
}
43+
44+
@Test public void loadFailureResult() {
45+
final String failureSample = "<xml>\n" +
46+
"<return_code><![CDATA[FAIL]]></return_code>\n" +
47+
"<return_msg><![CDATA[系统繁忙,请稍后再试.]]></return_msg>\n" +
48+
"<result_code><![CDATA[FAIL]]></result_code>\n" +
49+
"<err_code><![CDATA[268458547]]></err_code>\n" +
50+
"<err_code_des><![CDATA[系统繁忙,请稍后再试.]]></err_code_des>\n" +
51+
"<mch_billno><![CDATA[0010010404201411170000046542]]></mch_billno>\n" +
52+
"<mch_id>10010404</mch_id>\n" +
53+
"<wxappid><![CDATA[wx6fa7e3bab7e15415]]></wxappid>\n" +
54+
"<re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid>\n" +
55+
"<total_amount>1</total_amount>\n" +
56+
"</xml>";
57+
WxRedpackResult wxMpRedpackResult = (WxRedpackResult) xstream.fromXML(failureSample);
58+
assertEquals("FAIL", wxMpRedpackResult.getReturnCode());
59+
assertEquals("FAIL", wxMpRedpackResult.getResultCode());
60+
assertEquals("onqOjjmM1tad-3ROpncN-yUfa6uI", wxMpRedpackResult.getReOpenid());
61+
assertEquals(1, wxMpRedpackResult.getTotalAmount());
62+
}
63+
}

0 commit comments

Comments
 (0)