Bladeren bron

修复展示消息首页时会同时展示已读和未读的bug.已读消息和未读消息混合排序

nnkwrik 6 jaren geleden
bovenliggende
commit
91da44decd

+ 1 - 1
auth-service/src/test/java/io/github/nnkwrik/authservice/jwt/GenerateToken.java

@@ -32,7 +32,7 @@ public class GenerateToken {
      */
     @Test
     public void generateToken() throws IllegalAccessException {
-        String openId = "1";
+        String openId = "3";
         String nickName = "测试用户";
         String avatarUrl = "https://avatars2.githubusercontent.com/u/29662114?s=460&v=4";
 

+ 7 - 5
im-service/src/main/java/io/github/nnkwrik/imservice/controller/ChatController.java

@@ -3,7 +3,6 @@ package io.github.nnkwrik.imservice.controller;
 import io.github.nnkwrik.common.dto.JWTUser;
 import io.github.nnkwrik.common.dto.Response;
 import io.github.nnkwrik.common.token.injection.JWT;
-import io.github.nnkwrik.imservice.model.po.LastChat;
 import io.github.nnkwrik.imservice.model.vo.ChatForm;
 import io.github.nnkwrik.imservice.model.vo.ChatIndex;
 import io.github.nnkwrik.imservice.redis.RedisClient;
@@ -16,6 +15,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -42,8 +42,7 @@ public class ChatController {
         if (user == null) {
             return Response.ok(0);
         }
-        List<LastChat> unreadMessage = redisClient.hvals(user.getOpenId());
-        int unreadCount = unreadMessage.stream().mapToInt(LastChat::getUnreadCount).sum();
+        int unreadCount = indexService.getUnreadCount(user.getOpenId());
         log.info("已登录用户查询未读消息个数, {} 条未读信息.用户id = {},用户昵称 = {}", unreadCount, user.getOpenId(), user.getNickName());
 
         return Response.ok(unreadCount);
@@ -52,12 +51,15 @@ public class ChatController {
     //打开消息一览时
     @GetMapping("/chat/index")
     public Response<List<ChatIndex>> getChatIndex(@JWT JWTUser user,
-                                                  @RequestParam(value = "page", defaultValue = "1") int page,
+                                                  @RequestParam(value = "offsetTime", required = false) Date offsetTime,
                                                   @RequestParam(value = "size", defaultValue = "10") int size) {
         if (user == null) {
             return Response.ok(0);
         }
-        List<ChatIndex> voList = indexService.showIndex(user.getOpenId(), page, size);
+        if (offsetTime == null) {
+            offsetTime = new Date();
+        }
+        List<ChatIndex> voList = indexService.showIndex(user.getOpenId(), size, offsetTime);
         log.info("展示消息一览,展示{} 条信息.用户id = {},用户昵称 = {}", voList.size(), user.getOpenId(), user.getNickName());
 
         return Response.ok(voList);

+ 6 - 0
im-service/src/main/java/io/github/nnkwrik/imservice/dao/ChatMapper.java

@@ -3,6 +3,8 @@ package io.github.nnkwrik.imservice.dao;
 import io.github.nnkwrik.imservice.model.po.Chat;
 import org.apache.ibatis.annotations.*;
 
+import java.util.List;
+
 /**
  * @author nnkwrik
  * @date 18/12/05 21:54
@@ -23,4 +25,8 @@ public interface ChatMapper {
     @Select("select u1,u2,goods_id from chat where id = #{id}")
     Chat getChatById(@Param("id") int id);
 
+    @Select("select id\n" +
+            "from chat where (u1 = #{user_id} and show_to_u1 = true) or (u2 = #{user_id} and show_to_u2 = true)")
+    List<Integer> getChatIdsByUser(@Param("user_id") String userId);
+
 }

+ 20 - 9
im-service/src/main/java/io/github/nnkwrik/imservice/dao/HistoryMapper.java

@@ -6,6 +6,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -23,11 +24,12 @@ public interface HistoryMapper {
             "values (#{chatId}, #{u1ToU2}, #{messageType}, #{messageBody}, #{sendTime});")
     void addHistory(History history);
 
-
     /**
-     * 获取自己和所有人的最后一条"已读的"聊天记录,按时间倒序
+     * 获取自己和所有人的最后一条"已读的"聊天记录,取offsetTime之前的,按时间倒序
      *
      * @param unreadChatIds 未读的chatId
+     * @param userId        当前用户的id
+     * @param offsetTime    取offsetTime之前
      * @return
      */
     @Select("<script>\n" +
@@ -35,18 +37,27 @@ public interface HistoryMapper {
             "from history\n" +
             "       inner join (select chat_id, max(send_time) as max_time\n" +
             "                   from history\n" +
-            "                   where chat_id in (select id\n" +
-            "                                     from chat\n" +
-            "                                     where id not in\n" +
+            "                   where chat_id in\n" +
+            "                         (select id\n" +
+            "                          from chat\n" +
+            "                                     where " +
+            "                   <if test=\"unreadChatIds.size() > 0\">" +
+            "                       id not in\n" +
             "                       <foreach item = 'item' collection = 'unreadChatIds' open = '(' separator = ',' close = ')'>\n" +
             "                       #{item}\n" +
             "                       </foreach>\n" +
-            "                       and ((u1 = 1 and show_to_u1 = true) or (u2 = 1 and show_to_u2 = true)))\n" +
-            "                   group by chat_id) as foo on foo.chat_id = history.chat_id and foo.max_time = history.send_time\n" +
-            "        inner join chat where history.chat_id = chat.id\n" +
+            "                            and " +
+            "                   </if>" +
+            "                   ((u1 = #{user_id} and show_to_u1 = true) or (u2 = #{user_id} and show_to_u2 = true)))\n" +
+            "                   group by chat_id\n" +
+            "                   HAVING max_time &lt;= #{offset_time,jdbcType=TIMESTAMP}) as foo\n" +
+            "         on foo.chat_id = history.chat_id and foo.max_time = history.send_time\n" +
+            "       inner join chat on history.chat_id = chat.id\n" +
             "order by send_time desc" +
             "</script>")
-    List<HistoryExample> getLastReadChat(@Param("unreadChatIds") List<Integer> unreadChatIds);
+    List<HistoryExample> getLastReadChat(@Param("unreadChatIds") List<Integer> unreadChatIds,
+                                         @Param("user_id") String userId,
+                                         @Param("offset_time") Date offsetTime);
 
 
     /**

+ 10 - 8
im-service/src/main/java/io/github/nnkwrik/imservice/redis/RedisClient.java

@@ -16,19 +16,21 @@ public class RedisClient {
     private RedisTemplate redisTemplate;
 
 
-    public <T> T hget(String key, String field) {
-        return (T) redisTemplate.opsForHash().get(key, field);
+    public <T> T get(String key) {
+        return (T) redisTemplate.opsForValue().get(key);
     }
 
-    public void hset(String key, String field, Object value) {
-        redisTemplate.opsForHash().put(key, field, value);
+    public <T> List<T> multiGet(List<String> keys) {
+        return redisTemplate.opsForValue().multiGet(keys);
     }
 
-    public <T> List<T> hvals(String key) {
-        return redisTemplate.opsForHash().values(key);
+    public void set(String key, Object value) {
+        redisTemplate.opsForValue().set(key, value);
     }
 
-    public void hdel(String key,String... fields){
-        redisTemplate.opsForHash().delete(key,fields);
+    public void del(String key) {
+        redisTemplate.delete(key);
     }
+
+
 }

+ 4 - 1
im-service/src/main/java/io/github/nnkwrik/imservice/service/IndexService.java

@@ -2,6 +2,7 @@ package io.github.nnkwrik.imservice.service;
 
 import io.github.nnkwrik.imservice.model.vo.ChatIndex;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -9,5 +10,7 @@ import java.util.List;
  * @date 18/12/07 16:31
  */
 public interface IndexService {
-    List<ChatIndex> showIndex(String userId, int page, int size);
+    List<ChatIndex> showIndex(String userId, int size, Date offsetTime);
+
+    int getUnreadCount(String userId);
 }

+ 8 - 5
im-service/src/main/java/io/github/nnkwrik/imservice/service/impl/FormServiceImpl.java

@@ -47,7 +47,7 @@ public class FormServiceImpl implements FormService {
 
     @Override
     public ChatForm showForm(int chatId, String userId, int page, int size, int offset) {
-        flushUnread(userId, chatId);
+        flushUnread(chatId, userId);
         ChatForm vo = new ChatForm();
 
         Chat chat = chatMapper.getChatById(chatId);
@@ -70,10 +70,13 @@ public class FormServiceImpl implements FormService {
         return vo;
     }
 
-    private void flushUnread(String userId, int chatId) {
-        LastChat lastChat = redisClient.hget(userId, chatId + "");
-        addMessageToSQL(lastChat.getLastMsg());
-        redisClient.hdel(userId, chatId + "");
+    private void flushUnread(int chatId, String userId) {
+        LastChat lastChat = redisClient.get(chatId + "");
+        if (lastChat.getLastMsg().getReceiverId().equals(userId)) {
+            log.info("把chatId={}设为已读消息", chatId);
+            addMessageToSQL(lastChat.getLastMsg());
+            redisClient.del(chatId + "");
+        }
     }
 
 //    public void flushWsMsgList(String userId, int chatId,List<WsMessage> wsMsgList){

+ 76 - 43
im-service/src/main/java/io/github/nnkwrik/imservice/service/impl/IndexServiceImpl.java

@@ -5,6 +5,7 @@ import fangxianyu.innerApi.goods.GoodsClientHandler;
 import fangxianyu.innerApi.user.UserClientHandler;
 import io.github.nnkwrik.common.dto.SimpleGoods;
 import io.github.nnkwrik.common.dto.SimpleUser;
+import io.github.nnkwrik.imservice.dao.ChatMapper;
 import io.github.nnkwrik.imservice.dao.HistoryMapper;
 import io.github.nnkwrik.imservice.model.po.History;
 import io.github.nnkwrik.imservice.model.po.HistoryExample;
@@ -17,10 +18,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -43,69 +41,74 @@ public class IndexServiceImpl implements IndexService {
     @Autowired
     private GoodsClientHandler goodsClientHandler;
 
+    @Autowired
+    private ChatMapper chatMapper;
+
 
     @Override
-    public List<ChatIndex> showIndex(String currentUser, int page, int size) {
-        List<LastChat> unreadMessage = redisClient.hvals(currentUser);
+    public List<ChatIndex> showIndex(String currentUser, int size, Date offsetTime) {
 
         List<ChatIndex> resultVoList = new ArrayList<>();    //最终要返回的值
-        Map<Integer, Integer> chatGoodsMap = new HashMap<>();         //需要去商品服务查的id
-        Map<Integer, String> chatUserMap = new HashMap<>();           //需要去用户服务查的id
+        Map<Integer, Integer> chatGoodsMap = new HashMap<>();         //k=chatId,v=需要去商品服务查的id
+        Map<Integer, String> chatUserMap = new HashMap<>();           //k=chatId,v=需要去用户服务查的id
 
+        List<Integer> chatIds = chatMapper.getChatIdsByUser(currentUser);
+        List<LastChat> unreadMessage = redisClient.multiGet(
+                chatIds.stream()
+                        .map(id -> id + "")
+                        .collect(Collectors.toList()));
 
-        int alreadyShow = size * (page - 1);
-        int needShow = page * size;
-        if (unreadMessage.size() >= needShow) {
-            //需要展示的内容全在redis中
+        //从redis(未读)和sql(已读)中各尝试取10个
+        List<LastChat> unread = getDisplayUnread(unreadMessage, size, offsetTime);
+        dealUnread(currentUser, unread, resultVoList, chatGoodsMap, chatUserMap);
 
-            List<LastChat> unread = getDisplayUnread(unreadMessage, alreadyShow, size);
-
-            dealUnread(unread, resultVoList, chatGoodsMap, chatUserMap);
-        } else if (unreadMessage.size() > alreadyShow) {
-            //需要的内容的一部分在redis(未读),一部分在sql(已读)
+        List<Integer> unreadChatIds = unread.stream()
+                .map(chat -> chat.getLastMsg().getChatId())
+                .collect(Collectors.toList());
+        PageHelper.offsetPage(0, size);
+        List<HistoryExample> read = historyMapper.getLastReadChat(unreadChatIds, currentUser, offsetTime);
+        dealRead(read, currentUser, resultVoList, chatGoodsMap, chatUserMap);
 
-            //未读消息
-            List<LastChat> unread = getDisplayUnread(unreadMessage, alreadyShow, size);
-            dealUnread(unread, resultVoList, chatGoodsMap, chatUserMap);
+        //排序后删除超出size的
+        sortAndLimitMsg(size, resultVoList, chatGoodsMap, chatUserMap);
 
 
-            List<Integer> unreadChatIds = unread.stream()
-                    .map(chat -> chat.getLastMsg().getChatId())
-                    .collect(Collectors.toList());
+        //添加用户和商品信息
+        resultVoList = setGoodsAndUser4Chat(resultVoList, chatGoodsMap, chatUserMap);
 
-            //已读消息
-            int remain = needShow - unreadMessage.size();
-            PageHelper.offsetPage(0, remain);
-            List<HistoryExample> read = historyMapper.getLastReadChat(unreadChatIds);
-            dealRead(read, currentUser, resultVoList, chatGoodsMap, chatUserMap);
 
+        return resultVoList;
+    }
 
-        } else {
-            //需要的内容全在sql
+    @Override
+    public int getUnreadCount(String userId) {
+        //去查userId参与的chat的id
+        List chatIdList = chatMapper.getChatIdsByUser(userId);
+        List<LastChat> lastChatList = redisClient.multiGet(chatIdList);
 
-            int offset = alreadyShow - unreadMessage.size();
-            PageHelper.offsetPage(offset, size);
-            List<HistoryExample> read = historyMapper.getLastChat();
-            dealRead(read, currentUser, resultVoList, chatGoodsMap, chatUserMap);
-        }
+        //过滤自己发送的
+        int unreadCount = lastChatList.stream()
+                .filter(chat -> !chat.getLastMsg().getSenderId().equals(userId))
+                .mapToInt(LastChat::getUnreadCount)
+                .sum();
 
-        //添加用户和商品信息
-        resultVoList = setGoodsAndUser4Chat(resultVoList, chatGoodsMap, chatUserMap);
+        return unreadCount;
 
-        return resultVoList;
     }
 
 
-    private List<LastChat> getDisplayUnread(List<LastChat> unreadMessage, int offset, int size) {
+    private List<LastChat> getDisplayUnread(List<LastChat> unreadMessage, int size, Date offsetTime) {
         List<LastChat> displayUnread = unreadMessage.stream()
+                .filter(msg -> msg != null && offsetTime.compareTo(msg.getLastMsg().getSendTime()) > 0)
                 .sorted((a, b) -> b.getLastMsg().getSendTime().compareTo(a.getLastMsg().getSendTime()))
-                .skip(offset)
                 .limit(size)
                 .collect(Collectors.toList());
+
         return displayUnread;
     }
 
-    private void dealUnread(List<LastChat> unread,
+    private void dealUnread(String currentUserId,
+                            List<LastChat> unread,
                             List<ChatIndex> resultVoList,
                             Map<Integer, Integer> chatGoodsMap,
                             Map<Integer, String> chatUserMap) {
@@ -115,9 +118,13 @@ public class IndexServiceImpl implements IndexService {
             chatGoodsMap.put(po.getLastMsg().getChatId(), po.getLastMsg().getGoodsId());
             chatUserMap.put(po.getLastMsg().getChatId(), po.getLastMsg().getSenderId());
 
-            //设置未读数
+            //设置未读数,是自己发送的则不显示未读消息数
             ChatIndex vo = new ChatIndex();
-            vo.setUnreadCount(po.getUnreadCount());
+            if (po.getLastMsg().getSenderId().equals(currentUserId)) {
+                vo.setUnreadCount(0);
+            } else {
+                vo.setUnreadCount(po.getUnreadCount());
+            }
 
             //设置最后一条信息
             History lastChat = new History();
@@ -157,6 +164,32 @@ public class IndexServiceImpl implements IndexService {
 
     }
 
+    private void sortAndLimitMsg(int size,
+                                List<ChatIndex> voList,
+                                Map<Integer, Integer> chatGoodsMap,
+                                Map<Integer, String> chatUserMap) {
+        voList = voList.stream()
+                .sorted((a, b) -> b.getLastChat().getSendTime().compareTo(a.getLastChat().getSendTime()))
+                .limit(size)
+                .collect(Collectors.toList());
+        if (voList.size() > size) {
+            Set<Integer> addedIds = new HashSet<>();
+            addedIds.addAll(chatUserMap.keySet());
+            addedIds.addAll(chatUserMap.keySet());
+            List<Integer> needIds = voList.stream()
+                    .map(vo -> vo.getLastChat().getChatId())
+                    .collect(Collectors.toList());
+            for (Integer added : addedIds) {
+
+                if (!needIds.contains(added)) {
+                    chatGoodsMap.remove(added);
+                    chatUserMap.remove(added);
+                }
+            }
+        }
+
+    }
+
     private List<ChatIndex> setGoodsAndUser4Chat(List<ChatIndex> voList,
                                                  Map<Integer, Integer> chatGoodsMap,
                                                  Map<Integer, String> chatUserMap) {

+ 2 - 2
im-service/src/main/java/io/github/nnkwrik/imservice/service/impl/WebSocketServiceImpl.java

@@ -75,7 +75,7 @@ public class WebSocketServiceImpl implements WebSocketService {
     }
 
     private void updateRedis(WsMessage message) {
-        LastChat lastChat = redisClient.hget(message.getReceiverId(), message.getChatId() + "");
+        LastChat lastChat = redisClient.get(message.getChatId() + "");
         if (lastChat != null) {
             lastChat.setUnreadCount(lastChat.getUnreadCount() + 1);
             lastChat.setLastMsg(message);
@@ -84,7 +84,7 @@ public class WebSocketServiceImpl implements WebSocketService {
             lastChat.setUnreadCount(1);
             lastChat.setLastMsg(message);
         }
-        redisClient.hset(message.getReceiverId(), message.getChatId() + "", lastChat);
+        redisClient.set(message.getChatId() + "", lastChat);
     }
 
 

+ 0 - 35
im-service/src/test/java/io/github/nnkwrik/imservice/TestRedisClient.java

@@ -1,35 +0,0 @@
-package io.github.nnkwrik.imservice;
-
-import io.github.nnkwrik.imservice.model.vo.WsMessage;
-import io.github.nnkwrik.imservice.redis.RedisClient;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.List;
-
-/**
- * @author nnkwrik
- * @date 18/12/07 13:57
- */
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-public class TestRedisClient {
-
-    @Autowired
-    private RedisClient redisClient;
-
-    @Test
-    public void testNoUnread(){
-        //not exist
-        List<WsMessage> hvals = redisClient.hvals("1212");
-        if (hvals == null){
-            System.out.println("null");
-        }else {
-            System.out.println(hvals.size());
-        }
-
-    }
-}