SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

这篇具有很好参考价值的文章主要介绍了SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

ok,那么今天的话也是带来这个非常常用的一个技术,那就是咱们完成nutty的一个应用,今天的话,我会介绍地很详细,这样的话,拿到这个博文的代码就基本上可以按照自己的想法去构建自己的一个在线应用了。比如聊天,在线消息推送之类的。其实一开始我原来的想法做在线消息推送是直接mq走起,但是想了想对mq的依赖太高了。而且总感觉不安全,况且还有实时在线处理的一些要求,所以的话才觉得切换nutty来做。我的构想是这样的:

SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统
在我的构想里面的话,基本上除了和客户端建立的连接之外,会暴露出我们的一个服务器地址和接口。
其他的业务服务,都是通过其他的服务进行调用后返回的,客户端和nutty服务器只是建立长连接,负责接收消息,确认消息。具体的业务消息是如何发送的都是通过其他微服务的,好处就是确保安全,例如限制用户的聊天评率(因为可能是恶意脚本)。

不过的话,我们今天的部分是在这里:
SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统
就是紫色框起来的地方。这部分是基础,也是毛坯房,后面你们可以根据本文去造自己的房子。

后端

首先是我们的服务后端的搭建,这部分的话其实可以参考我的这篇文章:实用水文篇–SpringBoot整合Netty实现消息推送服务器

那么我们这边只是说说不同的地方,核心的主要的地方。

项目结构

SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

这里的话,可以看到我们的这边的话其实是和先前的一样的,其实没什么变化,区别在里面:
SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

这里面我重写了一下方法,对上次的一些内容进行了修改,因为上次是毛坯中的毛坯嘛。

初始化器

首先是我们的初始化器,那么在这里的话,我增加了这个心跳在线的一个处理。主要是因为,实际上,就是说,避免我们的一个资源的浪费嘛。

public class ServerHandler extends ChannelInitializer<SocketChannel> {

    /**
     * 初始化通道以及配置对应管道的处理器
     * @param channel
     * @throws Exception
     */
    @Override
    protected void initChannel(SocketChannel channel) throws Exception{
   
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(new HttpServerCodec());
        
        pipeline.addLast(new ChunkedWriteHandler());
        pipeline.addLast(new HttpObjectAggregator(1024*64));

        //===========================增加心跳支持==============================

        /**
         * 针对客户端,如果在1分钟时间内没有向服务端发送读写心跳(ALL),则主动断开连接
         * 如果有读空闲和写空闲,则不做任何处理
         */
        pipeline.addLast(new IdleStateHandler(8,10,12));
        //自定义的空闲状态检测的handler
        pipeline.addLast(new HeartBeatHandler());

      
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        //自定义的handler
        pipeline.addLast(new ServerListenerHandler());


    }
}

对应的心跳检测的实现类在这里:

public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent)evt;//强制类型转化
            if(event.state()== IdleState.READER_IDLE){
                System.out.println("进入读空闲......");
            }else if(event.state() == IdleState.WRITER_IDLE) {
                System.out.println("进入写空闲......");
            }else if(event.state()== IdleState.ALL_IDLE){
                System.out.println("channel 关闭之前:users 的数量为:"+ UserConnectPool.getChannelGroup().size());
                Channel channel = ctx.channel();
                //资源释放
                channel.close();
                System.out.println("channel 关闭之后:users 的数量为:"+UserConnectPool.getChannelGroup().size());
            }
        }
    }


}

服务类

之后的话就是我们具体的消息推送,服务之类的了。

public class ServerListenerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger log = LoggerFactory.getLogger(ServerBoot.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        //获取客户端所传输的消息
        String content = msg.text();
        //1.获取客户端发来的消息
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        assert dataContent != null;
        System.out.println("----->"+dataContent);
        Integer action = dataContent.getAction();
        Channel channel =  ctx.channel();

        //2.判断消息类型,根据不同的类型来处理不同的业务
        if(Objects.equals(action, MessageActionEnum.CONNECT.type)){
            //2.1 当websocket 第一次open的时候,初始化channel,把用的channel 和 userid 关联起来
            String senderId = dataContent.getChatMsg().getSenderId();
            UserConnectPool.getChannelMap().put(senderId,channel);
            //这里是输出一个用户关系
            UserConnectPool.output();
        } 

        } else if(Objects.equals(action, MessageActionEnum.KEEPALIVE.type)){
            //2.4 心跳类型的消息
            System.out.println("收到来自channel 为["+channel+"]的心跳包");
        }

    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //接收到请求
        log.info("有新的客户端链接:[{}]", ctx.channel().id().asLongText());
        UserConnectPool.getChannelGroup().add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        String chanelId = ctx.channel().id().asShortText();
        log.info("客户端被移除:channel id 为:"+chanelId);
        UserConnectPool.getChannelGroup().remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        //发生了异常后关闭连接,同时从channelgroup移除
        ctx.channel().close();
        UserConnectPool.getChannelGroup().remove(ctx.channel());
    }
}

可以看到这里只保留了两个玩意,一个是把用户注册到咱们的这个nutty服务器的内存里面。还有一个是心跳包。

那么其他的数据类型什么的,都在整合nutty的那篇博文里面。

那么我们的聊天怎么处理,很简单,在Controller接受到消息,然后在那里面调用Channel完成消息的转发。

具体的案例也在那篇nutty的整合里面。

前端

那么之后的话,是我们的一个前端 。

封装websocket

这边的话对这个websocket做了一个封装,可以在vue、uniapp当中使用。我这边还用到了element-ui主要是来做消息提醒的,你可以选择删掉。

SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统


// 导出socket对象
export {
  socket
}
import { Message } from 'element-ui'
// socket主要对象
var socket = {
  websock: null,
  /**
   * 这个是我们的ws的地址
   * */
  ws_url: "ws://localhost:9000/ws",
  /**
   * 开启标识
   * */
  socket_open: false,
  /**
   * 心跳timer
   * */
  hearbeat_timer: null,
  /**
   * 心跳发送频率
   * */
  hearbeat_interval: 5000,
  /**
   * 是否开启重连
   * */
  is_reonnect: true,
  /**
   * 重新连接的次数
   * */
  reconnect_count: 3,
  /**
   * 当前重新连接的次数,默认为:1
   * */
  reconnect_current: 1,
  /**
   * 重新连接的时间类型
   * */
  reconnect_timer: null,
  /**
   * 重新连接的间隔
   * */
  reconnect_interval: 3000,

  /**
   * 初始化连接
   */
  init: () => {
    if (!("WebSocket" in window)) {
      Message({
        message: '当前浏览器与网站不兼容丫',
        type: 'error',
      });
      console.log('浏览器不支持WebSocket')
      return null
    }

    // 已经创建过连接不再重复创建
    if (socket.websock) {
      return socket.websock
    }

    socket.websock = new WebSocket(socket.ws_url)
    socket.websock.onmessage = function (e) {
      socket.receive(e)
    }

    // 关闭连接
    socket.websock.onclose = function (e) {
      console.log('连接已断开')
      console.log('connection closed (' + e.code + ')')
      clearInterval(socket.hearbeat_interval)
      socket.socket_open = false

      // 需要重新连接
      if (socket.is_reonnect) {
        socket.reconnect_timer = setTimeout(() => {
          // 超过重连次数
          if (socket.reconnect_current > socket.reconnect_count) {
            clearTimeout(socket.reconnect_timer)
            return
          }

          // 记录重连次数
          socket.reconnect_current++
          socket.reconnect()
        }, socket.reconnect_interval)
      }
    }

    // 连接成功
    socket.websock.onopen = function () {
      Message({
        message: '连接成功,欢迎来到WhiteHole',
        type: 'success',
      });
      console.log('连接成功')
      socket.socket_open = true
      socket.is_reonnect = true
      // 开启心跳
      socket.heartbeat()
    }
    // 连接发生错误
    socket.websock.onerror = function (err) {
      Message({
        message: '服务连接发送错误!',
        type: 'error',
      });
      console.log('WebSocket连接发生错误')
    }
  },
  /**
   * 获取websocket对象
   * */

  getSocket:()=>{
    //创建了直接返回,反之重来
    if (socket.websock) {
      return socket.websock
    }else {
      socket.init();
    }
  },

  getStatus:()=> {
    if (socket.websock.readyState === 0) {
      return "未连接";
    } else if (socket.websock.readyState === 1) {
      return "已连接";
    } else if (socket.websock.readyState === 2) {
      return "连接正在关闭";
    } else if (socket.websock.readyState === 3) {
      return "连接已关闭";
    }
  },

  /**
   * 发送消息
   * @param {*} data 发送数据
   * @param {*} callback 发送后的自定义回调函数
   */
  send: (data, callback = null) => {
    // 开启状态直接发送
    if (socket.websock.readyState === socket.websock.OPEN) {
      socket.websock.send(JSON.stringify(data))

      if (callback) {
        callback()
      }

      // 正在开启状态,则等待1s后重新调用
    } else if (socket.websock.readyState === socket.websock.CONNECTING) {
      setTimeout(function () {
        socket.send(data, callback)
      }, 1000)

      // 未开启,则等待1s后重新调用
    } else {
      socket.init()
      setTimeout(function () {
        socket.send(data, callback)
      }, 1000)
    }
  },

  /**
   * 接收消息
   * @param {*} message 接收到的消息
   */
  receive: (message) => {
    var recData = JSON.parse(message.data)
    /**
     *这部分是我们具体的对消息的处理
     * */
    // 自行扩展其他业务处理...
  },

  /**
   * 心跳
   */
  heartbeat: () => {
    console.log('socket', 'ping')
    if (socket.hearbeat_timer) {
      clearInterval(socket.hearbeat_timer)
    }

    socket.hearbeat_timer = setInterval(() => {
      //发送心跳包
      let data = {
        "action": 4,
        "chatMsg": null,
        "extend": null,
      }
      socket.send(data)
    }, socket.hearbeat_interval)
  },

  /**
   * 主动关闭连接
   */
  close: () => {
    console.log('主动断开连接')
    clearInterval(socket.hearbeat_interval)
    socket.is_reonnect = false
    socket.websock.close()
  },

  /**
   * 重新连接
   */
  reconnect: () => {
    console.log('发起重新连接', socket.reconnect_current)

    if (socket.websock && socket.socket_open) {
      socket.websock.close()
    }

    socket.init()
  },
}


使用

这个使用其实很简单,我们这边的话是Vue所以在开启的时候就用上了,在我们的这个App.vue或者是其他的主页面里面,我这边是home作为主页面(App.vue直接展示了home.vue(这个是你自己编写的))

SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

效果

刚刚的连接效果看到了,那么就来看到这个,我们后端的一个心跳:
SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统

可以看到以前正常。
之后的话,拿着这套毛坯房就可以happy了。文章来源地址https://www.toymoban.com/news/detail-437847.html

到了这里,关于SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 在线聊天室(Vue+Springboot+WebSocket)

    实现了一个简单的在线聊天室的前后端。前端用Vue实现,后端用Springboot实现。         在线聊天室的功能包括创建用户和显示在线用户列表、发送消息和显示消息列表、用户和消息列表实时更新这几点。以下是整体功能的活动图: 用户身份         进入聊天室的用户需

    2024年01月15日
    浏览(51)
  • 基于SpringBoot+Vue+WebSocket的在线聊天室

    WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它提供了一种持久连接,允许客户端和服务器之间进行实时数据传输,而无需进行频繁的请求和响应。 相对于传统的 HTTP 请求-响应模式,WebSocket 在客户端和服务器之间建立起一条长久的双向通信通道。这意味着服务器可

    2024年01月16日
    浏览(71)
  • SpringBoot集成WebSocket实现在线聊天

    在项目过程中涉及到了在线聊天的业务,刚好有了解到WebSocket可以实现这一功能,因此便对其进行了一定的研究并做下笔记,在本文中主要借鉴了以下资源: WebSocket_百度百科 李士伟的小程序聊天工程 Springboot+Websocket中@Autowired注入service为null的解决方法 WebSocket是 HTML5规范 中

    2024年02月04日
    浏览(40)
  • vue和node使用websocket实现数据推送,实时聊天

    需求:node做后端根据websocket,连接数据库,数据库的字段改变后,前端不用刷新页面也能更新到数据,前端也可以发送消息给后端,后端接受后把前端消息做处理再推送给前端展示 使用node ./app.js运行项目 在需要使用websocket连接的页面引入 默认如下: id为243 在数据库改为

    2024年02月15日
    浏览(51)
  • Springboot集成websocket实现消息推送和在线用户统计

    在启动类上添加一个bean 核心代码 实现消息推送只要在业务代码中调用sendMessageSpecial()方法即可。 然后调用刚才的业务接口测试:http://localhost:8080/websocket/t1 调用成功后可以看到三个窗口中都收到了消息

    2023年04月08日
    浏览(55)
  • SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存

    引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/details/92410518 在此基础上实现对聊天记录的保存。 代码地址:链接:https://pan.baidu.com/s/1IJFZDa4S_DF08773sKJWeA 提取码:jkui 思路:新建一个实体类用于保存聊天记录,在消息发送时,设置对象的各个值然后保存到数据库中。

    2024年02月02日
    浏览(57)
  • 基于 SpringBoot+WebSocket 无DB实现在线聊天室(附源码)

    0.1 样例展示 0.2 源码地址 GitHub:https://github.com/ShiJieCloud/web-chat Gitee:https://gitee.com/suitbaby/web-chat GitCode:I’m Jie / web-chat · GitCode 1.1 HTTP 常用的 HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出

    2024年02月05日
    浏览(49)
  • SpringBoot+Vue 整合websocket实现简单聊天窗口

    1 输入临时名字充当账号使用 2 进入聊天窗口 3 发送消息 (复制一个页面,输入其他名字,方便展示效果) 4 其他窗口效果 pom依赖 WebSocketConfig.java WebSocketServer.java MessageVo.java App.vue

    2024年02月09日
    浏览(46)
  • SpringBoot+WebSocket+VUE实现一个简单的聊天机器人

    要实现一个简单的聊天机器人,可以使用Spring Boot框架作为后端,使用WebSocket协议实现实时通信,使用VUE作为前端实现聊天界面。 引入jar包 在Spring Boot的配置类中添加WebSocket配置 这里的WebSocketHandler是自定义的WebSocket处理器,用于处理WebSocket消息。 做了一个简单的拦截器,实

    2023年04月19日
    浏览(44)
  • SpringBoot和Vue2集成WebSocket,实现聊天室功能

    springboot集成websocket实现聊天室的功能。如有不足之处,还望大家斧正。

    2024年01月23日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包