Browse Source

Merge remote-tracking branch 'wechat/develop' into develop

曾浩 4 years ago
parent
commit
a28a17a76b
69 changed files with 287 additions and 234 deletions
  1. 11 14
      weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java
  2. 5 1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxErrorException.java
  3. 23 0
      weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxRuntimeException.java
  4. 9 12
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java
  5. 1 1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
  6. 3 1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
  7. 7 6
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
  8. 3 3
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
  9. 1 1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
  10. 2 1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java
  11. 6 5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/JedisDistributedLock.java
  12. 12 11
      weixin-java-common/src/test/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLockTest.java
  13. 4 3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
  14. 4 3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
  15. 1 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImpl.java
  16. 7 6
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
  17. 2 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
  18. 2 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
  19. 2 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
  20. 6 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
  21. 4 3
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
  22. 2 1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
  23. 8 6
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
  24. 2 1
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java
  25. 11 14
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java
  26. 5 8
      weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java
  27. 5 4
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
  28. 4 3
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
  29. 6 5
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/AbstractWxMaRedisConfig.java
  30. 3 2
      weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java
  31. 2 1
      weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java
  32. 6 5
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
  33. 2 7
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java
  34. 0 2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
  35. 7 9
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
  36. 2 2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
  37. 5 8
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
  38. 3 2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
  39. 2 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
  40. 3 2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
  41. 3 2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxOAuth2ServiceImpl.java
  42. 2 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
  43. 2 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java
  44. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java
  45. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java
  46. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java
  47. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java
  48. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java
  49. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java
  50. 1 1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java
  51. 11 13
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java
  52. 5 8
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java
  53. 6 9
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
  54. 2 1
      weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java
  55. 3 2
      weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
  56. 2 1
      weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
  57. 2 1
      weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
  58. 1 1
      weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java
  59. 5 0
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ProfitSharingReturnQueryRequest.java
  60. 2 1
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
  61. 6 5
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
  62. 2 1
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
  63. 2 1
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java
  64. 5 3
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java
  65. 5 3
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PrivateKeySigner.java
  66. 8 6
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java
  67. 3 2
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java
  68. 8 5
      weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/SignUtils.java
  69. 2 1
      weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java

+ 11 - 14
weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxMessageInMemoryDuplicateChecker.java

@@ -61,23 +61,20 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
     if (this.backgroundProcessStarted.getAndSet(true)) {
       return;
     }
-    Thread t = new Thread(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          while (true) {
-            Thread.sleep(WxMessageInMemoryDuplicateChecker.this.clearPeriod);
-            Long now = System.currentTimeMillis();
-            for (Map.Entry<String, Long> entry :
-                WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet()) {
-              if (now - entry.getValue() > WxMessageInMemoryDuplicateChecker.this.timeToLive) {
-                WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet().remove(entry);
-              }
+    Thread t = new Thread(() -> {
+      try {
+        while (true) {
+          Thread.sleep(WxMessageInMemoryDuplicateChecker.this.clearPeriod);
+          Long now = System.currentTimeMillis();
+          for (Map.Entry<String, Long> entry :
+              WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet()) {
+            if (now - entry.getValue() > WxMessageInMemoryDuplicateChecker.this.timeToLive) {
+              WxMessageInMemoryDuplicateChecker.this.msgId2Timestamp.entrySet().remove(entry);
             }
           }
-        } catch (InterruptedException e) {
-          Thread.currentThread().interrupt();
         }
+      } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
       }
     });
     t.setDaemon(true);

+ 5 - 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxErrorException.java

@@ -6,7 +6,11 @@ package me.chanjar.weixin.common.error;
 public class WxErrorException extends Exception {
   private static final long serialVersionUID = -6357149550353160810L;
 
-  private WxError error;
+  private final WxError error;
+
+  public WxErrorException(String message) {
+    this(WxError.builder().errorCode(-1).errorMsg(message).build());
+  }
 
   public WxErrorException(WxError error) {
     super(error.toString());

+ 23 - 0
weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxRuntimeException.java

@@ -0,0 +1,23 @@
+package me.chanjar.weixin.common.error;
+
+/**
+ * WxJava专用的runtime exception.
+ *
+ * @author <a href="https://github.com/binarywang">Binary Wang</a>
+ * @date 2020-09-26
+ */
+public class WxRuntimeException extends RuntimeException {
+  private static final long serialVersionUID = 4881698471192264412L;
+
+  public WxRuntimeException(Throwable e) {
+    super(e);
+  }
+
+  public WxRuntimeException(String msg) {
+    super(msg);
+  }
+
+  public WxRuntimeException(String msg, Throwable e) {
+    super(msg, e);
+  }
+}

+ 9 - 12
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSessionManager.java

@@ -183,18 +183,15 @@ public class StandardSessionManager implements WxSessionManager, InternalSession
   public void add(InternalSession session) {
     // 当第一次有session创建的时候,开启session清理线程
     if (!this.backgroundProcessStarted.getAndSet(true)) {
-      Thread t = new Thread(new Runnable() {
-        @Override
-        public void run() {
-          while (true) {
-            try {
-              // 每秒清理一次
-              Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L);
-              backgroundProcess();
-            } catch (InterruptedException e) {
-              Thread.currentThread().interrupt();
-              StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e);
-            }
+      Thread t = new Thread(() -> {
+        while (true) {
+          try {
+            // 每秒清理一次
+            Thread.sleep(StandardSessionManager.this.backgroundProcessorDelay * 1000L);
+            backgroundProcess();
+          } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            StandardSessionManager.this.log.error("SessionManagerImpl.backgroundProcess error", e);
           }
         }
       });

+ 1 - 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java

@@ -58,7 +58,7 @@ public class BeanUtils {
     if (!requiredFields.isEmpty()) {
       String msg = String.format("必填字段【%s】必须提供值!", requiredFields);
       log.debug(msg);
-      throw new WxErrorException(WxError.builder().errorMsg(msg).build());
+      throw new WxErrorException(msg);
     }
   }
 

+ 3 - 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java

@@ -3,6 +3,8 @@ package me.chanjar.weixin.common.util;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.dom4j.*;
 import org.dom4j.io.SAXReader;
 import org.dom4j.tree.DefaultText;
@@ -40,7 +42,7 @@ public class XmlUtils {
         map.put(element.getName(), element2MapOrString(element));
       }
     } catch (DocumentException | SAXException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
 
     return map;

+ 7 - 6
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java

@@ -14,6 +14,7 @@ import javax.xml.parsers.ParserConfigurationException;
 
 import com.google.common.base.CharMatcher;
 import com.google.common.io.BaseEncoding;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.commons.codec.binary.Base64;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -77,7 +78,7 @@ public class WxCryptUtil {
       Element root = document.getDocumentElement();
       return root.getElementsByTagName("Encrypt").item(0).getTextContent();
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -198,7 +199,7 @@ public class WxCryptUtil {
       // 使用BASE64对加密后的字符串进行编码
       return BASE64.encodeToString(encrypted);
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -224,7 +225,7 @@ public class WxCryptUtil {
     // 验证安全签名
     String signature = SHA1.gen(this.token, timeStamp, nonce, cipherText);
     if (!signature.equals(msgSignature)) {
-      throw new RuntimeException("加密消息签名校验失败");
+      throw new WxRuntimeException("加密消息签名校验失败");
     }
 
     // 解密
@@ -252,7 +253,7 @@ public class WxCryptUtil {
       // 解密
       original = cipher.doFinal(encrypted);
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
 
     String xmlContent;
@@ -269,12 +270,12 @@ public class WxCryptUtil {
       xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
       fromAppid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
 
     // appid不相同的情况 暂时忽略这段判断
 //    if (!fromAppid.equals(this.appidOrCorpid)) {
-//      throw new RuntimeException("AppID不正确,请核实!");
+//      throw new WxRuntimeException("AppID不正确,请核实!");
 //    }
 
     return xmlContent;

+ 3 - 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java

@@ -58,7 +58,7 @@ public class HttpResponseProxy {
   private String getFileName(CloseableHttpResponse response) throws WxErrorException {
     Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
     if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
-      throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
+      throw new WxErrorException("无法获取到文件名");
     }
 
     return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
@@ -76,7 +76,7 @@ public class HttpResponseProxy {
 
   private String extractFileNameFromContentString(String content) throws WxErrorException {
     if (content == null || content.length() == 0) {
-      throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
+      throw new WxErrorException("无法获取到文件名");
     }
 
     Matcher m = PATTERN.matcher(content);
@@ -84,7 +84,7 @@ public class HttpResponseProxy {
       return m.group(1);
     }
 
-    throw new WxErrorException(WxError.builder().errorMsg("无法获取到文件名").errorCode(99999).build());
+    throw new WxErrorException("无法获取到文件名");
   }
 
 }

+ 1 - 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java

@@ -44,7 +44,7 @@ public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor
   @NotNull
   public String handleResponse(WxType wxType, String responseContent) throws WxErrorException {
     if (responseContent.isEmpty()) {
-      throw new WxErrorException(WxError.builder().errorCode(9999).errorMsg("无响应内容").build());
+      throw new WxErrorException("无响应内容");
     }
 
     if (responseContent.startsWith("<xml>")) {

+ 2 - 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonHelper.java

@@ -5,6 +5,7 @@ import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import jodd.util.MathUtil;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 
 import java.util.List;
 
@@ -173,7 +174,7 @@ public class GsonHelper {
    */
   public static void put(JsonObject jsonObject, Object... keyOrValue) {
     if (MathUtil.isOdd(keyOrValue.length)) {
-      throw new RuntimeException("参数个数必须为偶数");
+      throw new WxRuntimeException("参数个数必须为偶数");
     }
 
     for (int i = 0; i < keyOrValue.length / 2; i++) {

+ 6 - 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/JedisDistributedLock.java

@@ -5,6 +5,7 @@ import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 
 import com.github.jedis.lock.JedisLock;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import redis.clients.jedis.Jedis;
 import redis.clients.jedis.util.Pool;
 
@@ -26,10 +27,10 @@ public class JedisDistributedLock implements Lock {
   public void lock() {
     try (Jedis jedis = jedisPool.getResource()) {
       if (!lock.acquire(jedis)) {
-        throw new RuntimeException("acquire timeouted");
+        throw new WxRuntimeException("acquire timeouted");
       }
     } catch (InterruptedException e) {
-      throw new RuntimeException("lock failed", e);
+      throw new WxRuntimeException("lock failed", e);
     }
   }
 
@@ -37,7 +38,7 @@ public class JedisDistributedLock implements Lock {
   public void lockInterruptibly() throws InterruptedException {
     try (Jedis jedis = jedisPool.getResource()) {
       if (!lock.acquire(jedis)) {
-        throw new RuntimeException("acquire timeouted");
+        throw new WxRuntimeException("acquire timeouted");
       }
     }
   }
@@ -47,7 +48,7 @@ public class JedisDistributedLock implements Lock {
     try (Jedis jedis = jedisPool.getResource()) {
       return lock.acquire(jedis);
     } catch (InterruptedException e) {
-      throw new RuntimeException("lock failed", e);
+      throw new WxRuntimeException("lock failed", e);
     }
   }
 
@@ -67,7 +68,7 @@ public class JedisDistributedLock implements Lock {
 
   @Override
   public Condition newCondition() {
-    throw new RuntimeException("unsupported method");
+    throw new WxRuntimeException("unsupported method");
   }
 
 }

+ 12 - 11
weixin-java-common/src/test/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLockTest.java

@@ -1,6 +1,6 @@
 package me.chanjar.weixin.common.util.locks;
 
-import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.testng.annotations.BeforeTest;
@@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.testng.Assert.*;
 
+@Slf4j
 @Test(enabled = false)
 public class RedisTemplateSimpleDistributedLockTest {
 
@@ -40,19 +41,19 @@ public class RedisTemplateSimpleDistributedLockTest {
     final CountDownLatch endLatch = new CountDownLatch(threadSize);
 
     for (int i = 0; i < threadSize; i++) {
-      new Thread(new Runnable() {
-        @SneakyThrows
-        @Override
-        public void run() {
+      new Thread(() -> {
+        try {
           startLatch.await();
+        } catch (InterruptedException e) {
+          log.error("unexpected exception", e);
+        }
 
-          redisLock.lock();
-          assertEquals(lockCurrentExecuteCounter.incrementAndGet(), 1, "临界区同时只能有一个线程执行");
-          lockCurrentExecuteCounter.decrementAndGet();
-          redisLock.unlock();
+        redisLock.lock();
+        assertEquals(lockCurrentExecuteCounter.incrementAndGet(), 1, "临界区同时只能有一个线程执行");
+        lockCurrentExecuteCounter.decrementAndGet();
+        redisLock.unlock();
 
-          endLatch.countDown();
-        }
+        endLatch.countDown();
       }).start();
       startLatch.countDown();
     }

+ 4 - 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java

@@ -9,6 +9,7 @@ import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.session.StandardSessionManager;
 import me.chanjar.weixin.common.session.WxSession;
 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -227,7 +228,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
         if (retryTimes + 1 > this.maxRetryTimes) {
           log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
-          throw new RuntimeException("微信服务端异常,超出重试次数");
+          throw new WxRuntimeException("微信服务端异常,超出重试次数");
         }
 
         WxError error = e.getError();
@@ -249,7 +250,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
     } while (retryTimes++ < this.maxRetryTimes);
 
     log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-    throw new RuntimeException("微信服务端异常,超出重试次数");
+    throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
   protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
@@ -285,7 +286,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
       return null;
     } catch (IOException e) {
       log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 4 - 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java

@@ -6,6 +6,7 @@ import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.cp.api.WxCpExternalContactService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
@@ -30,7 +31,7 @@ public class WxCpExternalContactServiceImpl implements WxCpExternalContactServic
   public WxCpContactWayResult addContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
 
     if (info.getContactWay().getUsers() != null && info.getContactWay().getUsers().size() > 100) {
-      throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
+      throw new WxRuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
     }
 
     final String url = this.mainService.getWxCpConfigStorage().getApiUrl(ADD_CONTACT_WAY);
@@ -52,10 +53,10 @@ public class WxCpExternalContactServiceImpl implements WxCpExternalContactServic
   @Override
   public WxCpBaseResp updateContactWay(@NonNull WxCpContactWayInfo info) throws WxErrorException {
     if (StringUtils.isBlank(info.getContactWay().getConfigId())) {
-      throw new RuntimeException("更新「联系我」方式需要指定configId");
+      throw new WxRuntimeException("更新「联系我」方式需要指定configId");
     }
     if (info.getContactWay().getUsers() != null && info.getContactWay().getUsers().size() > 100) {
-      throw new RuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
+      throw new WxRuntimeException("「联系我」使用人数默认限制不超过100人(包括部门展开后的人数)");
     }
 
     final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_CONTACT_WAY);

+ 1 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImpl.java

@@ -31,7 +31,7 @@ public class WxCpGroupRobotServiceImpl implements WxCpGroupRobotService {
     WxCpConfigStorage wxCpConfigStorage = this.cpService.getWxCpConfigStorage();
     final String webhookKey = wxCpConfigStorage.getWebhookKey();
     if (StringUtils.isEmpty(webhookKey)) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("请先设置WebhookKey").build());
+      throw new WxErrorException("请先设置WebhookKey");
     }
     return wxCpConfigStorage.getApiUrl(WxCpApiPathConsts.WEBHOOK_SEND) + webhookKey;
   }

+ 7 - 6
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java

@@ -7,6 +7,7 @@ import com.google.gson.reflect.TypeToken;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.api.WxCpOaService;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -42,18 +43,18 @@ public class WxCpOaServiceImpl implements WxCpOaService {
   public List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime,
                                               List<String> userIdList) throws WxErrorException {
     if (startTime == null || endTime == null) {
-      throw new RuntimeException("starttime and endtime can't be null");
+      throw new WxRuntimeException("starttime and endtime can't be null");
     }
 
     if (userIdList == null || userIdList.size() > USER_IDS_LIMIT) {
-      throw new RuntimeException("用户列表不能为空,不超过 " + USER_IDS_LIMIT + " 个,若用户超过 " + USER_IDS_LIMIT + " 个,请分批获取");
+      throw new WxRuntimeException("用户列表不能为空,不超过 " + USER_IDS_LIMIT + " 个,若用户超过 " + USER_IDS_LIMIT + " 个,请分批获取");
     }
 
     long endTimestamp = endTime.getTime() / 1000L;
     long startTimestamp = startTime.getTime() / 1000L;
 
     if (endTimestamp - startTimestamp < 0 || endTimestamp - startTimestamp >= MONTH_SECONDS) {
-      throw new RuntimeException("获取记录时间跨度不超过一个月");
+      throw new WxRuntimeException("获取记录时间跨度不超过一个月");
     }
 
     JsonObject jsonObject = new JsonObject();
@@ -83,11 +84,11 @@ public class WxCpOaServiceImpl implements WxCpOaService {
   @Override
   public List<WxCpCheckinOption> getCheckinOption(Date datetime, List<String> userIdList) throws WxErrorException {
     if (datetime == null) {
-      throw new RuntimeException("datetime can't be null");
+      throw new WxRuntimeException("datetime can't be null");
     }
 
     if (userIdList == null || userIdList.size() > USER_IDS_LIMIT) {
-      throw new RuntimeException("用户列表不能为空,不超过 " + USER_IDS_LIMIT + " 个,若用户超过 " + USER_IDS_LIMIT + " 个,请分批获取");
+      throw new WxRuntimeException("用户列表不能为空,不超过 " + USER_IDS_LIMIT + " 个,若用户超过 " + USER_IDS_LIMIT + " 个,请分批获取");
     }
 
     JsonArray jsonArray = new JsonArray();
@@ -186,7 +187,7 @@ public class WxCpOaServiceImpl implements WxCpOaService {
       long starttimestamp = startTime.getTime() / 1000L;
 
       if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= MONTH_SECONDS) {
-        throw new RuntimeException("受限于网络传输,起止时间的最大跨度为30天,如超过30天,则以结束时间为基准向前取30天进行查询");
+        throw new WxRuntimeException("受限于网络传输,起止时间的最大跨度为30天,如超过30天,则以结束时间为基准向前取30天进行查询");
       }
 
       jsonObject.addProperty("start_time", starttimestamp);

+ 2 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java

@@ -5,6 +5,7 @@ import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
@@ -72,7 +73,7 @@ public class WxCpServiceApacheHttpClientImpl extends BaseWxCpServiceImpl<Closeab
         WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
         this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
       } catch (IOException e) {
-        throw new RuntimeException(e);
+        throw new WxRuntimeException(e);
       }
     }
     return this.configStorage.getAccessToken();

+ 2 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java

@@ -5,6 +5,7 @@ import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.apache.http.client.config.RequestConfig;
@@ -68,7 +69,7 @@ public class WxCpServiceImpl extends WxCpServiceApacheHttpClientImpl {
         WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
         getWxCpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
       } catch (IOException e) {
-        throw new RuntimeException(e);
+        throw new WxRuntimeException(e);
       }
     } finally {
       lock.unlock();

+ 2 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java

@@ -6,6 +6,7 @@ import com.thoughtworks.xstream.annotations.XStreamImplicit;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.XmlUtils;
 import me.chanjar.weixin.common.util.xml.IntegerArrayConverter;
 import me.chanjar.weixin.common.util.xml.LongArrayConverter;
@@ -450,7 +451,7 @@ public class WxCpXmlMessage implements Serializable {
     try {
       return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxCpConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 6 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java

@@ -99,11 +99,16 @@ public class WxCpConsts {
     public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact";
 
     /**
-     * 企业微信审批事件推送
+     * 企业微信审批事件推送(自建应用审批)
      */
     public static final String OPEN_APPROVAL_CHANGE = "open_approval_change";
 
     /**
+     * 企业微信审批事件推送(系统审批)
+     */
+    public static final String SYS_APPROVAL_CHANGE = "sys_approval_change";
+
+    /**
      * 修改日历事件
      */
     public static final String MODIFY_CALENDAR = "modify_calendar";

+ 4 - 3
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java

@@ -9,6 +9,7 @@ import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxCpErrorMsgEnum;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.session.StandardSessionManager;
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.common.util.DataUtils;
@@ -183,7 +184,7 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ
         if (retryTimes + 1 > this.maxRetryTimes) {
           log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
-          throw new RuntimeException("微信服务端异常,超出重试次数");
+          throw new WxRuntimeException("微信服务端异常,超出重试次数");
         }
 
         WxError error = e.getError();
@@ -205,7 +206,7 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ
     } while (retryTimes++ < this.maxRetryTimes);
 
     log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-    throw new RuntimeException("微信服务端异常,超出重试次数");
+    throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
   protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
@@ -244,7 +245,7 @@ public abstract class BaseWxCpTpServiceImpl<H, P> implements WxCpTpService, Requ
       return null;
     } catch (IOException e) {
       log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 2 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java

@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
@@ -81,7 +82,7 @@ public class WxCpTpServiceApacheHttpClientImpl extends BaseWxCpTpServiceImpl<Clo
         Integer expiresIn = jsonObject.get("expires_in").getAsInt();
         this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
       } catch (IOException e) {
-        throw new RuntimeException(e);
+        throw new WxRuntimeException(e);
       }
     }
     return this.configStorage.getSuiteAccessToken();

+ 8 - 6
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java

@@ -16,6 +16,8 @@ import me.chanjar.weixin.cp.bean.WxCpUser;
 
 import java.lang.reflect.Type;
 
+import static me.chanjar.weixin.cp.bean.WxCpUser.*;
+
 /**
  * cp user gson adapter.
  *
@@ -104,7 +106,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
     JsonArray attrJsonElements = o.get(EXTRA_ATTR).getAsJsonObject().get("attrs").getAsJsonArray();
     for (JsonElement attrJsonElement : attrJsonElements) {
       final Integer type = GsonHelper.getInteger(attrJsonElement.getAsJsonObject(), "type");
-      final WxCpUser.Attr attr = new WxCpUser.Attr().setType(type)
+      final Attr attr = new Attr().setType(type)
         .setName(GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"));
       user.getExtAttrs().add(attr);
 
@@ -142,7 +144,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
       switch (type) {
         case 0: {
           user.getExternalAttrs()
-            .add(WxCpUser.ExternalAttribute.builder()
+            .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
               .value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value"))
@@ -153,7 +155,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
         case 1: {
           final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject();
           user.getExternalAttrs()
-            .add(WxCpUser.ExternalAttribute.builder()
+            .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
               .url(GsonHelper.getString(web, "url"))
@@ -165,7 +167,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
         case 2: {
           final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject();
           user.getExternalAttrs()
-            .add(WxCpUser.ExternalAttribute.builder()
+            .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
               .appid(GsonHelper.getString(miniprogram, "appid"))
@@ -278,7 +280,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
 
     if (!user.getExtAttrs().isEmpty()) {
       JsonArray attrsJsonArray = new JsonArray();
-      for (WxCpUser.Attr attr : user.getExtAttrs()) {
+      for (Attr attr : user.getExtAttrs()) {
         JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
           "name", attr.getName());
         attrsJsonArray.add(attrJson);
@@ -317,7 +319,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
 
     if (!user.getExternalAttrs().isEmpty()) {
       JsonArray attrsJsonArray = new JsonArray();
-      for (WxCpUser.ExternalAttribute attr : user.getExternalAttrs()) {
+      for (ExternalAttribute attr : user.getExternalAttrs()) {
         JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
           "name", attr.getName());
 

+ 2 - 1
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/ApiTestModule.java

@@ -7,6 +7,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
@@ -30,7 +31,7 @@ public class ApiTestModule implements Module {
   public void configure(Binder binder) {
     try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) {
       if (inputStream == null) {
-        throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
+        throw new WxRuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
       }
 
       config = fromXml(WxXmlCpInMemoryConfigStorage.class, inputStream);

+ 11 - 14
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBusyRetryTest.java

@@ -1,8 +1,8 @@
 package me.chanjar.weixin.cp.api;
 
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
 import org.testng.annotations.DataProvider;
@@ -25,7 +25,7 @@ public class WxCpBusyRetryTest {
         RequestExecutor<T, E> executor, String uri, E data)
         throws WxErrorException {
         log.info("Executed");
-        throw new WxErrorException(WxError.builder().errorCode(-1).build());
+        throw new WxErrorException("something");
       }
     };
 
@@ -45,18 +45,15 @@ public class WxCpBusyRetryTest {
   public void testRetryInThreadPool(final WxCpService service) throws InterruptedException, ExecutionException {
     // 当线程池中的线程复用的时候,还是能保证相同的重试次数
     ExecutorService executorService = Executors.newFixedThreadPool(1);
-    Runnable runnable = new Runnable() {
-      @Override
-      public void run() {
-        try {
-          System.out.println("=====================");
-          System.out.println(Thread.currentThread().getName() + ": testRetry");
-          service.execute(null, null, null);
-        } catch (WxErrorException e) {
-          throw new RuntimeException(e);
-        } catch (RuntimeException e) {
-          // OK
-        }
+    Runnable runnable = () -> {
+      try {
+        System.out.println("=====================");
+        System.out.println(Thread.currentThread().getName() + ": testRetry");
+        service.execute(null, null, null);
+      } catch (WxErrorException e) {
+        throw new WxRuntimeException(e);
+      } catch (RuntimeException e) {
+        // OK
       }
     };
     Future<?> submit1 = executorService.submit(runnable);

+ 5 - 8
weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java

@@ -84,14 +84,11 @@ public class WxCpMessageRouterTest {
     }).end();
 
     final WxCpXmlMessage m = new WxCpXmlMessage();
-    Runnable r = new Runnable() {
-      @Override
-      public void run() {
-        router.route(m);
-        try {
-          Thread.sleep(1000);
-        } catch (InterruptedException e) {
-        }
+    Runnable r = () -> {
+      router.route(m);
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException e) {
       }
     };
     for (int i = 0; i < 10; i++) {

+ 5 - 4
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java

@@ -17,6 +17,7 @@ import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.DataUtils;
 import me.chanjar.weixin.common.util.crypto.SHA1;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
@@ -155,7 +156,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
       String response = doGetAccessTokenRequest();
       return extractAccessToken(response);
     } catch (IOException | InterruptedException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } finally {
       if (locked) {
         lock.unlock();
@@ -222,7 +223,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
     } while (retryTimes++ < this.maxRetryTimes);
 
     log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-    throw new RuntimeException("微信服务端异常,超出重试次数");
+    throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
   private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
@@ -267,7 +268,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
       return null;
     } catch (IOException e) {
       log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -354,7 +355,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
       return this;
     }
 
-    throw new RuntimeException(String.format("无法找到对应【%s】的小程序配置信息,请核实!", miniappId));
+    throw new WxRuntimeException(String.format("无法找到对应【%s】的小程序配置信息,请核实!", miniappId));
   }
 
   @Override

+ 4 - 3
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java

@@ -8,6 +8,7 @@ import com.google.gson.annotations.SerializedName;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import org.apache.commons.io.IOUtils;
 
@@ -174,7 +175,7 @@ public class WxMaMessage implements Serializable {
       return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMaConfig,
         timestamp, nonce, msgSignature);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -188,7 +189,7 @@ public class WxMaMessage implements Serializable {
       String plainText = new WxMaCryptUtils(config).decrypt(encryptedMessage.getEncrypt());
       return fromJson(plainText);
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -196,7 +197,7 @@ public class WxMaMessage implements Serializable {
     try {
       return fromEncryptedJson(IOUtils.toString(inputStream, StandardCharsets.UTF_8), config);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 6 - 5
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/AbstractWxMaRedisConfig.java

@@ -1,6 +1,7 @@
 package cn.binarywang.wx.miniapp.config.impl;
 
 import com.github.jedis.lock.JedisLock;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import redis.clients.jedis.Jedis;
 
 import java.io.File;
@@ -232,10 +233,10 @@ public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl {
     public void lock() {
       try (Jedis jedis = getConfiguredJedis()) {
         if (!lock.acquire(jedis)) {
-          throw new RuntimeException("acquire timeouted");
+          throw new WxRuntimeException("acquire timeouted");
         }
       } catch (InterruptedException e) {
-        throw new RuntimeException("lock failed", e);
+        throw new WxRuntimeException("lock failed", e);
       }
     }
 
@@ -243,7 +244,7 @@ public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl {
     public void lockInterruptibly() throws InterruptedException {
       try (Jedis jedis = getConfiguredJedis()) {
         if (!lock.acquire(jedis)) {
-          throw new RuntimeException("acquire timeouted");
+          throw new WxRuntimeException("acquire timeouted");
         }
       }
     }
@@ -253,7 +254,7 @@ public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl {
       try (Jedis jedis = getConfiguredJedis()) {
         return lock.acquire(jedis);
       } catch (InterruptedException e) {
-        throw new RuntimeException("lock failed", e);
+        throw new WxRuntimeException("lock failed", e);
       }
     }
 
@@ -273,7 +274,7 @@ public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl {
 
     @Override
     public Condition newCondition() {
-      throw new RuntimeException("unsupported method");
+      throw new WxRuntimeException("unsupported method");
     }
 
   }

+ 3 - 2
weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java

@@ -12,6 +12,7 @@ import javax.crypto.spec.SecretKeySpec;
 
 import com.google.common.base.CharMatcher;
 import com.google.common.io.BaseEncoding;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.commons.codec.binary.Base64;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
@@ -47,7 +48,7 @@ public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCrypt
 
       return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), UTF_8);
     } catch (Exception e) {
-      throw new RuntimeException("AES解密失败!", e);
+      throw new WxRuntimeException("AES解密失败!", e);
     }
   }
 
@@ -78,7 +79,7 @@ public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCrypt
       cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(Base64.decodeBase64(ivStr.getBytes(UTF_8))));
       return new String(cipher.doFinal(Base64.decodeBase64(encryptedData.getBytes(UTF_8))), UTF_8);
     } catch (Exception e) {
-      throw new RuntimeException("AES解密失败!", e);
+      throw new WxRuntimeException("AES解密失败!", e);
     }
   }
 

+ 2 - 1
weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java

@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.concurrent.locks.ReentrantLock;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -23,7 +24,7 @@ public class ApiTestModule implements Module {
   public void configure(Binder binder) {
     try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) {
       if (inputStream == null) {
-        throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
+        throw new WxRuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
       }
       TestConfig config = TestConfig.fromXml(inputStream);
       config.setAccessTokenLock(new ReentrantLock());

+ 6 - 5
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java

@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.api;
 
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
 import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
 import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
@@ -50,10 +51,10 @@ import java.util.concurrent.*;
  *
  * @author Daniel Qian
  */
+@Slf4j
 @AllArgsConstructor
 public class WxMpMessageRouter {
   private static final int DEFAULT_THREAD_POOL_SIZE = 100;
-  protected final Logger log = LoggerFactory.getLogger(WxMpMessageRouter.class);
   private final List<WxMpMessageRouterRule> rules = new ArrayList<>();
 
   private final WxMpService wxMpService;
@@ -201,7 +202,7 @@ public class WxMpMessageRouter {
       } else {
         res = rule.service(wxMessage, context, mpService, this.sessionManager, this.exceptionHandler);
         // 在同步操作结束,session访问结束
-        this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
+        log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
         sessionEndAccess(wxMessage);
       }
     }
@@ -214,14 +215,14 @@ public class WxMpMessageRouter {
       for (Future<?> future : futures) {
         try {
           future.get();
-          WxMpMessageRouter.this.log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUser());
+          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);
+          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);
+          log.error("Error happened when wait task finish", e);
         }
       }
     });

+ 2 - 7
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java

@@ -7,10 +7,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
 import org.apache.commons.lang3.StringUtils;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.regex.Pattern;
 
 public class WxMpMessageRouterRule {
@@ -130,9 +127,7 @@ public class WxMpMessageRouterRule {
   public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) {
     this.interceptors.add(interceptor);
     if (otherInterceptors != null && otherInterceptors.length > 0) {
-      for (WxMpMessageInterceptor i : otherInterceptors) {
-        this.interceptors.add(i);
-      }
+      Collections.addAll(this.interceptors, otherInterceptors);
     }
     return this;
   }

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

@@ -12,9 +12,7 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
-import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
-import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 

+ 7 - 9
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java

@@ -17,6 +17,7 @@ import me.chanjar.weixin.common.enums.TicketType;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.session.StandardSessionManager;
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.common.util.DataUtils;
@@ -28,9 +29,7 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.mp.api.*;
 import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
-import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
-import me.chanjar.weixin.mp.bean.result.WxMpUser;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import me.chanjar.weixin.mp.enums.WxMpApiUrl;
 import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
@@ -203,9 +202,8 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
   @Override
   public String shortUrl(String longUrl) throws WxErrorException {
     if (longUrl.contains("&access_token=")) {
-      throw new WxErrorException(WxError.builder().errorCode(-1)
-        .errorMsg("要转换的网址中存在非法字符{&access_token=},会导致微信接口报错,属于微信bug,请调整地址,否则不建议使用此方法!")
-        .build());
+      throw new WxErrorException("要转换的网址中存在非法字符{&access_token=}," +
+        "会导致微信接口报错,属于微信bug,请调整地址,否则不建议使用此方法!");
     }
 
     JsonObject o = new JsonObject();
@@ -303,7 +301,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
         if (retryTimes + 1 > this.maxRetryTimes) {
           log.warn("重试达到最大次数【{}】", maxRetryTimes);
           //最后一次重试失败后,直接抛出异常,不再等待
-          throw new RuntimeException("微信服务端异常,超出重试次数");
+          throw new WxRuntimeException("微信服务端异常,超出重试次数");
         }
 
         WxError error = e.getError();
@@ -314,7 +312,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
             log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
             Thread.sleep(sleepMillis);
           } catch (InterruptedException e1) {
-            throw new RuntimeException(e1);
+            throw new WxRuntimeException(e1);
           }
         } else {
           throw e;
@@ -323,7 +321,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
     } while (retryTimes++ < this.maxRetryTimes);
 
     log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
-    throw new RuntimeException("微信服务端异常,超出重试次数");
+    throw new WxRuntimeException("微信服务端异常,超出重试次数");
   }
 
   protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
@@ -448,7 +446,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
       return this;
     }
 
-    throw new RuntimeException(String.format("无法找到对应【%s】的公众号配置信息,请核实!", mpId));
+    throw new WxRuntimeException(String.format("无法找到对应【%s】的公众号配置信息,请核实!", mpId));
   }
 
   @Override

+ 2 - 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java

@@ -115,11 +115,11 @@ public class WxMpKefuServiceImpl implements WxMpKefuService {
   @Override
   public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException {
     if (number > 10000) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("非法参数请求,每次最多查询10000条记录!").build());
+      throw new WxErrorException("非法参数请求,每次最多查询10000条记录!");
     }
 
     if (startTime.after(endTime)) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("起始时间不能晚于结束时间!").build());
+      throw new WxErrorException("起始时间不能晚于结束时间!");
     }
 
     JsonObject param = new JsonObject();

+ 5 - 8
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java

@@ -29,7 +29,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
   @Override
   public WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException {
     if (sceneId == 0) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为0!").build());
+      throw new WxErrorException("临时二维码场景值不能为0!");
     }
 
     return this.createQrCode("QR_SCENE", null, sceneId, expireSeconds);
@@ -38,7 +38,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
   @Override
   public WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException {
     if (StringUtils.isBlank(sceneStr)) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("临时二维码场景值不能为空!").build());
+      throw new WxErrorException("临时二维码场景值不能为空!");
     }
 
     return this.createQrCode("QR_STR_SCENE", sceneStr, null, expireSeconds);
@@ -48,8 +48,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
     throws WxErrorException {
     //expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
     if (expireSeconds != null && expireSeconds > 2592000) {
-      throw new WxErrorException(WxError.builder().errorCode(-1)
-        .errorMsg("临时二维码有效时间最大不能超过2592000(即30天)!").build());
+      throw new WxErrorException("临时二维码有效时间最大不能超过2592000(即30天)!");
     }
 
     if (expireSeconds == null) {
@@ -84,9 +83,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
   @Override
   public WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException {
     if (sceneId < 1 || sceneId > 100000) {
-      throw new WxErrorException(WxError.builder().errorCode(-1)
-        .errorMsg("永久二维码的场景值目前只支持1--100000!")
-        .build());
+      throw new WxErrorException("永久二维码的场景值目前只支持1--100000!");
     }
 
     return this.getQrCodeTicket("QR_LIMIT_SCENE", null, sceneId, null);
@@ -113,7 +110,7 @@ public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
 
       return resultUrl;
     } catch (UnsupportedEncodingException e) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg(e.getMessage()).build());
+      throw new WxErrorException(e.getMessage());
     }
   }
 

+ 3 - 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java

@@ -1,6 +1,7 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
@@ -92,10 +93,10 @@ public class WxMpServiceHttpClientImpl extends BaseWxMpServiceImpl<CloseableHttp
           httpGet.releaseConnection();
         }
       } catch (IOException e) {
-        throw new RuntimeException(e);
+        throw new WxRuntimeException(e);
       }
     } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } finally {
       if (locked) {
         lock.unlock();

+ 2 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java

@@ -5,6 +5,7 @@ import jodd.http.HttpRequest;
 import jodd.http.ProxyInfo;
 import jodd.http.net.SocketHttpConnectionProvider;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 
@@ -77,7 +78,7 @@ public class WxMpServiceJoddHttpImpl extends BaseWxMpServiceImpl<HttpConnectionP
 
       return this.extractAccessToken(request.send().bodyText());
     } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } finally {
       if (locked) {
         lock.unlock();

+ 3 - 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java

@@ -1,6 +1,7 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
@@ -59,9 +60,9 @@ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl<OkHttpClient, OkH
       Response response = getRequestHttpClient().newCall(request).execute();
       return this.extractAccessToken(Objects.requireNonNull(response.body()).string());
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } finally {
       if (locked) {
         lock.unlock();

+ 3 - 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxOAuth2ServiceImpl.java

@@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
 import me.chanjar.weixin.common.util.http.URIUtil;
@@ -75,7 +76,7 @@ public class WxOAuth2ServiceImpl implements WxOAuth2Service {
       String responseText = executor.execute(url, null, WxType.MP);
       return WxMpUser.fromJson(responseText);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 
@@ -86,7 +87,7 @@ public class WxOAuth2ServiceImpl implements WxOAuth2Service {
     try {
       SimpleGetRequestExecutor.create(this.wxMpService.getRequestHttp()).execute(url, null, WxType.MP);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } catch (WxErrorException e) {
       return false;
     }

+ 2 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java

@@ -5,6 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.XmlUtils;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
@@ -716,7 +717,7 @@ public class WxMpXmlMessage implements Serializable {
     try {
       return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8), wxMpConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 2 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpKefuMessageGsonAdapter.java

@@ -2,6 +2,7 @@ package me.chanjar.weixin.mp.util.json;
 
 import com.google.gson.*;
 import me.chanjar.weixin.common.api.WxConsts.KefuMsgType;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
 import org.apache.commons.lang3.StringUtils;
 
@@ -96,7 +97,7 @@ public class WxMpKefuMessageGsonAdapter implements JsonSerializer<WxMpKefuMessag
         break;
       }
       default: {
-        throw new RuntimeException("非法消息类型,暂不支持");
+        throw new WxRuntimeException("非法消息类型,暂不支持");
       }
     }
 

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java

@@ -41,7 +41,7 @@ public class MaterialUploadApacheHttpRequestExecutor extends MaterialUploadReque
     }
 
     if (material == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("非法请求,material参数为空").build());
+      throw new WxErrorException("非法请求,material参数为空");
     }
 
     File file = material.getFile();

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java

@@ -37,7 +37,7 @@ public class MaterialUploadJoddHttpRequestExecutor extends MaterialUploadRequest
     request.withConnectionProvider(requestHttp.getRequestHttpClient());
 
     if (material == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("非法请求,material参数为空").build());
+      throw new WxErrorException("非法请求,material参数为空");
     }
 
     File file = material.getFile();

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java

@@ -31,7 +31,7 @@ public class MaterialUploadOkhttpRequestExecutor extends MaterialUploadRequestEx
   public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxType wxType) throws WxErrorException, IOException {
     logger.debug("MaterialUploadOkhttpRequestExecutor is running");
     if (material == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("非法请求,material参数为空").build());
+      throw new WxErrorException("非法请求,material参数为空");
     }
     File file = material.getFile();
     if (file == null || !file.exists()) {

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java

@@ -32,7 +32,7 @@ public class MediaImgUploadApacheHttpRequestExecutor extends MediaImgUploadReque
   @Override
   public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) throws WxErrorException, IOException {
     if (data == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("文件对象为空").build());
+      throw new WxErrorException("文件对象为空");
     }
 
     HttpPost httpPost = new HttpPost(uri);

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java

@@ -29,7 +29,7 @@ public class MediaImgUploadHttpRequestExecutor extends MediaImgUploadRequestExec
   @Override
   public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) throws WxErrorException, IOException {
     if (data == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("文件对象为空").build());
+      throw new WxErrorException("文件对象为空");
     }
 
     HttpRequest request = HttpRequest.post(uri);

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java

@@ -37,7 +37,7 @@ public abstract class QrCodeRequestExecutor<H, P> implements RequestExecutor<Fil
       case OK_HTTP:
         return new QrCodeOkhttpRequestExecutor(requestHttp);
       default:
-        throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("不支持的http框架").build());
+        throw new WxErrorException("不支持的http框架");
     }
   }
 

+ 1 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java

@@ -33,7 +33,7 @@ public class VoiceUploadApacheHttpRequestExecutor extends VoiceUploadRequestExec
   @Override
   public Boolean execute(String uri, File data, WxType wxType) throws WxErrorException, IOException {
     if (data == null) {
-      throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("文件对象为空").build());
+      throw new WxErrorException("文件对象为空");
     }
 
     HttpPost httpPost = new HttpPost(uri);

+ 11 - 13
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBusyRetryTest.java

@@ -3,6 +3,7 @@ package me.chanjar.weixin.mp.api;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
 import org.testng.annotations.*;
@@ -25,7 +26,7 @@ public class WxMpBusyRetryTest {
         RequestExecutor<T, E> executor, String uri, E data)
         throws WxErrorException {
         log.info("Executed");
-        throw new WxErrorException(WxError.builder().errorCode(-1).build());
+        throw new WxErrorException("something");
       }
     };
 
@@ -43,18 +44,15 @@ public class WxMpBusyRetryTest {
   public void testRetryInThreadPool(final WxMpService service) throws InterruptedException, ExecutionException {
     // 当线程池中的线程复用的时候,还是能保证相同的重试次数
     ExecutorService executorService = Executors.newFixedThreadPool(1);
-    Runnable runnable = new Runnable() {
-      @Override
-      public void run() {
-        try {
-          System.out.println("=====================");
-          System.out.println(Thread.currentThread().getName() + ": testRetry");
-          service.execute(null, (String)null, null);
-        } catch (WxErrorException e) {
-          throw new RuntimeException(e);
-        } catch (RuntimeException e) {
-          // OK
-        }
+    Runnable runnable = () -> {
+      try {
+        System.out.println("=====================");
+        System.out.println(Thread.currentThread().getName() + ": testRetry");
+        service.execute(null, (String)null, null);
+      } catch (WxErrorException e) {
+        throw new WxRuntimeException(e);
+      } catch (RuntimeException e) {
+        // OK
       }
     };
     Future<?> submit1 = executorService.submit(runnable);

+ 5 - 8
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java

@@ -97,14 +97,11 @@ public class WxMpMessageRouterTest {
     }).end();
 
     final WxMpXmlMessage m = new WxMpXmlMessage();
-    Runnable r = new Runnable() {
-      @Override
-      public void run() {
-        router.route(m);
-        try {
-          Thread.sleep(1000);
-        } catch (InterruptedException e) {
-        }
+    Runnable r = () -> {
+      router.route(m);
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException e) {
       }
     };
     for (int i = 0; i < 10; i++) {

+ 6 - 9
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java

@@ -82,15 +82,12 @@ public class BaseWxMpServiceImplTest {
     // 测试多线程刷新accessToken时是否重复刷新
     wxService.getWxMpConfigStorage().expireAccessToken();
     final Set<String> set = Sets.newConcurrentHashSet();
-    Runnable r = new Runnable() {
-      @Override
-      public void run() {
-        try {
-          String accessToken = wxService.getAccessToken();
-          set.add(accessToken);
-        } catch (WxErrorException e) {
-          e.printStackTrace();
-        }
+    Runnable r = () -> {
+      try {
+        String accessToken = wxService.getAccessToken();
+        set.add(accessToken);
+      } catch (WxErrorException e) {
+        e.printStackTrace();
       }
     };
 

+ 2 - 1
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/test/ApiTestModule.java

@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.concurrent.locks.ReentrantLock;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,7 +24,7 @@ public class ApiTestModule implements Module {
   public void configure(Binder binder) {
     try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) {
       if (inputStream == null) {
-        throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
+        throw new WxRuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
       }
 
       TestConfigStorage config = this.fromXml(TestConfigStorage.class, inputStream);

+ 3 - 2
weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java

@@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.crypto.SHA1;
 import me.chanjar.weixin.common.util.http.URIUtil;
 import me.chanjar.weixin.common.util.json.GsonParser;
@@ -384,7 +385,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
       config.updateAuthorizerRefreshToken(appId,wxOpenAuthorizerAccessToken.getAuthorizerRefreshToken());
       return config.getAuthorizerAccessToken(appId);
     } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     } finally {
       if (locked) {
         lock.unlock();
@@ -488,7 +489,7 @@ public class WxOpenComponentServiceImpl implements WxOpenComponentService {
         result = maService.post(requestUrl, param.toString());
         return result;
       default:
-        throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("appIdType类型异常").build());
+        throw new WxErrorException("appIdType类型异常");
     }
   }
 

+ 2 - 1
weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java

@@ -3,6 +3,7 @@ package me.chanjar.weixin.open.api.impl;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.open.api.WxOpenComponentService;
@@ -56,7 +57,7 @@ public abstract class WxOpenServiceAbstractImpl<H, P> implements WxOpenService,
       return null;
     } catch (IOException e) {
       this.log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uri, data, e.getMessage());
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 }

+ 2 - 1
weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java

@@ -4,6 +4,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import com.thoughtworks.xstream.annotations.XStreamConverter;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
@@ -149,7 +150,7 @@ public class WxOpenXmlMessage implements Serializable {
       return fromEncryptedXml(IOUtils.toString(is, StandardCharsets.UTF_8),
         wxOpenConfigStorage, timestamp, nonce, msgSignature);
     } catch (IOException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 }

+ 1 - 1
weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java

@@ -38,7 +38,7 @@ public abstract class MaQrCodeRequestExecutor<H, P> implements RequestExecutor<F
       case OK_HTTP:
         return new MaQrCodeOkhttpRequestExecutor(requestHttp);
       default:
-        throw new WxErrorException(WxError.builder().errorCode(-1).errorMsg("不支持的http框架").build());
+        throw new WxErrorException("不支持的http框架");
     }
   }
 

+ 5 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ProfitSharingReturnQueryRequest.java

@@ -73,6 +73,11 @@ public class ProfitSharingReturnQueryRequest extends BaseWxPayRequest {
   }
 
   @Override
+  protected boolean ignoreSubAppId() {
+    return true;
+  }
+
+  @Override
   protected void storeMap(Map<String, String> map) {
     map.put("order_id", orderId);
     map.put("out_order_no", outOrderNo);

+ 2 - 1
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java

@@ -9,6 +9,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
 import lombok.experimental.Accessors;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.BeanUtils;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
@@ -246,7 +247,7 @@ public abstract class BaseWxPayRequest implements Serializable {
 
       return document.asXML();
     } catch (Exception e) {
-      throw new RuntimeException("generate xml error", e);
+      throw new WxRuntimeException("generate xml error", e);
     }
   }
 

+ 6 - 5
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java

@@ -11,6 +11,7 @@ import com.google.common.collect.Maps;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import org.apache.commons.lang3.StringUtils;
@@ -139,7 +140,7 @@ public abstract class BaseWxPayResult {
         t.loadXml(doc);
         return (T) t;
       } catch (Exception e) {
-        throw new RuntimeException("parse xml error", e);
+        throw new WxRuntimeException("parse xml error", e);
       }
     }
     XStream xstream = XStreamInitializer.getInstance();
@@ -243,7 +244,7 @@ public abstract class BaseWxPayResult {
    */
   public Map<String, String> toMap() {
     if (StringUtils.isBlank(this.xmlString)) {
-      throw new RuntimeException("xml数据有问题,请核实!");
+      throw new WxRuntimeException("xml数据有问题,请核实!");
     }
 
     Map<String, String> result = Maps.newHashMap();
@@ -258,7 +259,7 @@ public abstract class BaseWxPayResult {
         result.put(list.item(i).getNodeName(), list.item(i).getTextContent());
       }
     } catch (XPathExpressionException e) {
-      throw new RuntimeException("非法的xml文本内容:" + xmlString);
+      throw new WxRuntimeException("非法的xml文本内容:" + xmlString);
     }
 
     return result;
@@ -282,7 +283,7 @@ public abstract class BaseWxPayResult {
       factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
       return factory.newDocumentBuilder().parse(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
     } catch (Exception e) {
-      throw new RuntimeException("非法的xml文本内容:\n" + this.xmlString, e);
+      throw new WxRuntimeException("非法的xml文本内容:\n" + this.xmlString, e);
     }
   }
 
@@ -302,7 +303,7 @@ public abstract class BaseWxPayResult {
         .compile(expression)
         .evaluate(doc, XPathConstants.STRING);
     } catch (XPathExpressionException e) {
-      throw new RuntimeException("未找到相应路径的文本:" + expression);
+      throw new WxRuntimeException("未找到相应路径的文本:" + expression);
     }
   }
 

+ 2 - 1
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java

@@ -23,6 +23,7 @@ import com.github.binarywang.wxpay.util.XmlConfig;
 import com.google.common.base.Joiner;
 import com.google.common.collect.Maps;
 import jodd.io.ZipUtil;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -409,7 +410,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
     WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
     String prepayId = unifiedOrderResult.getPrepayId();
     if (StringUtils.isBlank(prepayId)) {
-      throw new RuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。",
+      throw new WxRuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。",
         unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
     }
 

+ 2 - 1
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java

@@ -10,6 +10,7 @@ import com.github.binarywang.wxpay.v3.util.PemUtils;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -94,7 +95,7 @@ public class AutoUpdateCertificatesVerifier implements Verifier {
       autoUpdateCert();
       instant = Instant.now();
     } catch (IOException | GeneralSecurityException e) {
-      throw new RuntimeException(e);
+      throw new WxRuntimeException(e);
     }
   }
 

+ 5 - 3
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/CertificatesVerifier.java

@@ -1,5 +1,7 @@
 package com.github.binarywang.wxpay.v3.auth;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
@@ -30,11 +32,11 @@ public class CertificatesVerifier implements Verifier {
       sign.update(message);
       return sign.verify(Base64.getDecoder().decode(signature));
     } catch (NoSuchAlgorithmException e) {
-      throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+      throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e);
     } catch (SignatureException e) {
-      throw new RuntimeException("签名验证过程发生了错误", e);
+      throw new WxRuntimeException("签名验证过程发生了错误", e);
     } catch (InvalidKeyException e) {
-      throw new RuntimeException("无效的证书", e);
+      throw new WxRuntimeException("无效的证书", e);
     }
   }
 

+ 5 - 3
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PrivateKeySigner.java

@@ -1,5 +1,7 @@
 package com.github.binarywang.wxpay.v3.auth;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
@@ -27,11 +29,11 @@ public class PrivateKeySigner implements Signer {
       return new SignatureResult(
           Base64.getEncoder().encodeToString(sign.sign()), certificateSerialNumber);
     } catch (NoSuchAlgorithmException e) {
-      throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+      throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e);
     } catch (SignatureException e) {
-      throw new RuntimeException("签名计算失败", e);
+      throw new WxRuntimeException("签名计算失败", e);
     } catch (InvalidKeyException e) {
-      throw new RuntimeException("无效的私钥", e);
+      throw new WxRuntimeException("无效的私钥", e);
     }
   }
 }

+ 8 - 6
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java

@@ -1,5 +1,7 @@
 package com.github.binarywang.wxpay.v3.util;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -35,11 +37,11 @@ public class PemUtils {
       return kf.generatePrivate(
           new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
     } catch (NoSuchAlgorithmException e) {
-      throw new RuntimeException("当前Java环境不支持RSA", e);
+      throw new WxRuntimeException("当前Java环境不支持RSA", e);
     } catch (InvalidKeySpecException e) {
-      throw new RuntimeException("无效的密钥格式");
+      throw new WxRuntimeException("无效的密钥格式");
     } catch (IOException e) {
-      throw new RuntimeException("无效的密钥");
+      throw new WxRuntimeException("无效的密钥");
     }
   }
 
@@ -50,11 +52,11 @@ public class PemUtils {
       cert.checkValidity();
       return cert;
     } catch (CertificateExpiredException e) {
-      throw new RuntimeException("证书已过期", e);
+      throw new WxRuntimeException("证书已过期", e);
     } catch (CertificateNotYetValidException e) {
-      throw new RuntimeException("证书尚未生效", e);
+      throw new WxRuntimeException("证书尚未生效", e);
     } catch (CertificateException e) {
-      throw new RuntimeException("无效的证书", e);
+      throw new WxRuntimeException("无效的证书", e);
     }
   }
 }

+ 3 - 2
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java

@@ -2,6 +2,7 @@ package com.github.binarywang.wxpay.v3.util;
 
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
@@ -70,7 +71,7 @@ public class RsaCryptoUtil {
       byte[] ciphertext = cipher.doFinal(data);
       return Base64.getEncoder().encodeToString(ciphertext);
     } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
-      throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
+      throw new WxRuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
     } catch (InvalidKeyException e) {
       throw new IllegalArgumentException("无效的证书", e);
     } catch (IllegalBlockSizeException | BadPaddingException e) {
@@ -87,7 +88,7 @@ public class RsaCryptoUtil {
       byte[] data = Base64.getDecoder().decode(ciphertext);
       return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
     } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
-      throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
+      throw new WxRuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
     } catch (InvalidKeyException e) {
       throw new IllegalArgumentException("无效的私钥", e);
     } catch (BadPaddingException | IllegalBlockSizeException e) {

+ 8 - 5
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/SignUtils.java

@@ -1,12 +1,14 @@
 package com.github.binarywang.wxpay.v3.util;
 
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
 import java.security.*;
 import java.util.Base64;
 import java.util.Random;
 
 public class SignUtils {
 
-  public static String sign(String string, PrivateKey privateKey){
+  public static String sign(String string, PrivateKey privateKey) {
     try {
       Signature sign = Signature.getInstance("SHA256withRSA");
       sign.initSign(privateKey);
@@ -14,23 +16,24 @@ public class SignUtils {
 
       return Base64.getEncoder().encodeToString(sign.sign());
     } catch (NoSuchAlgorithmException e) {
-      throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+      throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e);
     } catch (SignatureException e) {
-      throw new RuntimeException("签名计算失败", e);
+      throw new WxRuntimeException("签名计算失败", e);
     } catch (InvalidKeyException e) {
-      throw new RuntimeException("无效的私钥", e);
+      throw new WxRuntimeException("无效的私钥", e);
     }
   }
 
   /**
    * 随机生成32位字符串.
    */
-  public static String genRandomStr(){
+  public static String genRandomStr() {
     return genRandomStr(32);
   }
 
   /**
    * 生成随机字符串
+   *
    * @param length 字符串长度
    * @return
    */

+ 2 - 1
weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/ApiTestModule.java

@@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import com.google.inject.Binder;
 import com.google.inject.Module;
 import com.thoughtworks.xstream.XStream;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,7 +25,7 @@ public class ApiTestModule implements Module {
   public void configure(Binder binder) {
     try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(TEST_CONFIG_XML)) {
       if (inputStream == null) {
-        throw new RuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
+        throw new WxRuntimeException("测试配置文件【" + TEST_CONFIG_XML + "】未找到,请参照test-config-sample.xml文件生成");
       }
 
       XmlWxPayConfig config = this.fromXml(XmlWxPayConfig.class, inputStream);