IM聊天学习资源

文章目录

  • 参考链接
    • 使用
    • 前端界面
    • 简单效果
      • 消息窗口平滑滚动至底部
      • vue使用watch监听vuex中的变量变化
    • websocket握手认证
      • ChatKeyCheckHandler
      • NettyChatServer
      • NettyChatInitializer

参考链接

zzhua/netty-chat-web - 包括前后端

vue.js实现带表情评论功能前后端实现(仿B站评论)
vue.js实现带表情评论仿bilibili(滚动加载效果)

vue.js支持表情输入
vue.js表情文本输入框组件

个人说说vue组件

JS操作文本域获取光标/指定位置插入

分布式ID生成之雪花算法(SnowFlake)


netty-demo-crazy - 疯狂架构师netty

IM即时通讯系统[SpringBoot+Netty]——梳理(总), 代码 im-system 在gitee

构建IM即使通讯Web页面 - B站视频,仅前端代码,代码 chat-demo 在gitee

  • 禹神:一小时快速上手Electron,前端Electron开发教程,笔记。一篇文章入门Electron
  • Electron集成Vite + Vue 开发IM即使通讯
  • easychat - gitee代码

基于vue3实现一个简单的输入框效果
vue3通过组合键实现换行操作的示例详解

easychat - B站视频,前后端,代码在gitee

subtlechat-mini - 前后端,有mini版和完整版

lyf-im - 前后端项目

box-im - 盒子im,很棒

MallChat - 前后端项目,代码很棒

木杉/ 视频通话 netty webrtc websocket springboot uniapp

木杉/ /mushan-im

ProgHub/chat_room

yymao/chatroom - 仅前端,im界面好看

H260788/PureChat - im界面好看,前端难度大

netty-chatroom - netty实现,仅后端代码

liurq_netty_barrage - netty实现的1个简单的弹幕效果

yorick_socket一套基于Netty的轻量级Socket和WebSocket框架,可用于搭建聊天服务器和游戏同步服务器

【聊天系统】从零开始自己做一个"wechat" - uniapp 和 springboot

linyu-mini-web&linyu-mini-server gitee 前后端代码

aq-chat web端,AQChatServer,aqchat-mobile,AQChat文档中心,

考拉开源/im-uniapp,im-platform 后台代码

ws-chat - 前后端代码

yan代码,B站视频)

im-whale-shark代码,B站视频

使用

前端使用:vue.js + vuex + iconfont + element-ui
后端使用:springboot + mybatisplus + redis + netty + websocket + spring security

可能有不少问题,反正先按照自己思路一点一点写,再参考下别人是怎么搞的再优化

前端界面

先写下大概的前端界面,界面出来了,才有继续写下去的动力

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

简单效果

在这里插入图片描述

消息窗口平滑滚动至底部

<div class="panel-main-body" ref="panelMainBodyContainerRef"><!-- 对应会话 的消息列表 --><div class="msg-item-list" ref="msgItemListContainerRef"><div :class="['msg-item', familyChatMsg.senderId != currUserId ? 'other' : 'owner']"v-for="(familyChatMsg, idx) in familyChatMsgList" :key="idx"><div class="avatar-wrapper "><img :src="familyChatMsg.avatar" class="avatar fit-img" alt=""></div><div class="msg"><div class="msg-header">{{ familyChatMsg.nickName }}</div><div class="msg-content" v-html="familyChatMsg.content"></div></div></div></div></div><script>
export default {methods: {/* 滚动至底部,不过调用此方法的时机应当在familyChatMsgList更新之后, 因此需要监听它 */scrollToEnd() {const panelMainBodyContainerRef = this.$refs['panelMainBodyContainerRef']const msgItemListContainerRef = this.$refs['msgItemListContainerRef']// console.log(msgItemListContainerRef.scrollTop);// console.log(panelMainBodyContainerRef.scrollHeight);msgItemListContainerRef.scrollTop = msgItemListContainerRef.scrollHeightconsole.log('滚动至底部~');},}}
</script><style>
.msg-item-list {/* 平滑滚动 */scroll-behavior: smooth;
}
</style>

vue使用watch监听vuex中的变量变化

computed: {...mapGetters('familyChatStore', ['familyChatMsgList']),
},watch: {// 监听store中的数据 - 是通过监听getters完成的familyChatMsgList:{handler(newVal, oldVal) {// console.log('---------------------');// console.log(newVal.length, oldVal.length);this.$nextTick(()=>{this.scrollToEnd()})}}},

websocket握手认证

客户端在登录完成后,可以请求后端的接口获取1个chatKey(这个chatKey只有在用户登录后,携带token访问时才能得到),得到此chatKey后,连接websocket客户端时,把这个chatKey作为请求参数拼接到ws://xxxx.xx.xx:9091/ws?chatKey=xxx,这样在握手的时候,就可以拿到这个请求参数。但是,我不想在握手完成事件时再去拿这个chatKey(虽然这样做,也没什么问题,但感觉逻辑不是很好,都已经握手完成了,再来断掉ws连接有点不好),因此,设置1个ChatKeyCheckHandler,它继承自SimpleInboundHandlerAdapter,处理的泛型是FullHttpRequest,并且把这个处理器放在WebSocketServerProtocolHandler的前面,这样,在处理握手请求时,就可以拿到请求参数了,而握手完成之后,由于后面的消息是websocket协议帧数据,它不会FullHttpRequest类型的,因此不会经过这个处理器,这样感觉比较好~

ChatKeyCheckHandler

@Slf4j
@ChannelHandler.Sharable
@Component
public class ChatKeyCheckHandler extends SimpleChannelInboundHandler<FullHttpRequest> {public ChatKeyCheckHandler() {super(false);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {log.info("http请求-chatKeyCheckHandler处理");FullHttpRequest request = ((FullHttpRequest) msg);String uri = request.uri();log.info("请求uri: {}");log.info("请求header: {}", Arrays.toString(request.headers().names().toArray()));List<String> chatKeys = UriComponentsBuilder.fromUriString(uri).build().getQueryParams().get(Constants.CHAT_KEY);if (CollectionUtils.isEmpty(chatKeys)) {log.error("欲建立websocket连接,但未携带chatKey,直接略过");// 还得写个响应回去,并且关闭HTTP连接HttpRequest req = msg;FullHttpResponse response = new DefaultFullHttpResponse(req.protocolVersion(), OK,Unpooled.wrappedBuffer("NOT ALLOWD WITHOUT CHAT_KEY".getBytes()));response.headers().set(CONTENT_TYPE, TEXT_PLAIN).setInt(CONTENT_LENGTH, response.content().readableBytes());// Tell the client we're going to close the connection.response.headers().set(CONNECTION, CLOSE);ChannelFuture f = ctx.writeAndFlush(response);f.addListener(ChannelFutureListener.CLOSE);return;}String chatKey = chatKeys.iterator().next();ctx.channel().attr(WsContext.CHAT_KEY_ATTR).set(chatKey);log.info("建立websocket连接的握手请求, 携带了chatKey: {}", chatKey);// 在此处校验chatKey是否合理, 如果不合理, 则不允许建立websocket链接(不会进行后面的握手处理)ctx.fireChannelRead(request);}
}

NettyChatServer

@Slf4j
@Component
public class NettyChatServer implements SmartLifecycle {@Autowiredprivate NettyProperties nettyProps;@Autowiredprivate NettyChatInitializer nettyChatInitializer;private volatile boolean running = false;private ServerChannel serverChannel;private EventLoopGroup bossGroup;private EventLoopGroup workerGroup;public void start() {log.info("starting netty server~");bossGroup = new NioEventLoopGroup(1);workerGroup = new NioEventLoopGroup(2);ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(nettyChatInitializer);// 这里会异步调用ChannelFuture channelFuture = serverBootstrap.bind(nettyProps.getPort());channelFuture.addListener(future -> log.info("netty started, listening: {}", nettyProps.getPort()));// 保存对ServerSocketChannel的引用serverChannel = (NioServerSocketChannel) channelFuture.channel();channelFuture.channel().closeFuture().addListener(future -> log.info("netty stopped!"));running = true;}@Overridepublic void stop() {log.info("stop netty server");try {serverChannel.close();} catch (Exception e) {log.error("关闭ServerSocketChannel失败");}if (bossGroup != null) {bossGroup.shutdownGracefully();}if (workerGroup != null) {workerGroup.shutdownGracefully();}running = false;}@Overridepublic boolean isRunning() {return this.running;}}

NettyChatInitializer

@Component
public class NettyChatInitializer extends ChannelInitializer<SocketChannel> {@Autowiredprivate NettyProperties nettyProperties;@Autowiredprivate DispatcherMsgHandler dispatcherMsgHandler;@Autowiredprivate HandShakeHandler handShakeHandler;@Autowiredprivate ChatKeyCheckHandler chatKeyCheckHandler;@Overrideprotected void initChannel(SocketChannel ch) throws Exception {DefaultEventLoopGroup eventExecutors = new DefaultEventLoopGroup(2);ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));pipeline.addLast("http-decoder", new HttpRequestDecoder());pipeline.addLast("http-encoder", new HttpResponseEncoder());pipeline.addLast("aggregator", new HttpObjectAggregator(64 * 1024));pipeline.addLast(new ChunkedWriteHandler());WebSocketServerProtocolConfig wsServerConfig = WebSocketServerProtocolConfig.newBuilder().websocketPath(nettyProperties.getWsPath()).checkStartsWith(true).maxFramePayloadLength(Integer.MAX_VALUE).build();pipeline.addLast("chatKeyHandler", chatKeyCheckHandler);pipeline.addLast("websocketHandler", new WebSocketServerProtocolHandler(wsServerConfig));pipeline.addLast("handShakeHandler", handShakeHandler);pipeline.addLast("heartBeanCheckHandler", new HeatBeatCheckHandler());pipeline.addLast(eventExecutors, "dispatcherMsgHandler", dispatcherMsgHandler);}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

彻底理解JVM类加载机制

文章目录 一、类加载器和双亲委派机制1.1、类加载器1.2、双亲委派机制1.3、自定义类加载器1.4、打破双亲委派机制 二、类的加载 图片来源&#xff1a;图灵学院   由上图可知&#xff0c;创建对象&#xff0c;执行其中的方法&#xff0c;在java层面&#xff0c;最重要的有获取…

使用FRP进行内网穿透

一、基本概念 内网穿透&#xff1a;它是一种网络技术或方法&#xff0c;旨在允许外部网络&#xff08;如互联网&#xff09;访问位于内部网络&#xff08;内网&#xff09;中的设备或服务。由于内部网络通常处于NAT&#xff08;网络地址转换&#xff09;、防火墙或其他安全机制…

Mysql常见问题处理集锦

Mysql常见问题处理集锦 root用户密码忘记&#xff0c;重置的操作(windows上的操作)MySQL报错&#xff1a;ERROR 1118 (42000): Row size too large. 或者 Row size too large (&#xff1e; 8126).场景&#xff1a;报错原因解决办法 详解行大小限制示例&#xff1a;内容来源于网…

《计算机网络》课后探研题书面报告_网际校验和算法

网际校验和算法 摘 要 本文旨在研究和实现网际校验和&#xff08;Internet Checksum&#xff09;算法。通过阅读《RFC 1071》文档理解该算法的工作原理&#xff0c;并使用编程语言实现网际校验和的计算过程。本项目将对不同类型的网络报文&#xff08;包括ICMP、TCP、UDP等&a…

Python毕业设计选题:基于django+vue的智能租房系统的设计与实现

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 租客注册 添加租客界面 租客管理 房屋类型管理 房屋信息管理 系统管理 摘要 本文首…

联发科MTK6762/MT6762安卓核心板_4G智能模块应用

MT6762安卓核心板是一款工业级高性能、可运行 android9.0 操作系统的 4G智能模块。MT6762平台打造具备 AI 体验、先进双摄像头拍摄效果且具备丰富连接功能的智能手机主板。 MT6762安卓核心板 是一款髙性能低功耗的 4G 全网通安卓智能模块。此模块支持 2G/3G/4G 移动&#xff0c…

彩色图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中&#xff0c;经常需要获取感兴趣区域的面积属性&#xff0c;下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…

重拾Python学习,先从把python删除开始。。。

自己折腾就是不行啊&#xff0c;屡战屡败&#xff0c;最近终于找到前辈教我 第一步 删除Python 先把前阵子折腾的WSL和VScode删掉。还是得用spyder&#xff0c;跟matlab最像&#xff0c;也最容易入手。 从VScode上搞python&#xff0c;最后安装到appdata上&#xff0c;安装插…

Redis系列之底层数据结构字典Dict

Redis系列之底层数据结构字典Dict Dict数据结构 Dict是Redis数据结构中使用最为频繁的复合型数据结构&#xff0c;本质上是一个哈希表 查看redis6.0版本的源码&#xff0c;链接&#xff1a;https://github.com/redis/redis/blob/6.0/src/dict.h 哈希表的结构定义&#xff1…

《贪心算法:原理剖析与典型例题精解》

必刷的贪心算法典型例题&#xff01; 算法竞赛&#xff08;蓝桥杯&#xff09;贪心算法1——数塔问题-CSDN博客 算法竞赛&#xff08;蓝桥杯&#xff09;贪心算法2——需要安排几位师傅加工零件-CSDN博客 算法&#xff08;蓝桥杯&#xff09;贪心算法3——二维数组排序与贪心算…

基于 Python 的深度学习的车俩特征分析系统,附源码

博主介绍&#xff1a;✌stormjun、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

VSCode 的部署

一、VSCode部署 (1)、简介 vsCode 全称 Visual Studio Code&#xff0c;是微软出的一款轻量级代码编辑器&#xff0c;免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比Diff、版本管理GIT等特性&…

【开源免费】基于SpringBoot+Vue.JS欢迪迈手机商城(JAVA毕业设计)

本文项目编号 T 141 &#xff0c;文末自助获取源码 \color{red}{T141&#xff0c;文末自助获取源码} T141&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

Transformer创新模型!Transformer+BO-SVR多变量回归预测,添加气泡图、散点密度图(Matlab)

Transformer创新模型&#xff01;TransformerBO-SVR多变量回归预测&#xff0c;添加气泡图、散点密度图&#xff08;Matlab&#xff09; 目录 Transformer创新模型&#xff01;TransformerBO-SVR多变量回归预测&#xff0c;添加气泡图、散点密度图&#xff08;Matlab&#xff0…

Nmap之企业漏洞扫描(Enterprise Vulnerability Scanning for Nmap)

简介 Namp是一个开源的网络连接端扫描软件&#xff0c;主要用于网络发现和安全审核。‌它可以帮助用户识别网络上的设备、分析它们的服务、检测操作系统类型&#xff0c;甚至发现潜在的安全漏洞。Nmap由Fyodor开发&#xff0c;最初是为了满足网络管理员的需求&#xff0c;但随…

windows下安装并使用node.js

一、下载Node.js 选择对应你系统的Node.js版本下载 Node.js官网下载地址 Node.js中文网下载地址??? 这里我选择的是Windows64位系统的Node.js20.18.0&#xff08;LTS长期支持版本&#xff09;版本的.msi安装包程序 官网下载&#xff1a; 中文网下载&#xff1a; 二、安…

Ability Kit-程序框架服务(类似Android Activity)

文章目录 Ability Kit&#xff08;程序框架服务&#xff09;简介Stage模型开发概述Stage模型应用组件应用/组件级配置UIAbility组件概述概述声明配置 生命周期概述生命周期状态说明Create状态WindowStageCreate**和**WindowStageDestroy状态WindowStageWillDestroy状态Foregrou…

Redis超详细入门教程(基础篇)

目录 一、什么是Redis 二、安装Redis 1、Windows系统安装 2、Linux系统安装 三、Redis通用命令 四、Redis基本命令 五、五种数据结构类型 5.1、String类型 5.2、List集合类型 5.3、Set集合类型 5.4、Hash集合类型 5.5、Zset有序集合类型 六、总结 一、什么是Redi…

黑马Java面试教程_P1_导学与准备篇

系列博客目录 文章目录 系列博客目录导学Why?举例 准备篇企业是如何筛选简历的(筛选简历的规则)HR如何筛选简历部门负责人筛选简历 简历注意事项简历整体结构个人技能该如何描述项目该如何描述 应届生该如何找到合适的练手项目项目来源找到项目后&#xff0c;如何深入学习项目…

在Linux上如何让ollama在GPU上运行模型

之前一直在 Mac 上使用 ollama 所以没注意&#xff0c;最近在 Ubuntu 上运行发现一直在 CPU 上跑。我一开始以为是超显存了&#xff0c;因为 Mac 上如果超内存的话&#xff0c;那么就只用 CPU&#xff0c;但是我发现 Llama3.2 3B 只占用 3GB&#xff0c;这远没有超。看了一下命…