SpringBoot整合websocket实现即时通信聊天

目录
  • 一、技术介绍
    • 1.1 客户端WebSocket
      • 1.1.1 函数
      • 1.1.2 事件
    • 1.2 服务端WebSocket
  • 二、实战
    • 2.1、服务端
      • 2.1.1引入maven依赖
      • 2.1.2 编写配置类
      • 2.1.3 编写WebSocketService服务类
      • 2.1.4 建立连接
      • 2.1.5 关闭连接
      • 2.1.6 发送消息
      • 2.1.7 监听错误
    • 2.2 客户端
      • 2.2.1 主页面
      • 2.2.1 聊天页面
  • 三、开源地址
  • 四、参考文献

一、技术介绍

线上演示地址:http://chat.breez.work

实时通信(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息文件语音视频交流。[4]

场景再现:

  • 微信聊天
  • QQ聊天
  • 网站在线客服

1.1 客户端WebSocket

WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送接收数据的 API。使用 WebSocket() 构造函数来构造一个 WebSocket。[1]

构造函数如下所示:

const webSocket = WebSocket(url[, protocols])

例子如下:

const webSocket = new WebSocket("ws://42.193.120.86:3688/ws/小明/翠花")

1.1.1 函数

1、 webSocket.send()
该函数用于向服务端发送一条消息,例子如下:

webSocket.send("Hello server!");

2、 webSocket.close()
该函数用于关闭客户端与服务端的连接,例子如下:

webSocket.close();

1.1.2 事件

1、webSocket.onopen
该事件用于监听客户端与服务端的连接状态,如果客户端与服务端连接成功则该事件触发,例子如下:

webSocket.onopen = function(event) {
  console.log("连接已经建立,可以进行通信");
};

2、webSocket.onclose
如果服务端与客户端连接断开,那么此事件出发,例子如下:

webSocket.onclose = function(event) {
  console.log("连接已经关闭");
};

3、webSocket: message event
该事件用于监听服务端向客户端发送的消息,例子如下:

webSocket.addEventListener('message', function (event) {
    console.log('来自服务端的消息:', event.data);
});

4、webSocket:error event
如果客户端与服务端发生错误时,那么此事件将会触发,例子如下:

webSocket.addEventListener('error', function (event) {
  console.log('连接出现错误', event);
});

1.2 服务端WebSocket

@ServerEndpoint用于声明一个socket服务,例子如下:

@ServerEndpoint(value = "/ws/{userId}/{targetId}")

几个重要的方法注解:

  • @OnOpen 打开连接
  • @OnClose 监听关闭
  • @OnMessage 发送消息
  • @OnError 监听错误

二、实战

2.1、服务端

2.1.1引入maven依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.1.2 编写配置类

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2.1.3 编写WebSocketService服务类

下面的userId代表发送者的ID号,target代表发送目标ID号。

@Component
@ServerEndpoint(value = "/ws/{userId}/{target}")
public class WebSocketService {
    //用于保存连接的用户信息
    private static ConcurrentHashMap<String, Session> SESSION = new ConcurrentHashMap<>();
    //原子递增递减,用于统计在线用户数
    private static AtomicInteger count = new AtomicInteger();
    //消息队列,用于保存待发送的信息
    private Queue<String> queue = new LinkedBlockingDeque<>();

   //onOpen()
   //onClose()
   //onMessage()
   //onError()
}

2.1.4 建立连接

建立连接之前,判断用户是否已经连接,如果没有连接,那么将用户session信息保存到集合,然后计数器递增。

@OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        if (!SESSION.containsKey(userId)) {
            SESSION.put(userId, session);
            count.incrementAndGet();
        }
    }

2.1.5 关闭连接

关闭连接的时候,将用户session删除和计数器递减。

 @OnClose
    public void onClose(@PathParam("userId") String userId) {
        SESSION.remove(userId);
        count.decrementAndGet();
    }

2.1.6 发送消息

发送采用的方法是:session.getBasicRemote().sendText("你好");

	@OnMessage
    public void onMessage(String message, @PathParam("userId") String userId, @PathParam("target") String target) throws IOException {
        queue.add(message);
        Session s = SESSION.get(target);
        if (s == null) {
            Session b = SESSION.get(userId);
            b.getBasicRemote().sendText("对方不在线");
        } else {
            for (int i = 0; i < queue.size(); i++) {
                String msg = queue.poll();
                Message m = new Message();
                m.setUserId(userId);
                s.getBasicRemote().sendText(msg);
            }
        }
    }

2.1.7 监听错误

出现错误,删除用户session信息和计数器递减

@OnError
    public void onError(Throwable error, @PathParam("userId") String userId) {
        SESSION.remove(userId);
        count.decrementAndGet();
        error.printStackTrace();
    }

2.2 客户端

本案例中客户端采用Nuxt编写,相关代码如下

2.2.1 主页面

运行截图如图所示:

<template>
  <div style="padding-left: 20%;">
    <div style="padding-left: 20%;padding-top: 30px;">
      <div style="font-size: 30px;">欢迎使用喵喵号聊天</div>
    </div>
    <div style="padding-top: 20%;">
      <el-form :rules="rules" ref="formInline" :inline="true" :model="formInline" class="demo-form-inline">
        <el-form-item label="我的喵喵号" prop="userId">
          <el-input v-model="formInline.userId" placeholder="喵喵号"></el-input>
        </el-form-item>
        <el-form-item label="对方喵喵号" prop="targetId">
          <el-input v-model="formInline.targetId" placeholder="喵喵号"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit('formInline')">聊一下</el-button>
        </el-form-item>
      </el-form>
    </div>

  </div>
</template>

<script>
  export default {
    name: 'IndexPage',
    data() {
      return {

        formInline: {
          userId: '',
          targetId: ''
        },
        rules: {
          userId: [{
            required: true,
            message: '请输入你的喵喵号',
            trigger: 'blur'
          }],
          targetId: [{
            required: true,
            message: '请输入对方喵喵号',
            trigger: 'blur'
          }]
        }
      }

    },
    methods: {
      onSubmit(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            this.$router.push({
              name: 'chat',
              params: this.formInline
            })
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      }
    },
    created() {

    }
  }
</script>
<style>
  body {
    background: url('../static/img/cat.jpg');
  }
</style>

2.2.1 聊天页面

运行截图如下:
小明

翠花

<template>
  <div>
    <el-row :gutter="20" style="padding-top: 20px;">
      <div style="padding-left: 35%;">
        <div style="padding-bottom: 15px">
          <div style="float: left;padding-right: 30px;">
            我的喵喵号:<el-tag type="warning">{{user.userId}}</el-tag>
          </div>
          <div>
            对方喵喵号:<el-tag type="success">{{user.targetId}}</el-tag>
            <el-link @click="clearMsg()" :underline="false" style="padding-left: 30px;" type="danger">清空消息</el-link>
          </div>
        </div>
        <div style="border: 1px green solid;width: 400px;height: 400px;border-radius: 10px;">
          <div v-for="(m,index) in msgList" :key="index++">
            <el-row :gutter="20">
              <div v-if="m.type===1" style="padding-left: 10px;">
                <el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>
                {{m.msg}}
              </div>
              <div v-if="m.type===2" style="padding-right: 15px;float: right;">
                {{m.msg}}
                <el-avatar src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"></el-avatar>

              </div>
              <div v-if="m.type===3" style="padding-left: 15px;padding-top: 15px;">系统消息:{{m.msg}}</div>
            </el-row>
          </div>
        </div>
      </div>
    </el-row>
    <el-row :gutter="5" style="padding-top: 20px;padding-left: 35%;">
      <el-col :span="9" :xs="9" :sm="9" :md="9" :lg="9" :xl="9">
        <el-input :disabled="msg_status" v-model="msg" placeholder="消息"></el-input>
      </el-col>
      <el-col :span="2">
        <el-button @click="sendMessage()" type="primary">发送</el-button>
      </el-col>
    </el-row>
  </div>

</template>

<script>
  export default {
    name: 'ChatPage',
    data() {
      return {
        url: 'localhost:3688/ws/1001/1002',
        msg: '',
        socket: {},
        msg_status: true,
        msgList: [],
        initList: [],
        count: 0,
        user: {
          userId: '',
          targetId: ''
        }

      }
    },
    created() {
      const userId = this.$route.params.userId
      const targetId = this.$route.params.targetId
      if (userId !== undefined && targetId !== undefined) {
        this.user.userId = userId
        this.user.targetId = targetId
        this.connect()
      } else {
        this.$router.push("/")
      }

    },
    methods: {
      //创建socket客户端
      connect() {
        var that = this
        this.socket = new WebSocket("ws://42.193.120.86:3688/ws/" + this.user.userId + "/" + this.user.targetId);
        this.socket.onclose = function(event) {
          that.$message('连接关闭');
        };
        this.socket.addEventListener('error', function(event) {
          that.$message.error('出现错误');
        });
        // 监听消息
        this.socket.addEventListener('message', function(event) {
          that.msgList.push({
            type: 2,
            msg: event.data
          })
          console.log(event.data);
          console.log({
            type: 2,
            msg: event.data
          });
        });

        this.socket.onopen = function(event) {
          that.msg_status = false
          that.msgList.push({
            type: 3,
            msg: '连接成功'
          })
        };
      },
      clearMsg() {
        this.$confirm('确认清空?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {

          this.msgList = []
        })
      },
      //发送消息
      sendMessage() {
        this.socket.send(this.msg)
        this.msgList.push({
          type: 1,
          msg: this.msg
        })
        this.msg = ''
      }
    }
  }
</script>

<style>
</style>

三、开源地址

Gitee:https://gitee.com/BreezAm/websocket

演示地址:http://chat.breez.work

四、参考文献

[1]MDN:WebSocket

[2]Nuxt:https://nuxtjs.org

[3]Vue:https://cn.vuejs.org

[4]百度百科:及时通信

到此这篇关于SpringBoot整合websocket实现即时通信聊天的文章就介绍到这了,更多相关SpringBoot websocket即时通信内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot+WebSocket实现一对一聊天和公告的示例代码

    1.POM文件导入Springboot整合websocket的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>2.1.6.RELEASE</version> </dependency> 2.注册WebSocket的

  • Springboot基于websocket实现简单在线聊天功能

    添加maven依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM

  • SpringBoot+WebSocket实现多人在线聊天案例实例

    目录 1.pom.xml 2.消息实体类 3.controller 4.WebSocket的配置文件 5.前端发送消息页面 6.测试 6.1.客户端A 6.2.客户端B 1.pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.o

  • SpringBoot+WebSocket搭建简单的多人聊天系统

    前言 今天闲来无事,就来了解一下WebSocket协议.来简单了解一下吧. WebSocket是什么 首先了解一下WebSocket是什么?WebSocket是一种在单个TCP连接上进行全双工通信的协议.这是一种比较官方的说法,简单点来说就是,在一次TCP连接中,通信的双方可以相互通信.比如A和B在打电话,A说话的时候,B也可以说话来进行信息的交互,这就叫做全双工通信.对应的是单工通信,和半双工通信,单工通信就是只能由A向B通信,比如电脑和打印机.半双工通信是可以AB可以互相通信,但是同一时间只

  • SpringBoot中webSocket实现即时聊天

    即时聊天 这个使用了websocket,在springboot下使用很简单.前端是小程序,这个就比较坑,小程序即时聊天上线需要域名并且使用wss协议,就是ws+ssl更加安全.但是要上线这还不够,你必须为企业主体开发者.个人开发者即时聊天属于社交.不在服务类目内,审核会不通过!!! 功能 :我们的小程序是个二手交易小程序,即时聊天对于一个后台服务器只是单核2g的来说有点抗不住.所以在双方都在线的时候没有存储聊天消息,只是在单方不在线时存储了离线消息.而且只能发三条离线消息.仿照了csdn的聊天.

  • SpringBoot整合websocket实现即时通信聊天

    目录 一.技术介绍 1.1 客户端WebSocket 1.1.1 函数 1.1.2 事件 1.2 服务端WebSocket 二.实战 2.1.服务端 2.1.1引入maven依赖 2.1.2 编写配置类 2.1.3 编写WebSocketService服务类 2.1.4 建立连接 2.1.5 关闭连接 2.1.6 发送消息 2.1.7 监听错误 2.2 客户端 2.2.1 主页面 2.2.1 聊天页面 三.开源地址 四.参考文献 一.技术介绍 线上演示地址:http://chat.breez.w

  • 微信小程序实现即时通信聊天功能的实例代码

    项目背景:小程序中实现实时聊天功能 一.服务器域名配置 配置流程 配置参考URL:https://developers.weixin.qq.com/miniprogram/dev/api/api-network.html 二.nginx中配置反向代理加密websocket(wss) upstream websocket{ hash $remote_addr consistent; server 127.0.0.1:9090 weight=5 max_fails=3 fail_timeout=30

  • 使用springboot整合websocket实现群聊教程

    目录 先上效果图: 先来准备工作导入依赖 导入依赖后扫描启用 接收前端传回数据 其中重点就是4个注解 **@OnOpen,@OnClose,@OnMessage,@OnError** 前端页面代码 模板引擎代码如下 最后效果图如下 先上效果图: 相对来说更好看那么一点但是,实现代码都是一样的. 先来准备工作导入依赖 <!--websocket依赖--> <dependency> <groupId>org.springframework.boot</groupId&

  • SpringBoot整合WebSocket实现后端向前端发送消息的实例代码

    一.什么是 websocket 接口 使用 websocket 建立长连接,服务端和客户端可以互相通信,服务端只要有数据更新,就可以主动推给客户端. WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输.在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道.两者之

  • springboot整合websocket最基础入门使用教程详解

    项目最终的文件结构 1 添加maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <

  • springboot整合websocket实现群聊思路代码详解

    实现思路 发送者向服务器发送大家早上好.其它客户端可以收到对应消息. 项目展示 通过springboot引入websocket,实现群聊,通过在线websocket测试进行展示. 核心代码 pom引入jar <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2

  • SpringBoot整合WebSocket的客户端和服务端的实现代码

    目录 一.项目中服务端的创建 二.java充当客户端链接ws 1.ws客户端的配置 2.配置信息需要在项目启动的时候去启用和链接ws服务 3.接收服务端推送的消息进行权限过滤demo 4.ws客户端推送消息,推送消息和上面服务端类似. 本文是项目中使用了websocket进行一些数据的推送,对比项目做了一个demo,ws的相关问题不做细数,仅做一下记录. 此demo针对ws的搭建主要逻辑背景是一个服务端B:通讯层 产生消息推送出去,另外一个项目A充当客户端和服务端,A的客户端:是接收通讯层去无差

  • 通过实例讲解springboot整合WebSocket

    一.背景 我们都知道 http 协议只能浏览器单方面向服务器发起请求获得响应,服务器不能主动向浏览器推送消息.想要实现浏览器的主动推送有两种主流实现方式: 轮询:缺点很多,但是实现简单 websocket:在浏览器和服务器之间建立 tcp 连接,实现全双工通信 springboot 使用 websocket 有两种方式,一种是实现简单的 websocket,另外一种是实现STOMP协议.这一篇实现简单的 websocket,STOMP 下一篇在讲. 注意:如下都是针对使用 springboot

随机推荐