首页 > 其他分享 >Websocket整合实现聊天操作

Websocket整合实现聊天操作

时间:2024-11-01 22:46:58浏览次数:5  
标签:Websocket ws 聊天 整合 sid websocket message public const

在实际开发中,尤其是web开发,我该如何做才可以实现消息或者数据的实时更新呢。

这里我为大家介绍,websocket长连接,它可以简历连接,且创建一个通道,通道中的数据可以实时更新。

废话不多说,接下来我将使用vue+springboot基于websocket来实现一个简单的聊天实现。

vue前端代码,这里主要的功能就是连接后端websocket服务器,然后发送消息。

​
<script setup>
import { reactive, ref, onMounted, onBeforeUnmount } from 'vue';

const messageCe = ref('');
const receivedMessages = ref([]);
const HEART_CHECK_TIME = 30000;
const data = reactive({
    readyLine: 0,
    onLine: 0,
    outLine: 0,
    errLine: 0,
});

const userId = 1;
const wsuri = `ws://localhost:8080/websocket/${userId}`;
let ws = new WebSocket(wsuri);

const heartCheck = createHeartCheck(ws, { userId });

onMounted(() => {
    ws.onopen = () => {
        ws.send(JSON.stringify({ test: "12345连接无误", toUserId: userId }));
    };

    ws.onerror = () => {
        reconnect();
    };

    ws.onmessage = (event) => {
        handleMessage(event.data);
        heartCheck();
    };

    ws.onclose = () => {
        console.log("已经关闭连接");
    };
});

onBeforeUnmount(() => {
    ws.close();
});

const sendMessage = () => {
    if (messageCe.value.trim() === '') return; // 防止发送空消息
    const data_mm = JSON.stringify({ message: messageCe.value }); // 将输入消息序列化
    ws.send(data_mm);
    messageCe.value = ''; // 清空输入框
};

function handleMessage(data) {
    try {
        const obj = JSON.parse(data);
        if (obj.message) {
            // 记录所有接收到的消息
            receivedMessages.value.push(`${obj.username || '匿名'}: ${obj.message}`);
        }
    } catch (e) {
        console.error('JSON字符串格式错误:', e);
    }
}

function reconnect() {
    console.log("尝试重新连接...");
    setTimeout(() => {
        ws = new WebSocket(wsuri);
    }, 3000);
}

function createHeartCheck(ws, { userId }) {
    let timer = null;
    let timeoutTimer = null;

    return () => {
        clearTimeout(timer);
        clearTimeout(timeoutTimer);
        timer = setTimeout(() => {
            const message = JSON.stringify({ checkHeart: 'ping', toUserId: userId });
            ws.send(message);
            console.log(`【发送消息】 ${message}`);
            timeoutTimer = setTimeout(() => {
                ws.close(); // 超时关闭连接
            }, HEART_CHECK_TIME);
        }, HEART_CHECK_TIME);
    };
}
</script>

<template>
    <div class="chat-container">
        <div class="messages" v-for="(msg, index) in receivedMessages" :key="index">
            {{ msg }}
        </div>
        <div class="input-container">
            <input type="text" v-model="messageCe" @keyup.enter="sendMessage" placeholder="输入消息..." />
            <button @click="sendMessage">发送</button>
        </div>
    </div>
</template>

<style scoped>
.chat-container {
    display: flex;
    flex-direction: column;
    height: 400px;
    width: 300px;
    border: 1px solid #ccc;
    border-radius: 8px;
    overflow: hidden;
    background-color: #f9f9f9;
    margin: 20px auto;
}

.messages {
    flex: 1;
    padding: 10px;
    overflow-y: auto; /* 允许垂直滚动 */
    border-bottom: 1px solid #ddd;
}

.input-container {
    display: flex;
    padding: 10px;
    background-color: #fff;
}

input {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
    margin-right: 10px;
}

button {
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    background-color: #007bff;
    color: white;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}
</style>

​

spring boot代码

pom.xml依赖

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

项目结构

config配置代码

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

​

 testController代码

@RestController
@RequestMapping("/test")
@Api(tags = { "测试" })
public class TestController {
 
    //推送数据接口
    @PostMapping("/socket/push/{sid}")
    public Map pushToWeb(@PathVariable String sid, String message) {
        Map<String,Object> result = new HashMap<>();
        try {
            WebSocketServer.sendInfo(message, sid);
            result.put("code", sid);
            result.put("msg", message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
    
}

server也就是websocket的代码,这里是整个项目的核心,这里有相关路径,而且提供每个生命节点的相关解决方法。

package my.websocket.service;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.ArrayList;

import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
@Service
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServer {
    private static int onlineCount = 0;
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    // 用于存储历史消息
    private static List<String> historyMessages = new ArrayList<>();

    private Session session;
    private String sid = "";

    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);
        this.sid = sid;
        addOnlineCount();

        try {
            // 发送连接成功消息
            sendMessage("conn_success");

            // 发送历史消息
            for (String message : historyMessages) {
                sendMessage(message);
            }

            log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount());
        } catch (IOException e) {
            log.error("websocket IO Exception");
        }
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        subOnlineCount();
        log.info("释放的sid为:" + sid);
        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自窗口" + sid + "的信息:" + message);

        // 存储历史消息
        historyMessages.add(message);

        // 群发消息
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @OnError
    public void one rror(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        log.info("推送消息到窗口" + sid + ",推送内容:" + message);
        for (WebSocketServer item : webSocketSet) {
            try {
                if (sid == null || item.sid.equals(sid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}

接下来就是启动前后端的项目了。

然后前端界面长这样

这里可以看到我们连接到了后台 

接下来我们就聊聊这里我们做了啥,我们现在是实现前端界面发送消息之后,其他界面可以接收到,并且在我们发送消息后,再打开一个新页面,它可以同步历史消息

 

 

这里可以发现,俩个连接都可以实现互相发送消息,且历史数据也会被读出,

并且后台也会接收到消息 

这里都是窗口1发的消息的原因是,他们连接的都是同一个窗口,因为我这里只是初步演示,所以在前端就没有多做处理,实际开发中都是以为这个为基本进行开发的,而且细心的人应该也能发现,我在vue代码中绑定了一个死数据id,所以会全是一个窗口。

接下来我们再模拟一下通过后台发送消息,这里我们使用apifox这个软件来实现发送消息。

这里我之前前端代码没有实现,所以我修改了一个函数,代码如下

​
function handleMessage(data) {
    try {
        console.log(data);
        const obj = JSON.parse(data);
        if (obj.message) {
            // 记录所有接收到的消息
            receivedMessages.value.push(`${obj.username || '匿名'}: ${obj.message}`);
        }
    } catch (e) {
        console.error('JSON字符串格式错误:', e);
        receivedMessages.value.push(`系统消息: ${data}`);
    }
}

​

 先编写后台api对应的参数

然后发送数据,这里可以看到我们前端接收到了后台发送过来的数据,支持,spring boot整合websocket结束

 

如有相关疑问,欢迎加入q裙463727795一起探讨编程问题!!! 

标签:Websocket,ws,聊天,整合,sid,websocket,message,public,const
From: https://blog.csdn.net/zhdbshiai/article/details/143322958

相关文章

  • WebSocket详解:从前端到后端的全栈理解
    文章目录前言一、WebSocket简介1.1WebSocket的特点二、WebSocket的工作原理2.1握手过程2.2数据传输三、WebSocket在前端的应用四、WebSocket在后端的应用五、WebSocket的局限与解决方案结语前言随着互联网技术的发展,传统的HTTP协议在某些场景下的局限性逐渐显......
  • 如何使用WebSockets在网页应用中实现实时通信
    摘要:实现网页应用中的实时通信,1、选择合适的WebSockets库以简化实施过程;2、在服务器端与客户端建立WebSocket连接;3、设计有效的消息协议;4、确保通信安全性;5、处理网络问题和重连机制。其中选择合适的WebSockets库是基础。它能够帮助开发者快速构建实时通信功能,如Socket.IO、Web......
  • 最新AI绘画ComfyUI整合包又更新了!
    「无套路!文末提供免费下载」文末领取最新整合包+1000张Comfyui工作流本次整合包分为3个版本:更新至20240826(后续每次推文都会有更新)‍本次文件包1.6TB左右,请权衡下载!这份完整版的SD整合包已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取......
  • 历史性突破:独立开发 .net core 在线客服系统累计处理聊天消息 48 万余条!
    业余时间用.netcore写了一个在线客服系统。我把这款业余时间写的小系统丢在网上,陆续有人找我要私有化版本,我都给了,毕竟软件业的初衷就是免费和分享。后来我索性就发了一个100%私有化版直接给大家下载,方便大家自己部署。同时,为了方便暂时不想自己私有化部署的朋友使用,我免费搭......
  • A股\美股\港股 WebSocket实时行情接口接入
    Websocket行情接入请按照下面的步骤完成沪深、港股或美股的行情接入。原文地址:https://jvquant.com/wiki.html#websocket-分配服务器为实现更好的用户体验,系统将自动为您分配合适的服务器。注意:每次分配的服务器地址会发生变化,连接服务前,请务必调用该接口获取最新的服务器地......
  • 记录springboot 3.3.5 版本整合 swagger +spring security + jwt
    springboot版本security版本wagger版本jwt版本redis版本pom文件如下引入redis是为了存储token<version>3.3.5</version><!--security--><dependency><groupId>org.springframework.boot</groupId><arti......
  • 2024最新多客游戏陪玩,语音聊天系统源码,IM聊天服务使用说明,欢迎学习下载!
    多客陪玩系统-游戏陪玩系统,线下家政,游戏代练系统,开黑陪玩系统:陪玩系统源码,高质量的陪玩系统源码,游戏陪玩APP源码开发,语音陪玩源码搭建多客陪玩系统,游戏开黑陪玩,线下搭子,开黑陪玩系统 系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发。系统支持微信......
  • 使用FastAPI整合Gradio和Django
    大家好,我是每天分享AI应用的萤火君!经常接触机器学习的同学可能都接触过Gradio这个框架,Gradio是一个基于Python的专门为机器学习项目创建的快速开发框架,可以让开发者快速发布自己的模型给用户测试,目前Huggingface上的机器学习项目都是基于Gradio对外提供服务的。不过Gradio的目......
  • 一个整合性、功能丰富的.NET网络通信框架
    前言最近有不少同学问:.NET网络通信框架有什么好推荐的吗?今天大姚给大家分享一款基于ApacheLicense开源的一个整合性、功能丰富的.NET(包括C#、VB.Net、F#)网络通信框架:TouchSocket。特色功能一键解决TCP黏分包问题,提供协议模板,支持快速实现固定包头、固定长度、区间字符......
  • springboot 整合 activiti 搭配 vue3 element-plus activiti-modeler bpmn-js
    springboot整合activiti搭配vue3element-plusactiviti-modelerbpmn-js配合使用ElementPlus+Vue3(idea开发,需要安装lombok插件)相关依赖版本后台:依赖版本spring-boot2.7.18knife4j-spring-boot-starter3.0.3pagehelper-spring-boot-starter1.3.0......