【分布式websocket 】前端vuex管理客户端消息crud!使用localStorage来存储【第19期】

前言

聊天系统客户端是要存储消息的,因为所有所有的历史消息都从服务器拉的话一方面服务器压力大,另一方面也耗费用户流量。所以客户端存储消息是势在必行的。如何存储呢上一篇文章也写了,大概就是浏览器的话是localStorage或者IndexedDB。然后手机端和桌面端就是sqllite了。这样子消息的存储结构以及消息的增删改查也是需要一套的了。本篇文章将着重从自己的开源项目技术选型来进行分享。vuex进行增删改查。B站会录制视频同步分享。

目前已经写的文章有。并且有对应视频版本。
git项目地址 【IM即时通信系统(企聊聊)】点击可跳转
sprinboot单体项目升级成springcloud项目 【第一期】
前端项目技术选型以及页面展示【第二期】
分布式权限 shiro + jwt + redis【第三期】
给为服务添加运维模块 统一管理【第四期】
微服务数据库模块【第五期】
netty与mq在项目中的使用(第六期(废弃))】
分布式websocket即时通信(IM)系统构建指南【第七期】
分布式websocket即时通信(IM)系统保证消息可靠性【第八期】
分布式websocket IM聊天系统相关问题问答【第九期】
什么?websocket也有权限!这个应该怎么做?【第十期】
分布式ID是什么,以美团Leaf为例改造融入自己项目【第十一期】
IM聊天系统为什么需要做消息幂等?如何使用Redis以及Lua脚本做消息幂等【第12期】
微信发送一条消息经历哪些过程。企业微信以及钉钉的IM架构对比【第13期】
微信群为什么上限是500人,IM设计系统中的群聊的设计难点【第14期】
【分布式websocket】RocketMQ发送消息保证消息最终一致性需要做哪些处理?【第15期】

【分布式websocket】群聊中的各种难点以及解决推拉结合【第16期】

【分布式webscoket】未读消息如何设计?解决缓存与数据库数据一致性!推送未读消息流程【第17期】

IM系统客户端消息存储在手机电脑浏览器分别存储在什么地方?对消息加密策略?如何保证服务端消息和客户端消息一致性【第18期】
【分布式websocket】聊天系统消息加密如何做【第20期】
【分布式webscoket】IM聊天系统消息如何存储 如何分库分表以及Seata解决事务以及ShardingSphere-Scaling解决数据迁移【第21期】

客户端消息结构:

技术选型在浏览器端的localStorage,当然是有缺陷的。后续根据情况再进行优化。页面如下。
在这里插入图片描述

在这里插入图片描述

chats: []            数组 存放每一个聊天用户
	lastContent:	 存放最后一条消息用于显示
	tagrgetId: 		 标识唯一会话,可以考虑改成会话id,目前使用的是单聊是对方的id,群聊是群聊id
	type :			 标记是私聊还是群聊
	unreadCount:	 未读消息数量 (TODO)
	messgaes :[]    存放每一个用户下面具体的聊天消息,数组
		type:		 用于标记消息是自己发的还是别人的,用于前端显示样式
		group:        用于区分消息是群聊还是单聊 ,创建消息的时候会使用到
		msgid:        消息唯一id
		avatarUrl:    用于页面上面显示聊天头像框
		content:	     消息内容
		tagrgetId:     标识唯一会话id
privateMsgMaxId: 拉取消息id

如下
客户端消息操作主要是 .

  • 添加 1.上线后拉取未读消息要存储未读消息 2.发送消息需要添加消息3.收到消息需要添加
  • 查询 进入聊天页面需要可以查到消息
  • 修改 消息发送失败需要修改状态发送失败
  • 删除 前端存储有限制只能维护一定时间的历史消息。更多的历史消息查询客户端

vuex基本概念概述

export default createStore({
  state,
  mutations,
  actions,
  getters,
  modules: {}
})

大概就是这么几个部分。
总结来说,Getter 用于获取由 state 计算得出的数据;
Mutation 用于同步地改变 state,
Action 则封装了异步操作,并最终通过 commit 来间接触发 mutations 更新状态。
state 就是封装变量的地方。

Vuex 允许将应用程序的状态集中存储在一个共享的 store 中,避免了组件之间通过 props 和 events 进行状态传递的复杂性和繁琐性。这使得状态管理更加清晰和易于维护。通过 Vuex 管理状态,整个应用程序共享同一个状态树,确保了状态的一致性和同步性。

场景介绍

消息查询

    // 创建一个计算属性,该属性基于其他响应式状态计算值
    const computedChats = computed(() => {
      let chat = null;
      console.log("computedChats route.query.groupId", route.query.groupId);
      if (state.current == 1) {
        chat = {
          targetId: state.toUser.openid,
        };
      } else {
        chat = {
          // targetId: state.toUser.openid,
          targetId: state.groupId,
        };
      }
      const idx = store.getters.findChatIdx(chat);
      if (idx == null || idx == undefined) {
        return [];
      }
      if (
        store.state.chats[idx] == null ||
        store.state.chats[idx] == undefined
      ) {
        return [];
      }
      console.log("computedChats idx", idx);
      console.log("computedChats 寻找成功啦", store.state.chats[idx]);
      return store.state.chats[idx];
    });

封装了一个计算属性。用于监听state里面的消息变化。逻辑大概是拿到当前会话的id,单聊的话就是对话的openid。然后去store里面去找一下。找不到的返回空数组。找到的话返回当前聊天下的所有信息.

对应前台页面

渲染一下这个compute属性

   <list-scroll :scroll-data="computedChats.messages">
            <div class="swiper-container">
              <div
                class="content"
                v-for="(item, index) in computedChats.messages"
                :key="index"
              >
                <div class="d-felx justify-start " v-if="item.type === 'self'">
                  <div style="display: flex;">
                    <van-image
                      width="35px"
                      height="35px"
                      fit="cover"
                      :src="userInfo.avatarUrl"
                    />
                    <div class="font-18 content1">
                      <text>{{ item.content }}</text>
                    </div>
                  </div>
                </div>
                <div
                  style="display: flex; justify-content: flex-end;"
                  v-if="item.type === 'receive'"
                >
                  <div class="font-18 content2">
                    <text>{{ item.content }}</text>
                  </div>
                  <div class="">
                    <van-image
                      width="35px"
                      height="35px"
                      fit="cover"
                      :src="toUser.avatarUrl"
                    />
                  </div>
                </div>
              </div>
            </div>
          </list-scroll>

消息添加

分为离线数据添加 和在线数据添加。
离线数据添加需要使用到action,异步的去后台拉取然后插入。
在线数据直接调用mutation数据插入。

 /**
   * 插入消息.
   * @param {*} state
   * @param {*} msgInfo 当前消息
   */
  insertMessage(state, msgInfo) {
    console.log("insertMessage",msgInfo)
      state.privateMsgMaxId = msgInfo.msgId;
      state.groupMsgMaxId = msgInfo.msgId;
    // 如果是已存在消息,则覆盖旧的消息数据
    let chat = this.getters.findChat(msgInfo);
    if (chat == null) {
      this.commit("createChat", msgInfo);
      chat = this.getters.findChat(msgInfo);
    }
    if(chat == null){
      console.log("没有找到chat",chat);
      return;
    }
    chat.messages.push(msgInfo);
    this.commit("saveToStorage");
  },

第一步,先更新一下这个最大的消息id。然后去store里面去找当前消息。找到之后给当前chat里面推送消息。并且同步的保存到Storgae里面.


 /**
   *  state.chats 将更新后的存储.
   * @param {*} state
   */
  saveToStorage(state) {
    let userId = state.userInfo.openid;
    let key = "chats-" + userId;
    let chatsData = {
      privateMsgMaxId: state.privateMsgMaxId,
      groupMsgMaxId: state.groupMsgMaxId,
      chats: state.chats,
    };
    localStorage.setItem(key, JSON.stringify(chatsData));
  },

这个存储的逻辑就是简单的将消息序列化后放到localStorage里面。

强调一下这个离线消息拉取的步骤;需要后台sql的配合。
 async pullOffline(ctx) {
    // 获取当前store中的privateMsgMaxId
    const privateMsgMaxId = ctx.state.privateMsgMaxId+"";
    console.log("privateMsgMaxId",ctx.state.privateMsgMaxId)
    const res = await getChatContentAll(privateMsgMaxId);
    const contentAll = res.content
    for (var i = 0; i < contentAll.length; i++) { 
      ctx.commit("initInsertMessage", contentAll[i]); 
    }
   
  }

调用后台接口getChatContentAll 然后获取未拉取的离线消息然后进行存储。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/462842.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决Linux中Eclipse启动时找不到Java环境的问题

按照报错的意思是没有在/usr/local/eclipse/jre/bin/java下找到java环境&#xff0c;我检查了一下eclipse的目录结构发现在/usr/local/eclipse没有jre/bin/java&#xff0c;我的想法是自己建对应文件夹然后软连接到我的java环境 cd /usr/local/eclipse sudo mkdir jre cd jre s…

基于Struts开发物流配送(快递)管理系统

开发工具&#xff1a;EclipseJdkTomcatMySQL数据库

使用Lua编写Wireshark解析ProtoBuf插件

文章目录 Wireshark Protobuf Lua-dissectorStep 1: 获取 WiresharkStep 2: 配置ProtoBuf相关设置添加ProtoBuf查找路径 Step 3 运行和调试Lua代码1. 添加Lua脚本2. 运行和调试 Step 4: 写Lua Dissector代码 :)Step 5(Optional): Decode AsGithub工程地址 Wireshark Protobuf L…

最新潮乎盲盒系统源码,附搭建教程

搭建方法 宝塔创建网站&#xff0c;上传后端程序到根目录&#xff0c;在.env修改数据库账号密码 上传数据库&#xff0c;伪静态thinkphp 运行目录public PHP扩展安装下面的 禁用函数先禁用下面那个&#xff0c;就可以了 前端是uniapp 后台admin 禁用函数putenv、 扩展fileinfo…

python问题:vscode切换环境,pip安装库网络错误

python问题&#xff1a;vscode切换环境&#xff0c;pip安装库网络错误 vscode切换环境pip安装库网络错误 记录一下遇见的python问题。 vscode切换环境 在vscode上面的搜索框输入 > select interpreter然后选择需要的环境。 pip安装库网络错误 用requirements.txt来安装…

【目标检测】原始的 YOLOv1 网络结构(GoogLeNet 作为 backbone 的实现)

现在看网上的很多 YOLOv1 的代码实现&#xff0c;基本都是使用新的 backbone&#xff0c;例如 ResNet 或者 VGG 来实现的&#xff0c;因为这些后面的通用的 backbone 可能比较方便的获得预训练模型&#xff0c;不需要从头开始训练。 但是我就是想看一下&#xff0c;一开始 YOL…

IntelliJ IDEA 面试题及答案整理,最新面试题

IntelliJ IDEA中的插件系统如何工作&#xff1f; IntelliJ IDEA的插件系统工作原理如下&#xff1a; 1、插件架构&#xff1a; IntelliJ IDEA通过插件架构扩展其功能&#xff0c;插件可以添加新的功能或修改现有功能。 2、安装和管理&#xff1a; 通过IDEA内置的插件市场下载…

游戏服务端配置“热更”及“秒启动”终极方案(golang/ygluu/卢益贵)

游戏服务端配置“热更”及“秒启动”终极方案&#xff08;golang/ygluu/卢益贵&#xff09; 关键词&#xff1a;游戏微服务架构、游戏服务端热更、模块化解耦、golang 一、前言 众所周知&#xff0c;游戏服务端配置信息热更有几大问题&#xff08;非lua架构&#xff09;&…

电脑那个部件坏了或者是哪个软件需要修复来看价钱

电脑维修价格表是多少&#xff1f; 价格取决于计算机的哪个部分损坏或哪个软件需要修复。 由于电脑中的部件非常多&#xff0c;而且会以各种奇怪的方式出现问题&#xff0c;下面我们就来看看具体的充电方法。 电脑维修价格表&#xff1a; 1. 重新安装系统。 安装XP系统通常需…

Tomcat Session 集群 ---------会话保持

一、 负载均衡、反向代理 环境搭建&#xff1a; nginx服务器192.168.246.7 tomcat 1服务器192.168.246.8 tomcat 2服务器192.168.246.9 7-1 nginx服务器搭建 [rootzzcentos1 ~]#systemctl stop firewalld [rootzzcentos1 ~]#setenforce 0 [rootzzcentos1 ~]#yum install …

Visual Studio配置libtorch(cuda安装一步到位)

Visual Studio配置libtorch visual Studio安装cuDNN安装CUDAToolkit安装libtorch下载Visual Studio配置libtorch(cuda版本配置) visual Studio安装 visual Studio点击安装 具体的安装和配置过程这里就不进行细讲了&#xff0c;可以参考我这篇博客Visual Studio配置OpenCV(保姆…

openCV实现拖拽虚拟方块

一、项目效果&#xff1a; 二、核心流程&#xff1a; openCV读取视频流、在每一帧图片上画一个矩形。使用mediapipe获取手指关键点坐标。根据手指坐标位置和矩形的坐标位置&#xff0c;判断手指点是否在矩形上&#xff0c;如果在则矩形跟随手指移动。 三、代码流程&#xff1…

基于SpringBoot框架实现的B2B平台的医疗病历交互系统

采用技术 基于SpringBoot框架实现的B2B平台的医疗病历交互系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 管理员角色 医院管理 医院注册 医院文…

C语言—打印如图矩阵

输出矩阵 在一个二维数组中形成并输出如下矩阵: #include <stdio.h> main() { int i,j,a[5][5];for(i0;i<4;i)for(j0;j<4;j)if(i<j) a[i][j]1;else a[i][j]i-j1;for(i0;i<4;i){ for(j0;j<4;j)printf("%d ",a[i][j]);printf("…

介绍一款鼠标无边界软件

"Mouse without Borders" 是一款由微软开发的免费工具&#xff0c;旨在帮助用户在多台计算机之间实现无缝的鼠标和键盘共享。通过 Mouse without Borders&#xff0c;用户可以在一个主控制台上控制多台计算机&#xff0c;就像操作一个大型虚拟桌面一样。 这个工具可…

zookeeper基础学习之六: zookeeper java客户端curator

简介 Curator是Netflix公司开源的一套zookeeper客户端框架&#xff0c;解决了很多Zookeeper客户端非常底层的细节开发工作&#xff0c;包括连接重连、反复注册Watcher和NodeExistsException异常等等。Patrixck Hunt&#xff08;Zookeeper&#xff09;以一句“Guava is to Java…

数字IC实践项目(9)—SNN加速器的设计和实现(tiny_ODIN)

数字IC实践项目&#xff08;9&#xff09;—基于Verilog的SNN加速器 写在前面的话项目整体框图完整电路框图 项目简介和学习目的软件环境要求 Wave&CoverageTiming&#xff0c;Area & Power总结 写在前面的话 项目介绍&#xff1a; SNN硬件加速器是一种专为脉冲神经网…

nanodet笔记

nanodet简单笔记 这里简单记录下nanodet的结构. 网络stride8,16,32的feature 经过共享卷积处理后cat在一起再transpose,直接产生shape为(B, n_grid, n_class8*4),其中B为batchsize, n_grid为feature map上点的个数, 4:表示top,bottom, left, right 4个值,每个值使用8个bin的概…

QT C++ QButtonGroup应用

//QT 中&#xff0c;按钮数量比较少&#xff0c;可以分别用各按钮的信号和槽处理。 //当按钮数量较多时&#xff0c;用QButtonGroup可以实现共用一个槽函数&#xff0c;批量处理&#xff0c;减少垃圾代码&#xff0c; //减少出错。 //开发平台&#xff1a;win10QT6.2.4 MSVC…

《计算机视觉中的深度学习》之目标检测算法原理

参考&#xff1a;《计算机视觉中的深度学习》 概述 目标检测的挑战&#xff1a; 减少目标定位的准确度减少背景干扰提高目标定位的准确度 目标检测系统常用评价指标&#xff1a;检测速度和精度 提高精度&#xff1a;有效排除背景&#xff0c;光照和噪声的影响 提高检测速度…