From 4dc297c5edcc20733b5afc6bea9e788f1432e465 Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Sun, 25 Jan 2015 11:17:48 +0800 Subject: [PATCH 01/19] upgrade to 1.1.2-SNAPSHOT --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 33d70220..64159e26 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 me.chanjar weixin-java-parent - 1.1.1 + 1.1.2-SNAPSHOT pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 3df66581..343ce2ce 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.1 + 1.1.2-SNAPSHOT weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index d9b364f7..f89523b9 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.1 + 1.1.2-SNAPSHOT weixin-java-cp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 3e1cf571..54003ac0 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.1 + 1.1.2-SNAPSHOT weixin-java-mp WeiXin Java Tools - MP From 6d383fa90e1b9315b3bfce48ba4f8e1339ae20ae Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Tue, 27 Jan 2015 13:34:14 +0800 Subject: [PATCH 02/19] =?UTF-8?q?issue=20#90=20WxMpUser=E6=B7=BB=E5=8A=A0s?= =?UTF-8?q?exId=E5=AD=97=E6=AE=B5=EF=BC=8C=E5=92=8C=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=9A=84=E6=80=A7=E5=88=AB=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chanjar/weixin/mp/bean/result/WxMpUser.java | 17 +++++++++++++++-- .../weixin/mp/util/json/WxMpGsonBuilder.java | 2 +- ...sonAdapter.java => WxMpUserGsonAdapter.java} | 9 +++++---- 3 files changed, 21 insertions(+), 7 deletions(-) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/{WxUserGsonAdapter.java => WxMpUserGsonAdapter.java} (87%) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java index 554a07db..e9e1d17d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java @@ -20,7 +20,11 @@ public class WxMpUser { protected String headImgUrl; protected Long subscribeTime; protected String unionId; - + protected Integer sexId; + + public Boolean getSubscribe() { + return subscribe; + } public Boolean isSubscribe() { return subscribe; } @@ -87,7 +91,16 @@ public class WxMpUser { public void setUnionId(String unionId) { this.unionId = unionId; } - + + public Integer getSexId() { + + return sexId; + } + + public void setSexId(Integer sexId) { + this.sexId = sexId; + } + public static WxMpUser fromJson(String json) { return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index 73083d8c..132c0415 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -16,7 +16,7 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMpMassGroupMessage.class, new WxMpMassGroupMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassOpenIdsMessage.class, new WxMpMassOpenIdsMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpGroup.class, new WxMpGroupGsonAdapter()); - INSTANCE.registerTypeAdapter(WxMpUser.class, new WxUserGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpUser.class, new WxMpUserGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpUserList.class, new WxUserListGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpMassVideo.class, new WxMpMassVideoAdapter()); INSTANCE.registerTypeAdapter(WxMpMassSendResult.class, new WxMpMassSendResultAdapter()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java similarity index 87% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java index 462994f6..ba6caaac 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserGsonAdapter.java @@ -14,7 +14,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpUser; import java.lang.reflect.Type; -public class WxUserGsonAdapter implements JsonDeserializer { +public class WxMpUserGsonAdapter implements JsonDeserializer { public WxMpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject o = json.getAsJsonObject(); @@ -29,10 +29,11 @@ public class WxUserGsonAdapter implements JsonDeserializer { wxMpUser.setProvince(GsonHelper.getString(o, "province")); wxMpUser.setSubscribeTime(GsonHelper.getLong(o, "subscribe_time")); wxMpUser.setUnionId(GsonHelper.getString(o, "unionid")); - Integer sex = GsonHelper.getInteger(o, "sex"); - if(new Integer(1).equals(sex)) { + Integer sexId = GsonHelper.getInteger(o, "sex"); + wxMpUser.setSexId(sexId); + if(new Integer(1).equals(sexId)) { wxMpUser.setSex("男"); - } else if (new Integer(2).equals(sex)) { + } else if (new Integer(2).equals(sexId)) { wxMpUser.setSex("女"); } else { wxMpUser.setSex("未知"); From 5b49c63d148e8f81c479217933135d4c2d4b44fe Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Tue, 27 Jan 2015 14:45:11 +0800 Subject: [PATCH 03/19] =?UTF-8?q?issue=20#91=20=E6=B7=BB=E5=8A=A0=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=8F=B7JS=5FAPI=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WxErrorExceptionHandler.java | 2 +- .../WxMessageDuplicateChecker.java | 2 +- .../WxMessageInMemoryDuplicateChecker.java | 2 +- .../weixin/common/bean/WxJsapiSignature.java | 4 +- .../common/util/LogExceptionHandler.java | 1 + .../weixin/common/util/RandomUtils.java | 17 +++++ ...WxMessageInMemoryDuplicateCheckerTest.java | 1 + .../weixin/cp/api/WxCpConfigStorage.java | 14 ++++ .../cp/api/WxCpInMemoryConfigStorage.java | 36 ++++++++++ .../weixin/cp/api/WxCpMessageRouter.java | 12 ++-- .../weixin/cp/api/WxCpMessageRouterRule.java | 2 +- .../weixin/cp/api/WxCpServiceImpl.java | 60 +++++++++++++++- .../java/TestNonAtomicLongAssignment.java | 68 +++++++++++++++++++ .../mp/api/WxMpInMemoryConfigStorage.java | 13 +++- .../weixin/mp/api/WxMpMessageRouter.java | 12 ++-- .../weixin/mp/api/WxMpMessageRouterRule.java | 2 +- .../me/chanjar/weixin/mp/api/WxMpService.java | 5 +- .../weixin/mp/api/WxMpServiceImpl.java | 21 ++---- 18 files changed, 232 insertions(+), 42 deletions(-) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/{util => api}/WxErrorExceptionHandler.java (82%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/{util => api}/WxMessageDuplicateChecker.java (96%) rename weixin-java-common/src/main/java/me/chanjar/weixin/common/{util => api}/WxMessageInMemoryDuplicateChecker.java (98%) rename weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpJsapiSignature.java => weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java (91%) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java create mode 100644 weixin-java-mp/src/main/java/TestNonAtomicLongAssignment.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxErrorExceptionHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java similarity index 82% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxErrorExceptionHandler.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java index 70940aef..9abda804 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxErrorExceptionHandler.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxErrorExceptionHandler.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util; +package me.chanjar.weixin.common.api; import me.chanjar.weixin.common.exception.WxErrorException; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java similarity index 96% rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageDuplicateChecker.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java index 1abe588b..6cdb689a 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageDuplicateChecker.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageDuplicateChecker.java @@ -1,4 +1,4 @@ -package me.chanjar.weixin.common.util; +package me.chanjar.weixin.common.api; /** *
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateChecker.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java
similarity index 98%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateChecker.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java
index ae0e0623..1efc7a27 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateChecker.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java
@@ -1,4 +1,4 @@
-package me.chanjar.weixin.common.util;
+package me.chanjar.weixin.common.api;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpJsapiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
similarity index 91%
rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpJsapiSignature.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
index a09c4082..c01d6c61 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpJsapiSignature.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
@@ -1,9 +1,9 @@
-package me.chanjar.weixin.mp.bean.result;
+package me.chanjar.weixin.common.bean;
 
 /**
  * jspai signature
  */
-public class WxMpJsapiSignature {
+public class WxJsapiSignature {
 
   private String noncestr;
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/LogExceptionHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/LogExceptionHandler.java
index 1fa1af75..a512e599 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/LogExceptionHandler.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/LogExceptionHandler.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.common.util;
 
+import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
 import me.chanjar.weixin.common.exception.WxErrorException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java
new file mode 100644
index 00000000..bbb11992
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.common.util;
+
+public class RandomUtils {
+
+  private static final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+  private static final java.util.Random RANDOM = new java.util.Random();
+
+  public static String getRandomStr() {
+    StringBuilder sb = new StringBuilder();
+    for (int i = 0; i < 16; i++) {
+      sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length())));
+    }
+    return sb.toString();
+  }
+
+}
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java
index 28642c44..7369d637 100644
--- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.common.util;
 
+import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java
index 44123a36..94029841 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java
@@ -22,6 +22,20 @@ public interface WxCpConfigStorage {
 
   public void updateAccessToken(String accessToken, int expiresIn);
 
+  public String getJsapiTicket();
+
+  public boolean isJsapiTicketExpired();
+
+  /**
+   * 强制将jsapi ticket过期掉
+   */
+  public void expireJsapiTicket();
+
+  /**
+   * 应该是线程安全的
+   * @param jsapiTicket
+   */
+  public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
 
   public String getCorpId();
   
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java
index b7f662cd..59fc6f2a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java
@@ -25,6 +25,9 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
   protected volatile String http_proxy_username;
   protected volatile String http_proxy_password;
 
+  protected volatile String jsapiTicket;
+  protected volatile long jsapiTicketExpiresTime;
+
   public String getAccessToken() {
     return this.accessToken;
   }
@@ -46,6 +49,37 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
     this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
   }
 
+  @Override
+  public String getJsapiTicket() {
+    return jsapiTicket;
+  }
+
+  public void setJsapiTicket(String jsapiTicket) {
+    this.jsapiTicket = jsapiTicket;
+  }
+
+  public long getJsapiTicketExpiresTime() {
+    return jsapiTicketExpiresTime;
+  }
+
+  public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) {
+    this.jsapiTicketExpiresTime = jsapiTicketExpiresTime;
+  }
+
+  public boolean isJsapiTicketExpired() {
+    return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
+  }
+
+  public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
+    this.jsapiTicket = jsapiTicket;
+    // 预留200秒的时间
+    this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l;
+  }
+
+  public void expireJsapiTicket() {
+    this.jsapiTicketExpiresTime = 0;
+  }
+
   public String getCorpId() {
     return this.corpId;
   }
@@ -153,6 +187,8 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage {
         ", http_proxy_port=" + http_proxy_port +
         ", http_proxy_username='" + http_proxy_username + '\'' +
         ", http_proxy_password='" + http_proxy_password + '\'' +
+        ", jsapiTicket='" + jsapiTicket + '\'' +
+        ", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' +
         '}';
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
index 52f16bf5..29798b91 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
@@ -5,9 +5,9 @@ import me.chanjar.weixin.common.session.InternalSessionManager;
 import me.chanjar.weixin.common.session.StandardSessionManager;
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.common.util.LogExceptionHandler;
-import me.chanjar.weixin.common.util.WxErrorExceptionHandler;
-import me.chanjar.weixin.common.util.WxMessageDuplicateChecker;
-import me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker;
+import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
+import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
+import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
 import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
 import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
 import org.slf4j.Logger;
@@ -87,8 +87,8 @@ public class WxCpMessageRouter {
 
   /**
    * 
-   * 设置自定义的 {@link me.chanjar.weixin.common.util.WxMessageDuplicateChecker}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker}
+   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
    * 
* @param messageDuplicateChecker */ @@ -109,7 +109,7 @@ public class WxCpMessageRouter { /** *
-   * 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler}
+   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
    * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
    * 
* @param exceptionHandler diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java index 7fb253c7..cf453938 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java @@ -2,7 +2,7 @@ package me.chanjar.weixin.cp.api; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java index 3f14a53c..3fc393b0 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java @@ -8,6 +8,7 @@ import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.WxMenu; import me.chanjar.weixin.common.bean.result.WxError; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; @@ -15,6 +16,7 @@ import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSession; import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.StringUtils; import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.fs.FileUtils; @@ -44,6 +46,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.UUID; @@ -54,7 +57,12 @@ public class WxCpServiceImpl implements WxCpService { /** * 全局的是否正在刷新access token的锁 */ - protected static final Object GLOBAL_ACCESS_TOKEN_REFRESH_LOCK = new Object(); + protected final Object globalAccessTokenRefreshLock = new Object(); + + /** + * 全局的是否正在刷新jsapi_ticket的锁 + */ + protected final Object globalJsapiTicketRefreshLock = new Object(); protected WxCpConfigStorage wxCpConfigStorage; @@ -90,7 +98,7 @@ public class WxCpServiceImpl implements WxCpService { wxCpConfigStorage.expireAccessToken(); } if (wxCpConfigStorage.isAccessTokenExpired()) { - synchronized (GLOBAL_ACCESS_TOKEN_REFRESH_LOCK) { + synchronized (globalAccessTokenRefreshLock) { if (wxCpConfigStorage.isAccessTokenExpired()) { String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + "&corpid=" + wxCpConfigStorage.getCorpId() @@ -121,6 +129,52 @@ public class WxCpServiceImpl implements WxCpService { return wxCpConfigStorage.getAccessToken(); } + public String getJsapiTicket() throws WxErrorException { + return getJsapiTicket(false); + } + + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException { + if (forceRefresh) { + wxCpConfigStorage.expireJsapiTicket(); + } + if (wxCpConfigStorage.isJsapiTicketExpired()) { + synchronized (globalJsapiTicketRefreshLock) { + if (wxCpConfigStorage.isJsapiTicketExpired()) { + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi"; + String responseContent = execute(new SimpleGetRequestExecutor(), url, null); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject(); + String jsapiTicket = tmpJsonObject.get("ticket").getAsString(); + int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt(); + wxCpConfigStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds); + } + } + } + return wxCpConfigStorage.getJsapiTicket(); + } + + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException { + long timestamp = System.currentTimeMillis() / 1000; + String noncestr = RandomUtils.getRandomStr(); + String jsapiTicket = getJsapiTicket(false); + try { + String signature = SHA1.genWithAmple( + "jsapi_ticket=" + jsapiTicket, + "noncestr=" + noncestr, + "timestamp=" + timestamp, + "url=" + url + ); + WxJsapiSignature jsapiSignature = new WxJsapiSignature(); + jsapiSignature.setTimestamp(timestamp); + jsapiSignature.setNoncestr(noncestr); + jsapiSignature.setUrl(url); + jsapiSignature.setSignature(signature); + return jsapiSignature; + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + public void messageSend(WxCpMessage message) throws WxErrorException { String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send"; post(url, message.toJson()); @@ -477,7 +531,7 @@ public class WxCpServiceImpl implements WxCpService { * 42001 access_token超时 */ if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001) { - // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token + // 强制设置wxCpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token wxCpConfigStorage.expireAccessToken(); return execute(executor, uri, data); } diff --git a/weixin-java-mp/src/main/java/TestNonAtomicLongAssignment.java b/weixin-java-mp/src/main/java/TestNonAtomicLongAssignment.java new file mode 100644 index 00000000..e86d89fe --- /dev/null +++ b/weixin-java-mp/src/main/java/TestNonAtomicLongAssignment.java @@ -0,0 +1,68 @@ +/** + * Created by qianjia on 15/1/25. + */ +public class TestNonAtomicLongAssignment { + + private static final long HI = 1l << 32; + private static final long LO = 1l; + + private static final long TEST_NUMBER = HI | LO; + + private static long assignee = 0l; + + public static void main(String[] args) { + + Thread writer = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + assignee = TEST_NUMBER; + } + } + }); + writer.setDaemon(true); + + Thread reader = new Thread(new Runnable() { + @Override + public void run() { + long i = 0; + while (true) { + i++; + long test = assignee; + if (test != TEST_NUMBER) { + System.out.print(i + " times:" + toBin(test)); + break; + } + } + } + }); + + // Thread worker = new Thread(new Runnable() { + // @Override + // public void run() { + // double d = 89009808877238948224343435452333323113131313133434434341212323232424243434335354232390490189190420928348910913094983.323334401928d; + // while(true) { + // Math.cbrt(d); + // d = d - 1l; + // } + // } + // }); + // worker.setDaemon(true); + // worker.start(); + + writer.start(); + reader.start(); + + } + + public static String toBin(long n) { + StringBuilder sb = new StringBuilder(Long.toBinaryString(n)); + int padding = 64 - sb.length(); + while (padding > 0) { + sb.insert(0, '0'); + padding--; + } + return sb.toString(); + } + +} 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 f1fb8fe6..3033d178 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 @@ -51,6 +51,18 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { return jsapiTicket; } + public void setJsapiTicket(String jsapiTicket) { + this.jsapiTicket = jsapiTicket; + } + + public long getJsapiTicketExpiresTime() { + return jsapiTicketExpiresTime; + } + + public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) { + this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; + } + public boolean isJsapiTicketExpired() { return System.currentTimeMillis() > this.jsapiTicketExpiresTime; } @@ -167,5 +179,4 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { ", jsapiTicketExpiresTime='" + jsapiTicketExpiresTime + '\'' + '}'; } - } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index 1cd2f580..d98c6a4a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -5,9 +5,9 @@ import me.chanjar.weixin.common.session.InternalSessionManager; import me.chanjar.weixin.common.session.StandardSessionManager; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.LogExceptionHandler; -import me.chanjar.weixin.common.util.WxErrorExceptionHandler; -import me.chanjar.weixin.common.util.WxMessageDuplicateChecker; -import me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; +import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; import org.slf4j.Logger; @@ -87,8 +87,8 @@ public class WxMpMessageRouter { /** *
-   * 设置自定义的 {@link me.chanjar.weixin.common.util.WxMessageDuplicateChecker}
-   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker}
+   * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
+   * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
    * 
* @param messageDuplicateChecker */ @@ -109,7 +109,7 @@ public class WxMpMessageRouter { /** *
-   * 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler}
+   * 设置自定义的{@link me.chanjar.weixin.common.api.WxErrorExceptionHandler}
    * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler}
    * 
* @param exceptionHandler diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java index 95db8ab4..5f27dab0 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java @@ -2,7 +2,7 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; -import me.chanjar.weixin.common.util.WxErrorExceptionHandler; +import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 7d1d6dcf..b2750871 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -1,10 +1,9 @@ package me.chanjar.weixin.mp.api; import me.chanjar.weixin.common.bean.WxMenu; +import me.chanjar.weixin.common.bean.WxJsapiSignature; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; -import me.chanjar.weixin.common.session.WxSession; -import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.mp.bean.*; import me.chanjar.weixin.mp.bean.result.*; @@ -86,7 +85,7 @@ public interface WxMpService { * @param url url * @return */ - public WxMpJsapiSignature createJsapiSignature(String url) throws WxErrorException; + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; /** *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
index 9f719140..f44ba14d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
@@ -7,11 +7,13 @@ import com.google.gson.reflect.TypeToken;
 import com.google.gson.stream.JsonReader;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.bean.WxMenu;
+import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.bean.result.WxError;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.exception.WxErrorException;
 import me.chanjar.weixin.common.session.StandardSessionManager;
 import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.common.util.RandomUtils;
 import me.chanjar.weixin.common.util.StringUtils;
 import me.chanjar.weixin.common.util.crypto.SHA1;
 import me.chanjar.weixin.common.util.fs.FileUtils;
@@ -42,15 +44,10 @@ import java.io.InputStream;
 import java.io.StringReader;
 import java.security.NoSuchAlgorithmException;
 import java.util.List;
-import java.util.Random;
 import java.util.UUID;
 
 public class WxMpServiceImpl implements WxMpService {
 
-  protected final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-  protected final Random RANDOM = new Random();
-
   protected final Logger log = LoggerFactory.getLogger(WxMpServiceImpl.class);
 
   /**
@@ -148,9 +145,9 @@ public class WxMpServiceImpl implements WxMpService {
     return wxMpConfigStorage.getJsapiTicket();
   }
 
-  public WxMpJsapiSignature createJsapiSignature(String url) throws WxErrorException {
+  public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException {
     long timestamp = System.currentTimeMillis() / 1000;
-    String noncestr = getRandomStr();
+    String noncestr = RandomUtils.getRandomStr();
     String jsapiTicket = getJsapiTicket(false);
     try {
       String signature = SHA1.genWithAmple(
@@ -159,7 +156,7 @@ public class WxMpServiceImpl implements WxMpService {
           "timestamp=" + timestamp,
           "url=" + url
       );
-      WxMpJsapiSignature jsapiSignature = new WxMpJsapiSignature();
+      WxJsapiSignature jsapiSignature = new WxJsapiSignature();
       jsapiSignature.setTimestamp(timestamp);
       jsapiSignature.setNoncestr(noncestr);
       jsapiSignature.setUrl(url);
@@ -170,14 +167,6 @@ public class WxMpServiceImpl implements WxMpService {
     }
   }
 
-  protected String getRandomStr() {
-    StringBuilder sb = new StringBuilder();
-    for (int i = 0; i < 16; i++) {
-      sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length())));
-    }
-    return sb.toString();
-  }
-
   public void customMessageSend(WxMpCustomMessage message) throws WxErrorException {
     String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
     execute(new SimplePostRequestExecutor(), url, message.toJson());

From 4740f1f37b92a4f1ecfd09aa617c75aeff5fcfa5 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Tue, 27 Jan 2015 15:53:29 +0800
Subject: [PATCH 04/19] issue #91

---
 .../me/chanjar/weixin/cp/api/WxCpService.java | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
index 3c84bec8..633c8164 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.cp.api;
 
+import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.bean.WxMenu;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.exception.WxErrorException;
@@ -67,6 +68,38 @@ public interface WxCpService {
    */
   String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
+  /**
+   * 获得jsapi_ticket,不强制刷新jsapi_ticket
+   * @see #getJsapiTicket(boolean)
+   * @return
+   * @throws WxErrorException
+   */
+  public String getJsapiTicket() throws WxErrorException;
+
+  /**
+   * 
+   * 获得jsapi_ticket
+   * 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   *
+   * 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
+   * 
+ * @param forceRefresh 强制刷新 + * @return + * @throws WxErrorException + */ + public String getJsapiTicket(boolean forceRefresh) throws WxErrorException; + + /** + *
+   * 创建调用jsapi时所需要的签名
+   *
+   * 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
+   * 
+ * @param url url + * @return + */ + public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; + /** *
    * 上传多媒体文件

From 3ae057af8fe6ac523c6e317d2994cc5927490311 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 4 Feb 2015 11:43:07 +0800
Subject: [PATCH 05/19] =?UTF-8?q?issue=20#95=20=E8=8E=B7=E5=8F=96=E5=85=B3?=
 =?UTF-8?q?=E6=B3=A8=E8=80=85=E5=88=97=E8=A1=A8userList=E6=96=B9=E6=B3=95?=
 =?UTF-8?q?=EF=BC=8C=E5=BD=93=E6=B2=A1=E6=9C=89=E5=85=B3=E6=B3=A8=E8=80=85?=
 =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=8A=A5=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/mp/util/json/WxUserListGsonAdapter.java        | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java
index 5be3d160..12bdf823 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxUserListGsonAdapter.java
@@ -22,9 +22,11 @@ public class WxUserListGsonAdapter implements JsonDeserializer {
     wxMpUserList.setTotal(GsonHelper.getInteger(o, "total"));
     wxMpUserList.setCount(GsonHelper.getInteger(o, "count"));
     wxMpUserList.setNextOpenId(GsonHelper.getString(o, "next_openid"));
-    JsonArray data = o.get("data").getAsJsonObject().get("openid").getAsJsonArray();
-    for (int i = 0; i < data.size(); i++) {
-      wxMpUserList.getOpenIds().add(GsonHelper.getAsString(data.get(i)));
+    if (!o.get("data").isJsonNull() && !o.get("data").getAsJsonObject().get("openid").isJsonNull()) {
+      JsonArray data = o.get("data").getAsJsonObject().get("openid").getAsJsonArray();
+      for (int i = 0; i < data.size(); i++) {
+        wxMpUserList.getOpenIds().add(GsonHelper.getAsString(data.get(i)));
+      }
     }
     return wxMpUserList;
   }

From 1e5e09877566cdc937e236bc7102f1fc24a88c75 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 4 Feb 2015 11:45:12 +0800
Subject: [PATCH 06/19] issue #92 A bug in
 me.chanjar.weixin.mp.api.WxMpServiceImpl.java at line 449

---
 .../src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
index f44ba14d..92d31318 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java
@@ -435,7 +435,7 @@ public class WxMpServiceImpl implements WxMpService {
   @Override
   public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) {
     String url = "https://api.weixin.qq.com/sns/auth?";
-    url += "access_token=" + oAuth2AccessToken;
+    url += "access_token=" + oAuth2AccessToken.getAccessToken();
     url += "&openid=" + oAuth2AccessToken.getOpenId();
 
     try {

From 95d8bd3c47f93bc4b722fd3067d39e0bf904b21c Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 4 Feb 2015 11:49:01 +0800
Subject: [PATCH 07/19] =?UTF-8?q?issue=20#99=20Wx*MessageRouter.isDuplicat?=
 =?UTF-8?q?eMessage=E6=96=B9=E6=B3=95=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java   | 2 +-
 .../main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
index 29798b91..7c588372 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
@@ -204,7 +204,7 @@ public class WxCpMessageRouter {
       messageId = String.valueOf(wxMessage.getCreateTime())
           + "-" +String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId())
           + "-" + wxMessage.getFromUserName()
-          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEvent());
+          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey());
       ;
     } else {
       messageId = String.valueOf(wxMessage.getMsgId());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
index d98c6a4a..8fd0d480 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
@@ -203,7 +203,7 @@ public class WxMpMessageRouter {
     if (wxMessage.getMsgId() == null) {
       messageId = String.valueOf(wxMessage.getCreateTime())
           + "-" + wxMessage.getFromUserName()
-          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEvent());
+          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey());
       ;
     } else {
       messageId = String.valueOf(wxMessage.getMsgId());

From 57e9beaae0dae1b1fa1d7a39bcfa7ade031fd2af Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 4 Feb 2015 17:09:15 +0800
Subject: [PATCH 08/19] =?UTF-8?q?issue=20#91=20=E6=B7=BB=E5=8A=A0=E4=BC=81?=
 =?UTF-8?q?=E4=B8=9A=E5=8F=B7JS=5FAPI=E7=9A=84=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
index 3fc393b0..c15a4ec2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
@@ -140,7 +140,7 @@ public class WxCpServiceImpl implements WxCpService {
     if (wxCpConfigStorage.isJsapiTicketExpired()) {
       synchronized (globalJsapiTicketRefreshLock) {
         if (wxCpConfigStorage.isJsapiTicketExpired()) {
-          String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
+          String url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket";
           String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
           JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
           JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();

From d2eb529ab2f0ff177bd22a288119b6259c191349 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 4 Feb 2015 17:12:02 +0800
Subject: [PATCH 09/19] =?UTF-8?q?issue=20#99=20Wx*MessageRouter.isDuplicat?=
 =?UTF-8?q?eMessage=E6=96=B9=E6=B3=95=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java  | 3 ++-
 .../main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java  | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
index 7c588372..2c3722f4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
@@ -204,7 +204,8 @@ public class WxCpMessageRouter {
       messageId = String.valueOf(wxMessage.getCreateTime())
           + "-" +String.valueOf(wxMessage.getAgentId() == null ? "" : wxMessage.getAgentId())
           + "-" + wxMessage.getFromUserName()
-          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey());
+          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey())
+          + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent())
       ;
     } else {
       messageId = String.valueOf(wxMessage.getMsgId());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
index 8fd0d480..2c610f07 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
@@ -203,7 +203,8 @@ public class WxMpMessageRouter {
     if (wxMessage.getMsgId() == null) {
       messageId = String.valueOf(wxMessage.getCreateTime())
           + "-" + wxMessage.getFromUserName()
-          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey());
+          + "-" + String.valueOf(wxMessage.getEventKey() == null ? "" : wxMessage.getEventKey())
+          + "-" + String.valueOf(wxMessage.getEvent() == null ? "" : wxMessage.getEvent())
       ;
     } else {
       messageId = String.valueOf(wxMessage.getMsgId());

From 1e94c452ba870361ab7254a50a6f5ec438d628ef Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Mon, 9 Feb 2015 09:07:54 +0800
Subject: [PATCH 10/19] =?UTF-8?q?issue=20#104=20WxCpService.oauth2getUserI?=
 =?UTF-8?q?nfo=E6=96=B9=E6=B3=95=E4=B8=8D=E4=BC=9A=E5=8E=BB=E5=88=B7?=
 =?UTF-8?q?=E6=96=B0access=20token?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/api/WxCpServiceImpl.java        | 23 ++++++-------------
 1 file changed, 7 insertions(+), 16 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
index c15a4ec2..79259957 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
@@ -427,22 +427,13 @@ public class WxCpServiceImpl implements WxCpService {
 
   @Override
   public String[] oauth2getUserInfo(String code) throws WxErrorException {
-    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?";
-    url += "access_token=" + wxCpConfigStorage.getAccessToken();
-    url += "&code=" + code;
-    url += "&agendid=" + wxCpConfigStorage.getAgentId();
-
-    try {
-      RequestExecutor executor = new SimpleGetRequestExecutor();
-      String responseText = executor.execute(getHttpclient(), httpProxy, url, null);
-      JsonElement je = Streams.parse(new JsonReader(new StringReader(responseText)));
-      JsonObject jo = je.getAsJsonObject();
-      return new String[] {GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId")};
-    } catch (ClientProtocolException e) {
-      throw new RuntimeException(e);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
+    String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?"
+                    + "code=" + code
+                    + "&agendid=" + wxCpConfigStorage.getAgentId();
+    String responseText = get(url, null);
+    JsonElement je = Streams.parse(new JsonReader(new StringReader(responseText)));
+    JsonObject jo = je.getAsJsonObject();
+    return new String[] {GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId")};
   }
 
   @Override

From 7e46113bbc24c94bb818998a67d2b48df3deca9d Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Mon, 9 Feb 2015 09:30:44 +0800
Subject: [PATCH 11/19] add travis support

---
 .travis.yml | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 .travis.yml

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..8acf0fc0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+language: java
+jdk:
+  - oraclejdk7
+
+script: "mvn clean deploy -Dmaven.test.skip=true"
+
+branches:
+  only:
+    - develop
+
+notifications:
+  email:
+    - chanjarster@gmail.com

From dc9161844e392881b7049e3e875cad01894e03c5 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Mon, 9 Feb 2015 09:35:35 +0800
Subject: [PATCH 12/19] add travis support

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 8acf0fc0..ea75f1c1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: java
 jdk:
   - oraclejdk7
 
-script: "mvn clean deploy -Dmaven.test.skip=true"
+script: "mvn clean install -Dmaven.test.skip=true"
 
 branches:
   only:

From 8e7fcc64b33d7f21eceb5649392503244babf229 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Mon, 9 Feb 2015 09:41:03 +0800
Subject: [PATCH 13/19] add travis status

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 495fbad7..0baa3e91 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-weixin-java-tools
+weixin-java-tools[![Build Status](https://travis-ci.org/chanjarster/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/chanjarster/weixin-java-tools)
 ===========
 
 微信公众号、企业号Java SDK。

From 2a439a6690333e8451bdbc2c42d29c341d46a7fa Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Tue, 10 Feb 2015 14:10:25 +0800
Subject: [PATCH 14/19] =?UTF-8?q?issue=20#107=20=E8=AF=B7=E7=BB=99?=
 =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=8A=A0=E4=B8=8ASerializable?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/me/chanjar/weixin/common/bean/WxAccessToken.java     | 4 +++-
 .../java/me/chanjar/weixin/common/bean/WxJsapiSignature.java  | 4 +++-
 .../src/main/java/me/chanjar/weixin/common/bean/WxMenu.java   | 3 ++-
 .../java/me/chanjar/weixin/common/bean/result/WxError.java    | 4 +++-
 .../weixin/common/bean/result/WxMediaUploadResult.java        | 4 +++-
 .../src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java   | 4 +++-
 .../src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java  | 3 ++-
 .../src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java      | 4 +++-
 .../src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java     | 3 ++-
 .../main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java   | 3 ++-
 .../java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java     | 3 ++-
 .../src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java    | 4 +++-
 .../java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java  | 4 +++-
 .../src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java | 3 ++-
 .../me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java     | 3 ++-
 .../main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java    | 4 +++-
 .../java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java     | 4 +++-
 .../main/java/me/chanjar/weixin/mp/bean/WxMpTemplateData.java | 4 +++-
 .../java/me/chanjar/weixin/mp/bean/WxMpTemplateMessage.java   | 3 ++-
 .../main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java   | 3 ++-
 .../java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java     | 4 +++-
 .../me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java  | 4 +++-
 .../chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java   | 4 +++-
 .../chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java  | 4 +++-
 .../me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java    | 4 +++-
 .../weixin/mp/bean/result/WxMpSemanticQueryResult.java        | 4 +++-
 .../main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java  | 4 +++-
 27 files changed, 72 insertions(+), 27 deletions(-)

diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java
index 2365daa2..c923e4f6 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxAccessToken.java
@@ -2,7 +2,9 @@ package me.chanjar.weixin.common.bean;
 
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
-public class WxAccessToken {
+import java.io.Serializable;
+
+public class WxAccessToken implements Serializable {
 
   private String accessToken;
   
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
index c01d6c61..af32310a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxJsapiSignature.java
@@ -1,9 +1,11 @@
 package me.chanjar.weixin.common.bean;
 
+import java.io.Serializable;
+
 /**
  * jspai signature
  */
-public class WxJsapiSignature {
+public class WxJsapiSignature implements Serializable {
 
   private String noncestr;
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java
index 70110230..912d47c9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java
@@ -2,6 +2,7 @@ package me.chanjar.weixin.common.bean;
 
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -12,7 +13,7 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder;
  * @author Daniel Qian
  *
  */
-public class WxMenu {
+public class WxMenu implements Serializable {
 
   private List buttons = new ArrayList();
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java
index 495ede81..e5123707 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxError.java
@@ -2,13 +2,15 @@ package me.chanjar.weixin.common.bean.result;
 
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 微信错误码说明
  * http://mp.weixin.qq.com/wiki/index.php?title=全局返回码说明
  * @author Daniel Qian
  *
  */
-public class WxError {
+public class WxError implements Serializable {
 
   private int errorCode;
   
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java
index 1695489a..0ac7fe8a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMediaUploadResult.java
@@ -2,7 +2,9 @@ package me.chanjar.weixin.common.bean.result;
 
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
-public class WxMediaUploadResult {
+import java.io.Serializable;
+
+public class WxMediaUploadResult implements Serializable {
 
   private String type;
   private String mediaId;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java
index 975cd595..04fb46fd 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpDepart.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.cp.bean;
 
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 微信部门
  *
  * @author Daniel Qian
  */
-public class WxCpDepart {
+public class WxCpDepart implements Serializable {
 
   private Integer id;
   private String name;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
index 0f5c4f82..ef645869 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
@@ -3,6 +3,7 @@ package me.chanjar.weixin.cp.bean;
 import me.chanjar.weixin.cp.bean.messagebuilder.*;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -11,7 +12,7 @@ import java.util.List;
  * @author Daniel Qian
  *
  */
-public class WxCpMessage {
+public class WxCpMessage implements Serializable {
 
   private String toUser;
   private String toParty;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java
index a56e9c5c..6c5d42c6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTag.java
@@ -2,10 +2,12 @@ package me.chanjar.weixin.cp.bean;
 
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * Created by Daniel Qian
  */
-public class WxCpTag {
+public class WxCpTag implements Serializable {
 
   private String id;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
index 2e8547d2..a5c69c01 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java
@@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.bean;
 
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -10,7 +11,7 @@ import java.util.List;
  *
  * @author Daniel Qian
  */
-public class WxCpUser {
+public class WxCpUser implements Serializable {
 
   private String userId;
   private String name;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
index 01317d0f..469bb0bd 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
@@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -25,7 +26,7 @@ import java.util.List;
  * @author Daniel Qian
  */
 @XStreamAlias("xml")
-public class WxCpXmlMessage {
+public class WxCpXmlMessage implements Serializable {
 
   ///////////////////////
   // 以下都是微信推送过来的消息的xml的element所对应的属性
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
index dc3d3baa..a19b79bd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
@@ -3,6 +3,7 @@ package me.chanjar.weixin.mp.bean;
 import me.chanjar.weixin.mp.bean.custombuilder.*;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -11,7 +12,7 @@ import java.util.List;
  * @author chanjarster
  *
  */
-public class WxMpCustomMessage {
+public class WxMpCustomMessage implements Serializable {
 
   private String toUser;
   private String msgType;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java
index cfa5fcb6..9cef8c1b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpGroup.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 微信用户分组
  * @author chanjarster
  *
  */
-public class WxMpGroup {
+public class WxMpGroup implements Serializable {
 
   private long id = -1;
   private String name;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java
index aa79c43f..b5faef72 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassGroupMessage.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 分组群发的消息
  * 
  * @author chanjarster
  */
-public class WxMpMassGroupMessage {
+public class WxMpMassGroupMessage implements Serializable {
   
   private Long groupId;
   private String msgtype;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java
index f3c67d5a..f7602838 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassNews.java
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -10,7 +11,7 @@ import java.util.List;
  * @author chanjarster
  *
  */
-public class WxMpMassNews {
+public class WxMpMassNews implements Serializable {
 
   private List articles = new ArrayList();
   
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
index b542162b..7ef2535c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -10,7 +11,7 @@ import java.util.List;
  * 
  * @author chanjarster
  */
-public class WxMpMassOpenIdsMessage {
+public class WxMpMassOpenIdsMessage implements Serializable {
   
   private List toUsers = new ArrayList();
   private String msgType;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java
index 3dc6c5d7..c2f04610 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassVideo.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 群发时用到的视频素材
  * 
  * @author chanjarster
  */
-public class WxMpMassVideo {
+public class WxMpMassVideo implements Serializable {
 
   private String mediaId;
   private String title;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java
index aac3bd10..faf0ec77 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpSemanticQuery.java
@@ -2,6 +2,8 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 语义理解查询用对象
  *
@@ -9,7 +11,7 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
  *
  * @author Daniel Qian
  */
-public class WxMpSemanticQuery {
+public class WxMpSemanticQuery implements Serializable {
 
   private String query;
   private String category;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateData.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateData.java
index e328fe85..51d29e28 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateData.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateData.java
@@ -1,9 +1,11 @@
 package me.chanjar.weixin.mp.bean;
 
+import java.io.Serializable;
+
 /**
  * @author Daniel Qian
  */
-public class WxMpTemplateData {
+public class WxMpTemplateData implements Serializable {
 
   private String name;
   private String value;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateMessage.java
index 91441cd1..aa061e3b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpTemplateMessage.java
@@ -2,10 +2,11 @@ package me.chanjar.weixin.mp.bean;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
-public class WxMpTemplateMessage {
+public class WxMpTemplateMessage implements Serializable {
 
   private String toUser;
   private String templateId;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java
index 8e7bacf2..8796b110 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java
@@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -25,7 +26,7 @@ import java.util.List;
  * @author chanjarster
  */
 @XStreamAlias("xml")
-public class WxMpXmlMessage {
+public class WxMpXmlMessage implements Serializable {
 
   ///////////////////////
   // 以下都是微信推送过来的消息的xml的element所对应的属性
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java
index a7534bde..370d4430 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java
@@ -8,8 +8,10 @@ import me.chanjar.weixin.mp.bean.outxmlbuilder.*;
 import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
 import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
 
+import java.io.Serializable;
+
 @XStreamAlias("xml")
-public abstract class WxMpXmlOutMessage {
+public abstract class WxMpXmlOutMessage implements Serializable {
 
   @XStreamAlias("ToUserName")
   @XStreamConverter(value=XStreamCDataConverter.class)
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java
index 9b5df2b8..adf6ebbc 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassSendResult.java
@@ -2,6 +2,8 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 
  * 群发消息一发送就返回的结果
@@ -13,7 +15,7 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
  * @author chanjarster
  *
  */
-public class WxMpMassSendResult {
+public class WxMpMassSendResult implements Serializable {
 
   private String errorCode;
   private String errorMsg;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
index e0ed145b..7100c630 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpMassUploadResult.java
@@ -2,6 +2,8 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 
  * 上传群发用的素材的结果
@@ -10,7 +12,7 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
  * @author chanjarster
  *
  */
-public class WxMpMassUploadResult {
+public class WxMpMassUploadResult implements Serializable {
 
   private String type;
   private String mediaId;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java
index e2d0d1a0..2d6696d4 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java
@@ -2,7 +2,9 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
-public class WxMpOAuth2AccessToken {
+import java.io.Serializable;
+
+public class WxMpOAuth2AccessToken implements Serializable {
 
   private String accessToken;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java
index bf240c57..562820c3 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 换取二维码的Ticket
  * 
  * @author chanjarster
  */
-public class WxMpQrCodeTicket {
+public class WxMpQrCodeTicket implements Serializable {
   
   protected String ticket;
   protected int expire_seconds = -1;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java
index a0972c35..936cfbfe 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpSemanticQueryResult.java
@@ -2,6 +2,8 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 语义理解查询结果对象
  *
@@ -9,7 +11,7 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
  *
  * @author Daniel Qian
  */
-public class WxMpSemanticQueryResult {
+public class WxMpSemanticQueryResult implements Serializable {
 
   private String query;
   private String type;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java
index e9e1d17d..5223e93e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java
@@ -2,12 +2,14 @@ package me.chanjar.weixin.mp.bean.result;
 
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
+import java.io.Serializable;
+
 /**
  * 微信用户信息
  * @author chanjarster
  *
  */
-public class WxMpUser {
+public class WxMpUser implements Serializable {
 
   protected Boolean subscribe;
   protected String openId;

From b8d011e73e70c231c718f8fb8f9543128ac8e858 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 11 Feb 2015 17:56:48 +0800
Subject: [PATCH 15/19] =?UTF-8?q?issue=20#105=20WxCpService.oauth2buildAut?=
 =?UTF-8?q?horizationUrl=E6=96=B9=E6=B3=95=E8=AE=BE=E8=AE=A1=E9=94=99?=
 =?UTF-8?q?=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/me/chanjar/weixin/cp/api/WxCpService.java   | 3 ++-
 .../main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java   | 4 ++--
 .../test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java   | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
index 633c8164..164a0874 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
@@ -353,10 +353,11 @@ public interface WxCpService {
    * 构造oauth2授权的url连接
    * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
    * 
+ * @param redirectUri * @param state * @return code */ - String oauth2buildAuthorizationUrl(String state); + String oauth2buildAuthorizationUrl(String redirectUri, String state); /** *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
index 79259957..c5b5e792 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
@@ -412,10 +412,10 @@ public class WxCpServiceImpl implements WxCpService {
   }
 
   @Override
-  public String oauth2buildAuthorizationUrl(String state) {
+  public String oauth2buildAuthorizationUrl(String redirectUri, String state) {
     String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" ;
     url += "appid=" + wxCpConfigStorage.getCorpId();
-    url += "&redirect_uri=" + URIUtil.encodeURIComponent(wxCpConfigStorage.getOauth2redirectUri());
+    url += "&redirect_uri=" + URIUtil.encodeURIComponent(redirectUri);
     url += "&response_type=code";
     url += "&scope=snsapi_base";
     if (state != null) {
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
index 0dadee91..3d808945 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java
@@ -62,7 +62,7 @@ public class WxCpDemoServer {
         @Override
         public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context,
             WxCpService wxCpService, WxSessionManager sessionManager) {
-          String href = "测试oauth2";
           return WxCpXmlOutMessage
               .TEXT()

From fd24b53202ff09984bd67b2ae04c5070cb5791f3 Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Thu, 12 Feb 2015 09:42:52 +0800
Subject: [PATCH 16/19] modify README

---
 README.md | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 0baa3e91..1136a653 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,8 @@
-weixin-java-tools[![Build Status](https://travis-ci.org/chanjarster/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/chanjarster/weixin-java-tools)
+weixin-java-tools
+
+[![Build Status](https://travis-ci.org/chanjarster/weixin-java-tools.svg?branch=develop)](https://travis-ci.org/chanjarster/weixin-java-tools)
+![Maven Central](https://img.shields.io/maven-central/v/me.chanjar/weixin-java-parent.svg)
+
 ===========
 
 微信公众号、企业号Java SDK。

From fb10acf6fd815599db07264acb09f8e12f28fdda Mon Sep 17 00:00:00 2001
From: Daniel Qian 
Date: Wed, 25 Feb 2015 14:37:15 +0800
Subject: [PATCH 17/19] =?UTF-8?q?issue=20#101=20=E8=8E=B7=E5=8F=96?=
 =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=9C=8D=E5=8A=A1=E5=99=A8IP=E5=9C=B0?=
 =?UTF-8?q?=E5=9D=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../me/chanjar/weixin/mp/api/WxMpService.java | 10 +++++
 .../weixin/mp/api/WxMpServiceImpl.java        | 14 +++++++
 .../weixin/mp/api/WxMpMiscAPITest.java        | 42 +++++++++++++++++++
 weixin-java-mp/src/test/resources/testng.xml  |  1 +
 4 files changed, 67 insertions(+)
 create mode 100644 weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java

diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index b2750871..862f854b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -421,6 +421,16 @@ public interface WxMpService {
    */
   public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken);
 
+  /**
+   * 
+   * 获取微信服务器IP地址
+   * http://mp.weixin.qq.com/wiki/0/2ad4b6bfd29f30f71d39616c2a0fcedc.html
+   * 
+ * @return + * @throws WxErrorException + */ + String[] getCallbackIP() throws WxErrorException; + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 * @param url diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java index 92d31318..74268b9e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.mp.api; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.internal.Streams; @@ -451,6 +452,19 @@ public class WxMpServiceImpl implements WxMpService { return true; } + @Override + public String[] getCallbackIP() throws WxErrorException { + String url = "https://api.weixin.qq.com/cgi-bin/getcallbackip"; + String responseContent = get(url, null); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + JsonArray ipList = tmpJsonElement.getAsJsonObject().get("ip_list").getAsJsonArray(); + String[] ipArray = new String[ipList.size()]; + for (int i = 0; i < ipList.size(); i++) { + ipArray[i] = ipList.get(i).getAsString(); + } + return ipArray; + } + public String get(String url, String queryParam) throws WxErrorException { return execute(new SimpleGetRequestExecutor(), url, queryParam); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java new file mode 100644 index 00000000..0b160306 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.api; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; +import me.chanjar.weixin.mp.bean.WxMpMassNews; +import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; +import me.chanjar.weixin.mp.bean.WxMpMassVideo; +import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +/** + * + * @author chanjarster + * + */ +@Test(groups = "miscAPI", dependsOnGroups = { "baseAPI"}) +@Guice(modules = ApiTestModule.class) +public class WxMpMiscAPITest { + + @Inject + protected WxMpServiceImpl wxService; + + @Test + public void getCallbackIP() throws WxErrorException { + String[] ipArray = wxService.getCallbackIP(); + System.out.println(Arrays.toString(ipArray)); + Assert.assertNotNull(ipArray); + Assert.assertNotEquals(ipArray.length, 0); + } + +} diff --git a/weixin-java-mp/src/test/resources/testng.xml b/weixin-java-mp/src/test/resources/testng.xml index cf9c2d64..cb1263d3 100644 --- a/weixin-java-mp/src/test/resources/testng.xml +++ b/weixin-java-mp/src/test/resources/testng.xml @@ -15,6 +15,7 @@ + From 978c51b90dca88dcff55a785907663bc6f912264 Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Wed, 25 Feb 2015 15:17:52 +0800 Subject: [PATCH 18/19] =?UTF-8?q?issue=20#100=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=88=86=E6=9E=90=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../me/chanjar/weixin/mp/api/WxMpService.java | 29 ++++++++- .../weixin/mp/api/WxMpServiceImpl.java | 24 +++++++ .../mp/bean/result/WxMpUserCumulate.java | 41 ++++++++++++ .../mp/bean/result/WxMpUserSummary.java | 63 +++++++++++++++++++ .../weixin/mp/util/json/WxMpGsonBuilder.java | 2 + .../json/WxMpUserCumulateGsonAdapter.java | 47 ++++++++++++++ .../util/json/WxMpUserSummaryGsonAdapter.java | 47 ++++++++++++++ .../weixin/mp/api/WxMpMiscAPITest.java | 29 ++++++++- 8 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserCumulate.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserSummary.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java create mode 100644 weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 862f854b..68a19bbe 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -11,13 +11,16 @@ import me.chanjar.weixin.mp.bean.result.*; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.List; /** * 微信API的Service */ public interface WxMpService { - + + public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); /** *
    * 验证推送过来的消息的正确性
@@ -431,6 +434,30 @@ public interface WxMpService {
    */
   String[] getCallbackIP() throws WxErrorException;
 
+  /**
+   * 
+   * 获取用户增减数据
+   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
+   * 
+ * @param beginDate 最大时间跨度7天 + * @param endDate endDate不能早于begingDate + * @return + * @throws WxErrorException + */ + List getUserSummary(Date beginDate, Date endDate) throws WxErrorException; + + /** + *
+   * 获取累计用户数据
+   * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
+   * 
+ * @param beginDate 最大时间跨度7天 + * @param endDate endDate不能早于begingDate + * @return + * @throws WxErrorException + */ + List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException; + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 * @param url diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java index 74268b9e..059a09f3 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java @@ -44,6 +44,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.security.NoSuchAlgorithmException; +import java.util.Date; import java.util.List; import java.util.UUID; @@ -465,6 +466,29 @@ public class WxMpServiceImpl implements WxMpService { return ipArray; } + + @Override + public List getUserSummary(Date beginDate, Date endDate) throws WxErrorException { + String url = "https://api.weixin.qq.com/datacube/getusersummary"; + JsonObject param = new JsonObject(); + param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); + param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); + String responseContent = post(url, param.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), new TypeToken>(){}.getType()); + } + + @Override + public List getUserCumulate(Date beginDate, Date endDate) throws WxErrorException { + String url = "https://api.weixin.qq.com/datacube/getusercumulate"; + JsonObject param = new JsonObject(); + param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); + param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); + String responseContent = post(url, param.toString()); + JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); + return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), new TypeToken>(){}.getType()); + } + public String get(String url, String queryParam) throws WxErrorException { return execute(new SimpleGetRequestExecutor(), url, queryParam); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserCumulate.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserCumulate.java new file mode 100644 index 00000000..4c295c41 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserCumulate.java @@ -0,0 +1,41 @@ +package me.chanjar.weixin.mp.bean.result; + +import java.io.Serializable; +import java.util.Date; + +/** + *
+ * 累计用户数据接口的返回JSON数据包
+ * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
+ * 
+ */ +public class WxMpUserCumulate implements Serializable { + + private Date refDate; + + private Integer cumulateUser; + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public Integer getCumulateUser() { + return cumulateUser; + } + + public void setCumulateUser(Integer cumulateUser) { + this.cumulateUser = cumulateUser; + } + + @Override + public String toString() { + return "WxMpUserCumulate{" + + "refDate=" + refDate + + ", cumulateUser=" + cumulateUser + + '}'; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserSummary.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserSummary.java new file mode 100644 index 00000000..de61a80b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserSummary.java @@ -0,0 +1,63 @@ +package me.chanjar.weixin.mp.bean.result; + +import java.io.Serializable; +import java.util.Date; + +/** + *
+ * 用户增减数据接口的返回JSON数据包
+ * http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
+ * 
+ */ +public class WxMpUserSummary implements Serializable { + + private Date refDate; + + private Integer userSource; + + private Integer newUser; + + private Integer cancelUser; + + public Date getRefDate() { + return refDate; + } + + public void setRefDate(Date refDate) { + this.refDate = refDate; + } + + public Integer getUserSource() { + return userSource; + } + + public void setUserSource(Integer userSource) { + this.userSource = userSource; + } + + public Integer getNewUser() { + return newUser; + } + + public void setNewUser(Integer newUser) { + this.newUser = newUser; + } + + public Integer getCancelUser() { + return cancelUser; + } + + public void setCancelUser(Integer cancelUser) { + this.cancelUser = cancelUser; + } + + @Override + public String toString() { + return "WxMpUserSummary{" + + "refDate=" + refDate + + ", userSource=" + userSource + + ", newUser=" + newUser + + ", cancelUser=" + cancelUser + + '}'; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java index 132c0415..3516cb9a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpGsonBuilder.java @@ -25,6 +25,8 @@ public class WxMpGsonBuilder { INSTANCE.registerTypeAdapter(WxMpTemplateMessage.class, new WxMpTemplateMessageGsonAdapter()); INSTANCE.registerTypeAdapter(WxMpSemanticQueryResult.class, new WxMpSemanticQueryResultAdapter()); INSTANCE.registerTypeAdapter(WxMpOAuth2AccessToken.class, new WxMpOAuth2AccessTokenAdapter()); + INSTANCE.registerTypeAdapter(WxMpUserSummary.class, new WxMpUserSummaryGsonAdapter()); + INSTANCE.registerTypeAdapter(WxMpUserCumulate.class, new WxMpUserCumulateGsonAdapter()); } public static Gson create() { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java new file mode 100644 index 00000000..ab4449a6 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserCumulateGsonAdapter.java @@ -0,0 +1,47 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; +import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; + +import java.lang.reflect.Type; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * + * @author Daniel Qian + * + */ +public class WxMpUserCumulateGsonAdapter implements JsonDeserializer { + + private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + public WxMpUserCumulate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + WxMpUserCumulate cumulate = new WxMpUserCumulate(); + JsonObject summaryJsonObject = json.getAsJsonObject(); + + try { + String refDate = GsonHelper.getString(summaryJsonObject, "ref_date"); + if (refDate != null) { + cumulate.setRefDate(SIMPLE_DATE_FORMAT.parse(refDate)); + } + cumulate.setCumulateUser(GsonHelper.getInteger(summaryJsonObject, "cumulate_user")); + } catch (ParseException e) { + throw new JsonParseException(e); + } + return cumulate; + + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java new file mode 100644 index 00000000..9db88884 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpUserSummaryGsonAdapter.java @@ -0,0 +1,47 @@ +/* + * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. + * + * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended + * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction + * arose from modification of the original source, or other redistribution of this source + * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. + */ +package me.chanjar.weixin.mp.util.json; + +import com.google.gson.*; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; + +import java.lang.reflect.Type; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * @author Daniel Qian + */ +public class WxMpUserSummaryGsonAdapter implements JsonDeserializer { + + private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + public WxMpUserSummary deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + WxMpUserSummary summary = new WxMpUserSummary(); + JsonObject summaryJsonObject = json.getAsJsonObject(); + + try { + String refDate = GsonHelper.getString(summaryJsonObject, "ref_date"); + if (refDate != null) { + summary.setRefDate(SIMPLE_DATE_FORMAT.parse(refDate)); + } + summary.setUserSource(GsonHelper.getInteger(summaryJsonObject, "user_source")); + summary.setNewUser(GsonHelper.getInteger(summaryJsonObject, "new_user")); + summary.setCancelUser(GsonHelper.getInteger(summaryJsonObject, "cancel_user")); + } catch (ParseException e) { + throw new JsonParseException(e); + } + + return summary; + } + +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java index 0b160306..5f2a7392 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMiscAPITest.java @@ -4,12 +4,15 @@ import com.google.inject.Inject; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.session.WxSession; import me.chanjar.weixin.mp.bean.WxMpMassGroupMessage; import me.chanjar.weixin.mp.bean.WxMpMassNews; import me.chanjar.weixin.mp.bean.WxMpMassOpenIdsMessage; import me.chanjar.weixin.mp.bean.WxMpMassVideo; import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult; import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult; +import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpUserSummary; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Guice; @@ -17,7 +20,11 @@ import org.testng.annotations.Test; import java.io.IOException; import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Arrays; +import java.util.Date; +import java.util.List; /** * @@ -32,11 +39,31 @@ public class WxMpMiscAPITest { protected WxMpServiceImpl wxService; @Test - public void getCallbackIP() throws WxErrorException { + public void testGetCallbackIP() throws WxErrorException { String[] ipArray = wxService.getCallbackIP(); System.out.println(Arrays.toString(ipArray)); Assert.assertNotNull(ipArray); Assert.assertNotEquals(ipArray.length, 0); } + @Test + public void testGetUserSummary() throws WxErrorException, ParseException { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date beginDate = simpleDateFormat.parse("2015-01-01"); + Date endDate = simpleDateFormat.parse("2015-01-02"); + List summaries = wxService.getUserSummary(beginDate, endDate); + System.out.println(summaries); + Assert.assertNotNull(summaries); + } + + @Test + public void testGetUserCumulate() throws WxErrorException, ParseException { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date beginDate = simpleDateFormat.parse("2015-01-01"); + Date endDate = simpleDateFormat.parse("2015-01-02"); + List cumulates = wxService.getUserCumulate(beginDate, endDate); + System.out.println(cumulates); + Assert.assertNotNull(cumulates); + } + } From 316e54baaa9e7d5bf788172d9d581a84b6e47b60 Mon Sep 17 00:00:00 2001 From: Daniel Qian Date: Wed, 25 Feb 2015 15:32:33 +0800 Subject: [PATCH 19/19] upgrade to 1.1.2 --- pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 64159e26..74032e85 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 me.chanjar weixin-java-parent - 1.1.2-SNAPSHOT + 1.1.2 pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 343ce2ce..cf886ba5 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.2-SNAPSHOT + 1.1.2 weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index f89523b9..779ef63c 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.2-SNAPSHOT + 1.1.2 weixin-java-cp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 54003ac0..c4ed287e 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.1.2-SNAPSHOT + 1.1.2 weixin-java-mp WeiXin Java Tools - MP