Explorar o código

issue #66 对去重逻辑做了一些调整

Daniel Qian %!s(int64=10) %!d(string=hai) anos
pai
achega
3216cb54dd

+ 12 - 3
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageDuplicateChecker.java

@@ -9,10 +9,19 @@ package me.chanjar.weixin.common.util;
 public interface WxMessageDuplicateChecker {
 
   /**
-   * 检查消息ID是否重复
-   * @param wxMsgId
+   * <h2>公众号的排重方式</h2>
+   *
+   * <p>普通消息:关于重试的消息排重,推荐使用msgid排重。<a href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html">文档参考</a>。</p>
+   * <p>事件消息:关于重试的消息排重,推荐使用FromUserName + CreateTime 排重。<a href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html">文档参考</a></p>
+   *
+   * <h2>企业号的排重方式</h2>
+   *
+   * 官方文档完全没有写,参照公众号的方式排重。
+   *
+   * <p>或者可以采取更简单的方式,如果有MsgId就用MsgId排重,如果没有就用FromUserName+CreateTime排重</p>
+   * @param messageId messageId需要根据上面讲的方式构造
    * @return 如果是重复消息,返回true,否则返回false
    */
-  public boolean isDuplicate(Long wxMsgId);
+  public boolean isDuplicate(String messageId);
 
 }

+ 5 - 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateChecker.java

@@ -25,7 +25,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
   /**
    * 消息id->消息时间戳的map
    */
-  private final ConcurrentHashMap<Long, Long> msgId2Timestamp = new ConcurrentHashMap<Long, Long>();
+  private final ConcurrentHashMap<String, Long> msgId2Timestamp = new ConcurrentHashMap<String, Long>();
 
   /**
    * 后台清理线程是否已经开启
@@ -65,7 +65,7 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
           while (true) {
             Thread.sleep(clearPeriod);
             Long now = System.currentTimeMillis();
-            for (Map.Entry<Long, Long> entry : msgId2Timestamp.entrySet()) {
+            for (Map.Entry<String, Long> entry : msgId2Timestamp.entrySet()) {
               if (now - entry.getValue() > timeToLive) {
                 msgId2Timestamp.entrySet().remove(entry);
               }
@@ -81,12 +81,12 @@ public class WxMessageInMemoryDuplicateChecker implements WxMessageDuplicateChec
   }
 
   @Override
-  public boolean isDuplicate(Long wxMsgId) {
-    if (wxMsgId == null) {
+  public boolean isDuplicate(String messageId) {
+    if (messageId == null) {
       return false;
     }
     checkBackgroundProcessStarted();
-    Long timestamp = msgId2Timestamp.putIfAbsent(wxMsgId, System.currentTimeMillis());
+    Long timestamp = msgId2Timestamp.putIfAbsent(messageId, System.currentTimeMillis());
     if (timestamp == null) {
       // 第一次接收到这个消息
       return false;

+ 3 - 3
weixin-java-common/src/test/java/me/chanjar/weixin/common/util/WxMessageInMemoryDuplicateCheckerTest.java

@@ -12,21 +12,21 @@ public class WxMessageInMemoryDuplicateCheckerTest {
 
     // 第一次检查
     for (Long msgId : msgIds) {
-      boolean result = checker.isDuplicate(msgId);
+      boolean result = checker.isDuplicate(String.valueOf(msgId));
       Assert.assertFalse(result);
     }
 
     // 过1秒再检查
     Thread.sleep(1000l);
     for (Long msgId : msgIds) {
-      boolean result = checker.isDuplicate(msgId);
+      boolean result = checker.isDuplicate(String.valueOf(msgId));
       Assert.assertTrue(result);
     }
 
     // 过1.5秒再检查
     Thread.sleep(1500l);
     for (Long msgId : msgIds) {
-      boolean result = checker.isDuplicate(msgId);
+      boolean result = checker.isDuplicate(String.valueOf(msgId));
       Assert.assertFalse(result);
     }
 

+ 17 - 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java

@@ -115,7 +115,7 @@ public class WxCpMessageRouter {
    * @param wxMessage
    */
   public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
-    if (messageDuplicateChecker.isDuplicate(wxMessage.getMsgId())) {
+    if (isDuplicateMessage(wxMessage)) {
       // 如果是重复消息,那么就不做处理
       return null;
     }
@@ -177,6 +177,22 @@ public class WxCpMessageRouter {
     return res;
   }
 
+  protected boolean isDuplicateMessage(WxCpXmlMessage wxMessage) {
+
+    String messageId = "";
+    if (wxMessage.getMsgId() == null) {
+      messageId = wxMessage.getFromUserName() + "-" + String.valueOf(wxMessage.getCreateTime());
+    } else {
+      messageId = String.valueOf(wxMessage.getMsgId());
+    }
+
+    if (messageDuplicateChecker.isDuplicate(messageId)) {
+      return true;
+    }
+    return false;
+
+  }
+
   /**
    * 对session的访问结束
    * @param wxMessage

+ 18 - 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java

@@ -1,5 +1,6 @@
 package me.chanjar.weixin.mp.api;
 
+import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.session.*;
 import me.chanjar.weixin.common.util.WxMessageDuplicateChecker;
 import me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateChecker;
@@ -113,7 +114,7 @@ public class WxMpMessageRouter {
    * @param wxMessage
    */
   public WxMpXmlOutMessage route(final WxMpXmlMessage wxMessage) {
-    if (messageDuplicateChecker.isDuplicate(wxMessage.getMsgId())) {
+    if (isDuplicateMessage(wxMessage)) {
       // 如果是重复消息,那么就不做处理
       return null;
     }
@@ -175,6 +176,22 @@ public class WxMpMessageRouter {
     return res;
   }
 
+  protected boolean isDuplicateMessage(WxMpXmlMessage wxMessage) {
+
+    String messageId = "";
+    if (wxMessage.getMsgId() == null) {
+      messageId = wxMessage.getFromUserName() + "-" + String.valueOf(wxMessage.getCreateTime());
+    } else {
+      messageId = String.valueOf(wxMessage.getMsgId());
+    }
+
+    if (messageDuplicateChecker.isDuplicate(messageId)) {
+      return true;
+    }
+    return false;
+
+  }
+
   /**
    * 对session的访问结束
    * @param wxMessage