diff --git a/pom.xml b/pom.xml index 379f5cf45..c87072185 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.9.0 + 3.9.1.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK @@ -172,7 +172,7 @@ org.slf4j slf4j-api - 1.7.24 + 1.7.30 com.thoughtworks.xstream @@ -268,7 +268,7 @@ org.springframework.data spring-data-redis - 1.8.23.RELEASE + 2.3.3.RELEASE true provided diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml index 3ec16a227..05f541442 100644 --- a/spring-boot-starters/pom.xml +++ b/spring-boot-starters/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B pom wx-java-spring-boot-starters @@ -14,7 +14,7 @@ WxJava 各个模块的 Spring Boot Starter - 2.1.4.RELEASE + 2.3.3.RELEASE diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml index b6e5904ac..72513a80d 100644 --- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.0 + 3.9.1.B 4.0.0 diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml index 7e59fc8c8..623c2147e 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.0 + 3.9.1.B 4.0.0 diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml index 5a98c83a4..3d7cabcbe 100644 --- a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.0 + 3.9.1.B 4.0.0 diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml index 1a93eb54f..e4cffe7d9 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.0 + 3.9.1.B 4.0.0 diff --git a/weixin-graal/pom.xml b/weixin-graal/pom.xml index 016544bc6..d28ffff26 100644 --- a/weixin-graal/pom.xml +++ b/weixin-graal/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B weixin-graal diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 8786e0458..16abcf236 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B weixin-java-common @@ -50,7 +50,7 @@ org.slf4j jcl-over-slf4j - 1.7.24 + 1.7.30 diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java index 882853945..11a0742a7 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import jodd.util.MathUtil; import java.util.List; @@ -151,4 +152,50 @@ public class GsonHelper { public static JsonArray getAsJsonArray(JsonElement element) { return element == null ? null : element.getAsJsonArray(); } + + /** + * 快速构建JsonObject对象,批量添加一堆属性 + * + * @param keyOrValue 包含key或value的数组 + * @return JsonObject对象. + */ + public static JsonObject buildJsonObject(Object... keyOrValue) { + JsonObject result = new JsonObject(); + put(result, keyOrValue); + return result; + } + + /** + * 批量向JsonObject对象中添加属性 + * + * @param jsonObject 原始JsonObject对象 + * @param keyOrValue 包含key或value的数组 + */ + public static void put(JsonObject jsonObject, Object... keyOrValue) { + if (MathUtil.isOdd(keyOrValue.length)) { + throw new RuntimeException("参数个数必须为偶数"); + } + + for (int i = 0; i < keyOrValue.length / 2; i++) { + final Object key = keyOrValue[2 * i]; + final Object value = keyOrValue[2 * i + 1]; + if (value == null) { + jsonObject.add(key.toString(), null); + continue; + } + + if (value instanceof Boolean) { + jsonObject.addProperty(key.toString(), (Boolean) value); + } else if (value instanceof Character) { + jsonObject.addProperty(key.toString(), (Character) value); + } else if (value instanceof Number) { + jsonObject.addProperty(key.toString(), (Number) value); + } else if (value instanceof JsonElement) { + jsonObject.add(key.toString(), (JsonElement) value); + } else { + jsonObject.addProperty(key.toString(), value.toString()); + } + } + + } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java index dfac1c28f..8c5ccc26f 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java @@ -3,8 +3,6 @@ package me.chanjar.weixin.common.util.locks; import lombok.Getter; import lombok.NonNull; import org.jetbrains.annotations.NotNull; -import org.springframework.dao.DataAccessException; -import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.StringRedisTemplate; @@ -76,13 +74,10 @@ public class RedisTemplateSimpleDistributedLock implements Lock { } final byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8); final byte[] valueBytes = value.getBytes(StandardCharsets.UTF_8); - List redisResults = redisTemplate.executePipelined(new RedisCallback() { - @Override - public String doInRedis(RedisConnection connection) throws DataAccessException { - connection.set(keyBytes, valueBytes, Expiration.milliseconds(leaseMilliseconds), RedisStringCommands.SetOption.SET_IF_ABSENT); - connection.get(keyBytes); - return null; - } + List redisResults = redisTemplate.executePipelined((RedisCallback) connection -> { + connection.set(keyBytes, valueBytes, Expiration.milliseconds(leaseMilliseconds), RedisStringCommands.SetOption.SET_IF_ABSENT); + connection.get(keyBytes); + return null; }); Object currentLockSecret = redisResults.size() > 1 ? redisResults.get(1) : redisResults.get(0); return currentLockSecret != null && currentLockSecret.toString().equals(value); diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/GsonHelperTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/GsonHelperTest.java new file mode 100644 index 000000000..396862e70 --- /dev/null +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/json/GsonHelperTest.java @@ -0,0 +1,139 @@ +package me.chanjar.weixin.common.util.json; + +import com.google.gson.JsonObject; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * GsonHelper 的单元测试. + * + * @author Binary Wang + * @date 2020-09-04 + */ +public class GsonHelperTest { + + @Test + public void testIsNull() { + } + + @Test + public void testIsNotNull() { + } + + @Test + public void testGetLong() { + } + + @Test + public void testGetPrimitiveLong() { + } + + @Test + public void testGetInteger() { + } + + @Test + public void testGetPrimitiveInteger() { + } + + @Test + public void testGetDouble() { + } + + @Test + public void testGetPrimitiveDouble() { + } + + @Test + public void testGetFloat() { + } + + @Test + public void testGetPrimitiveFloat() { + } + + @Test + public void testGetBoolean() { + } + + @Test + public void testGetString() { + } + + @Test + public void testGetAsString() { + } + + @Test + public void testGetAsLong() { + } + + @Test + public void testGetAsPrimitiveLong() { + } + + @Test + public void testGetAsInteger() { + } + + @Test + public void testGetAsPrimitiveInt() { + } + + @Test + public void testGetAsBoolean() { + } + + @Test + public void testGetAsPrimitiveBool() { + } + + @Test + public void testGetAsDouble() { + } + + @Test + public void testGetAsPrimitiveDouble() { + } + + @Test + public void testGetAsFloat() { + } + + @Test + public void testGetAsPrimitiveFloat() { + } + + @Test + public void testGetIntArray() { + } + + @Test + public void testGetStringArray() { + } + + @Test + public void testGetLongArray() { + } + + @Test + public void testGetAsJsonArray() { + } + + @Test + public void testBuildSimpleJsonObject() { + try { + GsonHelper.buildJsonObject(1, 2, 3); + } catch (RuntimeException e) { + assertThat(e.getMessage()).isEqualTo("参数个数必须为偶数"); + } + + System.out.println(GsonHelper.buildJsonObject(1, 2)); + System.out.println(GsonHelper.buildJsonObject(1, null)); + System.out.println(GsonHelper.buildJsonObject("int", 1, "float", 2.1f, "double", 2.5)); + System.out.println(GsonHelper.buildJsonObject("boolean", true, "string", "1av")); + System.out.println(GsonHelper.buildJsonObject(1, true, "jsonElement", new JsonObject())); + System.out.println(GsonHelper.buildJsonObject("num", 2, "string", "cde", "char", 'a', "bool", true)); + } +} diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 86d6feab3..4c0c2e9ea 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B weixin-java-cp 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 a6ceb4e55..221f49aa8 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 @@ -86,6 +86,9 @@ public class WxCpUser implements Serializable { @Data @Accessors(chain = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor public static class Attr { /** * 属性类型: 0-文本 1-网页 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatInfo.java index 0c33309bc..83eb5c376 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatInfo.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpUserExternalGroupChatInfo.java @@ -58,6 +58,14 @@ public class WxCpUserExternalGroupChatInfo extends WxCpBaseResp { @SerializedName("join_time") private Long joinTime; + + /** + * 外部联系人在微信开放平台的唯一身份标识(微信unionid) + * 通过此字段企业可将外部联系人与公众号/小程序用户关联起来 + * 仅当群成员类型是微信用户(包括企业成员未添加好友),且企业或第三方服务商绑定了微信开发者ID有此字段 + */ + @SerializedName("unionid") + private String unionId; /** * 入群方式。 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java index e721b33ac..5ec9d1482 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java @@ -276,11 +276,11 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri o.addProperty("main_department", user.getMainDepartment()); } - if (user.getExtAttrs().size() > 0) { + if (!user.getExtAttrs().isEmpty()) { JsonArray attrsJsonArray = new JsonArray(); for (WxCpUser.Attr attr : user.getExtAttrs()) { - JsonObject attrJson = new JsonObject(); - + JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(), + "name", attr.getName()); attrsJsonArray.add(attrJson); if (attr.getType() == null) { @@ -290,19 +290,12 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri } switch (attr.getType()) { - case 0: { - JsonObject text = new JsonObject(); - text.addProperty("value", attr.getTextValue()); - attrJson.add("text", text); + case 0: + attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getTextValue())); break; - } - case 1: { - JsonObject web = new JsonObject(); - web.addProperty("url", attr.getWebUrl()); - web.addProperty("title", attr.getWebTitle()); - attrJson.add("web", web); + case 1: + attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getWebUrl(), "title", attr.getWebTitle())); break; - } default: //ignored } } @@ -322,12 +315,11 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri attrsJson.addProperty(EXTERNAL_CORP_NAME, user.getExternalCorpName()); } - if (user.getExternalAttrs().size() > 0) { + if (!user.getExternalAttrs().isEmpty()) { JsonArray attrsJsonArray = new JsonArray(); for (WxCpUser.ExternalAttribute attr : user.getExternalAttrs()) { - JsonObject attrJson = new JsonObject(); - attrJson.addProperty("type", attr.getType()); - attrJson.addProperty("name", attr.getName()); + JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(), + "name", attr.getName()); attrsJsonArray.add(attrJson); @@ -336,27 +328,16 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri } switch (attr.getType()) { - case 0: { - JsonObject text = new JsonObject(); - text.addProperty("value", attr.getValue()); - attrJson.add("text", text); + case 0: + attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getValue())); break; - } - case 1: { - JsonObject web = new JsonObject(); - web.addProperty("url", attr.getUrl()); - web.addProperty("title", attr.getTitle()); - attrJson.add("web", web); + case 1: + attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getUrl(), "title", attr.getTitle())); break; - } - case 2: { - JsonObject miniprogram = new JsonObject(); - miniprogram.addProperty("appid", attr.getAppid()); - miniprogram.addProperty("pagepath", attr.getPagePath()); - miniprogram.addProperty("title", attr.getTitle()); - attrJson.add("miniprogram", miniprogram); + case 2: + attrJson.add("miniprogram", GsonHelper.buildJsonObject("appid", attr.getAppid(), + "pagepath", attr.getPagePath(), "title", attr.getTitle())); break; - } default://忽略 } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java index d78175c1b..a83e8837d 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java @@ -91,7 +91,7 @@ public class WxCpUserGsonAdapterTest { assertThat(user).isNotNull(); assertThat(user.getOrders()).isNotEmpty(); - assertThat(user.getOrders().length).isEqualTo(2); + assertThat(user.getOrders()).hasSize(2); assertThat(user.getOrders()[0]).isEqualTo(1); assertThat(user.getOrders()[1]).isEqualTo(2); @@ -140,6 +140,12 @@ public class WxCpUserGsonAdapterTest { public void testSerialize() { WxCpUser user = new WxCpUser(); user.setOrders(new Integer[]{1, 2}); + user.addExtAttr(WxCpUser.Attr.builder() + .type(0) + .name("文本名称") + .textValue("文本") + .build()); + user.addExternalAttr(WxCpUser.ExternalAttribute.builder() .type(0) .name("文本名称") @@ -159,7 +165,9 @@ public class WxCpUserGsonAdapterTest { .title("my miniprogram") .build()); - assertThat(user.toJson()).isEqualTo("{\"order\":[1,2],\"external_profile\":{\"external_attr\":" + + assertThat(user.toJson()).isEqualTo("{\"order\":[1,2]," + + "\"extattr\":{\"attrs\":[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}}]}," + + "\"external_profile\":{\"external_attr\":" + "[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}}," + "{\"type\":1,\"name\":\"网页名称\",\"web\":{\"url\":\"http://www.test.com\",\"title\":\"标题\"}}," + "{\"type\":2,\"name\":\"测试app\"," + diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 16d56b930..d708de8a9 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index a89664d46..f1fad08a8 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.0 + 3.9.1.B weixin-java-mp 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 98ef7716f..9b2ca03fe 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 @@ -1,18 +1,5 @@ package me.chanjar.weixin.mp.api; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; @@ -23,6 +10,18 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.LogExceptionHandler; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; /** *
@@ -183,7 +182,7 @@ public class WxMpMessageRouter {
       }
     }
 
-    if (matchRules.size() == 0) {
+    if (matchRules.isEmpty()) {
       return null;
     }
 
@@ -193,11 +192,8 @@ public class WxMpMessageRouter {
       // 返回最后一个非异步的rule的执行结果
       if (rule.isAsync()) {
         futures.add(
-          this.executorService.submit(new Runnable() {
-            @Override
-            public void run() {
-              rule.service(wxMessage, context, mpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler);
-            }
+          this.executorService.submit(() -> {
+            rule.service(wxMessage, context, mpService, WxMpMessageRouter.this.sessionManager, WxMpMessageRouter.this.exceptionHandler);
           })
         );
       } else {
@@ -208,35 +204,34 @@ public class WxMpMessageRouter {
       }
     }
 
-    if (futures.size() > 0) {
-      this.executorService.submit(new Runnable() {
-        @Override
-        public void run() {
-          for (Future future : futures) {
-            try {
-              future.get();
-              WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser());
-              // 异步操作结束,session访问结束
-              sessionEndAccess(wxMessage);
-            } catch (InterruptedException e) {
-              WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
-              Thread.currentThread().interrupt();
-            } catch (ExecutionException e) {
-              WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
-            }
-          }
-        }
-      });
+    if (futures.isEmpty()) {
+      return res;
     }
+
+    this.executorService.submit(() -> {
+      for (Future future : futures) {
+        try {
+          future.get();
+          WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser());
+          // 异步操作结束,session访问结束
+          sessionEndAccess(wxMessage);
+        } catch (InterruptedException e) {
+          WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
+          Thread.currentThread().interrupt();
+        } catch (ExecutionException e) {
+          WxMpMessageRouter.this.log.error("Error happened when wait task finish", e);
+        }
+      }
+    });
     return res;
   }
 
   public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
-    return this.route(wxMessage, new HashMap(2));
+    return this.route(wxMessage, new HashMap<>(2));
   }
 
   public WxMpXmlOutMessage route(String appid, final WxMpXmlMessage wxMessage) {
-    return this.route(appid, wxMessage, new HashMap(2));
+    return this.route(appid, wxMessage, new HashMap<>(2));
   }
 
   private boolean isMsgDuplicated(WxMpXmlMessage wxMessage) {
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index cf743a404..8001b4ab8 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.0
+    3.9.1.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 1a51f3aad..bfc41e354 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.0
+    3.9.1.B
   
   4.0.0
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
index 5e768bef9..00e2ede65 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EntPayServiceImpl.java
@@ -8,7 +8,6 @@ import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.EntPayService;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.util.SignUtils;
-import org.apache.commons.codec.binary.Base64;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.openssl.PEMParser;
@@ -22,6 +21,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.PublicKey;
 import java.security.Security;
+import java.util.Base64;
 
 /**
  * 
@@ -168,7 +168,7 @@ public class EntPayServiceImpl implements EntPayService {
 
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
         byte[] encrypt = cipher.doFinal(srcString.getBytes(StandardCharsets.UTF_8));
-        return Base64.encodeBase64String(encrypt);
+        return Base64.getEncoder().encodeToString(encrypt);
       }
     } catch (Exception e) {
       throw new WxPayException("加密出错", e);
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
index c03713473..fe25bffc6 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
@@ -3,7 +3,6 @@ package com.github.binarywang.wxpay.service.impl;
 import com.github.binarywang.wxpay.bean.WxPayApiData;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.google.gson.JsonObject;
-import jodd.util.Base64;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpEntity;
@@ -29,6 +28,7 @@ import org.apache.http.util.EntityUtils;
 import javax.net.ssl.SSLContext;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
+import java.util.Base64;
 
 /**
  * 
@@ -48,7 +48,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
       try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
         try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
           final byte[] bytes = EntityUtils.toByteArray(response.getEntity());
-          final String responseData = Base64.encodeToString(bytes);
+          final String responseData = Base64.getEncoder().encodeToString(bytes);
           this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据(Base64编码后)】:{}", url, requestStr, responseData);
           wxApiData.set(new WxPayApiData(url, requestStr, responseData, null));
           return bytes;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
index b7ef11695..65f5e869b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
@@ -1,11 +1,5 @@
 package com.github.binarywang.wxpay.service.impl;
 
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import javax.net.ssl.SSLContext;
-
-import org.apache.commons.lang3.StringUtils;
-
 import com.github.binarywang.wxpay.bean.WxPayApiData;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import jodd.http.HttpConnectionProvider;
@@ -15,9 +9,14 @@ import jodd.http.ProxyInfo;
 import jodd.http.ProxyInfo.ProxyType;
 import jodd.http.net.SSLSocketHttpConnectionProvider;
 import jodd.http.net.SocketHttpConnectionProvider;
-import jodd.util.Base64;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.methods.HttpPost;
 
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
 /**
  * 微信支付请求实现类,jodd-http实现.
  * Created by Binary Wang on 2016/7/28.
@@ -30,7 +29,7 @@ public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl {
     try {
       HttpRequest request = this.buildHttpRequest(url, requestStr, useKey);
       byte[] responseBytes = request.send().bodyBytes();
-      final String responseString = Base64.encodeToString(responseBytes);
+      final String responseString = Base64.getEncoder().encodeToString(responseBytes);
       this.log.info("\n【请求地址】:{}\n【请求数据】:{}\n【响应数据(Base64编码后)】:{}", url, requestStr, responseString);
       if (this.getConfig().isIfSaveApiData()) {
         wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));