IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Spring Boot + WebSocket实现网页在线实时聊天 -> 正文阅读

[网络协议]Spring Boot + WebSocket实现网页在线实时聊天

作者:token comment

部分代码

首先创建springboot项目并引入依赖:

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

服务端核心代码

@Component
@ServerEndpoint("/chat/lobby")
public class LobbyChat {


    @OnOpen
    public void onOpen(Session session) throws IOException {
        /*
         * @description: TODO 链接建立时调用该方法
         * @params: [session]   //连接发起者的会话对象
         * @return: void
         * @author: QGQ
         * @dateTime: 2022/3/1 18:59
         */
//        Info.increaseOnlineCount();
        //从querystring中取出用户输入的用户名并解码然后和session对象一起保存到user对象中
        User user = new User(URLDecoder.decode(session.getQueryString().split("=")[1],"UTF-8"),session);
        Info.addUser(user);
        //向所有用户推送最新的在线者信息
        for (User u: Info.getUserList()) {
            send(u.getSession(),MsgHelper.generateUserInfo(Info.getUserList()));
        }
        System.out.println("一名用户上线,"+user.toString()+"当前在线人数为:"+ Info.getOnlineCount());
    }

    @OnClose
    public void onClose(Session session) throws IOException {
        /*
         * @description: TODO 某用户下线,更新在线人数和在线者列表
         * @params: [session]
         * @return: void
         * @author: QGQ
         * @dateTime: 2022/3/1 19:01
         */
        System.out.println("用户"+Info.getUser(session)+"已下线,当前在线人数:"+(Info.getOnlineCount()-1));
        Info.removeUser(session);
        //向所有用户推送最新的在线者信息
        for (User u: Info.getUserList()) {
            send(u.getSession(),MsgHelper.generateUserInfo(Info.getUserList()));
        }
    }
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("发生错误!");
        error.printStackTrace();
    }

    @OnMessage
    public void onMessage(String msg,Session session) throws IOException {
        /*
         * @description: TODO 根据收到消息的类型将收到的消息发给所有在线者或个人
         * @params: [session]
         * @return: void
         * @author: QGQ
         * @dateTime: 2022/3/1 19:51
         */
        //使用jackson的API将前端发来的封装好的消息对象转成map
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String,String> received = objectMapper.readValue(msg, new TypeReference<Map<String,String>>(){});
//        System.out.println(received);
        String msgObj = null;   //用于封装规定格式的消息对象
        User sender = Info.getUser(session);    //获取发送者对象
        if (received.get("type").equals("lobby")){
            //该type值表示这是发往大厅的消息
            System.out.println("用户"+Info.getUser(session)+"发出的消息:"+received.get("content"));

            msgObj = MsgHelper.generateUserMsg(sender.getUsername(),sender.getSession().getId(),"lobby",received.get("content"));
            for (User u: Info.getUserList()) {
                send(u.getSession(),msgObj);
            }
        }
        if (received.get("type").equals("friend")){
            //该type值表示这条消息是发给某人的
            System.out.println(received);
            msgObj = MsgHelper.generateUserMsg(sender.getUsername(),sender.getSession().getId(),"friend",received.get("content"));
//            send(Info.getUser(session).getSession(),msgObj);
            send(Info.getUser(received.get("sessionID")).getSession(),msgObj);
        }
    }


    public static void send(Session receiver,String msg) throws IOException {
        /*
         * @description: TODO 向用户发送消息
         * @params: [receiver, msg] //前者为接受者,后者为发送的内容
         * @return: void
         * @author: QGQ
         * @dateTime: 2022/3/3 20:20
         */
        receiver.getBasicRemote().sendText(msg);
    }

}

前端核心代码:

let app = Vue.createApp({
    data(){
        return {
            username:"",    //当前用户的昵称
            lobby_input:"hello", //大厅输入框的内容
            friend_input:"",   //私聊输入框的内容
            msg_records_f: [],    //私聊框消息记录,格式为{type:"message",sender:xxx,senderID:xxx,to:xxx,time:xxx,content:xxx}
            msg_records_l:[],   //大厅消息记录,格式同上
            received_msg_f: "", //私聊框收到的最新消息
            online_count: 0,    //在线人数
            onlineUsers:null,   //在线者列表
            pri_chat_obj: {username:"未开始私聊",sessionId:-1}, //当前私聊对象,格式为{username:xxx,sessionID:xxx}
            socket: null,   //websocket对象
            btnChatMovedActiveIndex: -1,   //决定CSS类.btn-chat-moved是否生效
        }
    },
    methods:{
        sendMsgToF(){
          // 向私聊对象发送消息
          if(this.pri_chat_obj.sessionId != -1){
              if(this.friend_input!=""){
                  console.log(this.msgObjF);
                  this.socket?.send(this.msgObjF);
                  let d= new Date();
                  let timeStr = d.getHours() + "时" + d.getMinutes() +"分" + d.getSeconds() + "秒";
                  this.msg_records_f.push({sender:this.username,time:timeStr,content:this.friend_input});
                  this.friend_input = "";
              }
          }else {
              alert("请先选择私聊对象");
          }
        },
        sendMsgToL(){
          //发送消息到大厅,没输入任何文字时不发送
            if (this.lobby_input !== ""){
                this.socket?.send(this.msgObjL);
                this.lobby_input = "";
            }
        },
        chatWith(user){
          //切换私聊对象为user
            if(user!==this.pri_chat_obj){
                this.pri_chat_obj = user;
                this.msg_records_f = [];
            }
        },
        getUserBySessionID(id){
          //通过sessionID获取发送者对象
            for (let i = 0; i < this.onlineUsers.length; i++) {
                if (this.onlineUsers[i].sessionId === id){
                    return this.onlineUsers[i];
                }
            }
        }
    },
    computed:{
        msgObjL(){
            //要发送给后端的大厅消息对象,格式为{type:lobby,content:xxx}
            return  JSON.stringify({type:"lobby",content:this.lobby_input});
        },
        msgObjF(){
            //要发送给后端的私聊消息对象,格式为:{type:friend,sessionID:xxx,content:xxx}
            return  JSON.stringify({type:"friend",sessionID:this.pri_chat_obj.sessionId,content:this.friend_input});
        }
    },
    watch:{
        received_msg_f(val){
            console.log(val)
        }
    },
    mounted(){
        let name = window.prompt("请输入你在本次聊天中要使用的昵称");
        while (name === ""||name == null){
            name = window.prompt("请输入一个昵称!");
        }
        this.username = name;
        let webSocket = new WebSocket("ws://127.0.0.1:8080/chat/lobby?username="+this.username);
        webSocket.onopen = function (){
            console.log("链接建立成功");
            app.$data.socket = webSocket;
            // app.$data.online_count++;
        }
        webSocket.onclose = function (){
            console.log("连接已关闭");
        }
        webSocket.onerror = function (err){
            alert("连接服务器失败!");
            console.log(err);
        }
        //收到消息时调用
        webSocket.onmessage = function (event){
            console.log(event.data)
            let msgObj = JSON.parse(event.data);    //获取后端封装的消息对象
            // app.$data.received_msg_f = msgObj.content;  //修改最新收到的消息
            console.log(msgObj)
            if(msgObj.type==="message"){
                //该type值表示这是某个用户发送的消息
                if(msgObj.to==="lobby"){
                    app.$data.msg_records_l.push(msgObj);   //将收到的消息加入消息记录
                }
                if (msgObj.to==="friend"){
                    app.$data.msg_records_f.push(msgObj);
                    app.$data.pri_chat_obj = app.getUserBySessionID(msgObj.senderID);
                }
            }
            if (msgObj.type=="info"){
                //该type值表示这是服务器推送的在线用户信息
                // console.log(msgObj);
                app.$data.online_count = msgObj.onlineCount;
                app.$data.onlineUsers = msgObj.userList;
            }
        }
        //当窗口被关闭时,先关闭ws连接
        window.onbeforeunload = function (){
            webSocket.close();
            app.$data.socket = null;
            app.$data.online_count--;
        }

    }
}).mount("#app");

完整代码可在Gitee查看.

演示

先输入要使用的昵称
在这里插入图片描述
同样方法打开三个标签页
在这里插入图片描述
在大厅大消息所有人都会收到
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
鼠标在在线者列表上悬浮会出现chat按钮,点击可开始私聊
在这里插入图片描述
向私聊对象发送消息,只有他一个人会收到,Tony收到消息
在这里插入图片描述
Thor没有收到在这里插入图片描述
Peter收到Tony的回复
在这里插入图片描述

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:59:52  更:2022-03-10 23:00:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:45:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码