websocket实现实时通信,通知未读已读

3,254 阅读3分钟

好久没有写文章了,最近粗略实现了文章未读已读和实时通信功能,在此记录一下此功能的实现。😁🍔

前端:Vue2

后端:SpringBoot

组件库:Element-UI

前言

一开始在网上找资料的时候看到很多人用websocket和redis实现实时通信(聊天室),我本来想尝试一下redis,但是我这个项目只是涉及到通知未读已读和发布文章时需要实时通信,后面还是用mysql临时记录一下。

主要思路:

  1. 创建一个表格用于记录通知信息(通知id,作者id,作者姓名,创作时间等),一个表格用于记录每位用户未读通知的信息(用户id,文章id,记录id等);
  2. 用户登录后,会发送一个请求获取未读消息列表unread并存入vuex中,Header中有一个通知图标带有Badge(标记),上面的数字即为未读消息数量;
  3. 点击进入可以看到消息列表,点击消息可以进入文章详情界面。也就是在进入文章详情页面的时候,在未读消息列表(vuex中的unread)中删除该通知,并且发送请求删除表中对应数据。
  4. 发布通知时,后端会存储通知相关信息,记录每位非作者用户未读此通知。并通过websocket发送消息给后端。后端收到消息后向非作者用户广播各个用户的未读通知列表。

鉴于网上有很多通用的配置,我在此就只展示用于我实现此功能的主要代码了。

后端

建立连接成功后,发送该用户未读通知列表

@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
    this.session = session;
    this.userId= userId;
    // 将用户id和实例存入webSocketSet
    webSocketSet.put(userId, this);
    try {
    // 根据用户id查找其未读通知列表
        List<TempNoticeVo> tn = tempNoticeMapper.selectList(this.userId);
        String json = JSON.toJSONString(tn);
        this.session.getBasicRemote().sendText(json);
    } catch (IOException e) {
        log.error("用户:"+userId+",网络异常!");
    }
}

接收到用户发送的消息后,将用户未读通知列表进行广播

    @OnMessage
    public void onMessage(String noticeid, Session session) throws IOException {
        // 广播消息(除了发通知作者,其余都通知)
        
        List<Id> ids = personMapper.findAllId();
        for(int i=0;i<ids.size();i++) {
            if(ids.get(i).getId().equals(userId))
                ids.remove(i);
        }
        if(id!=null)
            tempNoticeMapper.addList(id,ids);
        else{
            System.out.println("noticeid为空");
        }
        sendMessage(noticeid);
    }
    
 public void sendMessage(String message) throws IOException {
    for (String key:webSocketSet.keySet()){
         if(!userId.equals(key)){
           System.out.println("userid为:"+key);
           List<TempNoticeVo> tn = tempNoticeMapper.selectList(key);
           String json = JSON.toJSONString(tn);
           webSocketSet.get(key).session.getBasicRemote().sendText(json);
    }
}

前端

建立连接,收到服务器传过来的未读消息列表后将其存入vuex

    conWebSocket(noticeid) {
      const vm = this
      if (window.WebSocket) {
        vm.socket = new WebSocket(`ws://localhost:8083/websocket/${vm.uid}`)
        const socket = vm.socket
        socket.onopen = function (e) {
          console.log('连接服务器成功')
          vm.$message({ type: 'success', message: '连接服务器成功' })
        }
        socket.onclose = function (e) {
          console.log('服务器关闭')
        }
        socket.onerror = function () {
          console.log('连接出错')
        }
        // 接收服务器的消息
        socket.onmessage = function (e) {
          const message = JSON.parse(e.data)
          store.commit('user/setUnread', message)
        }
      }
    }

发布文章得到后端传过来的通知id后通过websocket向服务器发送信息

    conWebSocket(noticeid) {
      const vm = this
      if (window.WebSocket) {
        vm.socket = new WebSocket(`ws://localhost:8083/websocket/${vm.uid}`)
        const socket = vm.socket
        socket.onopen = function (e) {
          console.log('连接服务器成功')
          vm.$message({ type: 'success', message: '连接服务器成功' })
          if (vm.uid && noticeid !== -1) {
            vm.socket.send(noticeid)
          }
        }
        socket.onclose = function (e) {
          console.log('服务器关闭')
        }
        socket.onerror = function () {
          console.log('连接出错')
        }
        // 接收服务器的消息
        socket.onmessage = function (e) {
          const message = JSON.parse(e.data)
          console.log(message)
        }
      }
    },

前端两个不同的组件分别创建了一个 WebSocket实例进行通信,可以用但是我想知道这样有没有问题或者怎么处理更好,有大佬知道的可以在评论区指点一下嘛,先谢为敬🤝

实现效果如下:

通知未读已读.gif

其他

此处只是粗略实现实时通信和消息未读已读功能,所以写的不是很完善。想要了解实时通信有大佬推荐看socket.io官网,因为websocket用起来不太行。