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 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> WebSocket+SpringBoot+vue实现群聊和私聊 -> 正文阅读

[网络协议]WebSocket+SpringBoot+vue实现群聊和私聊

最近,因为工作的需求需要实现一个小型的客服聊天系统,在网上搜一一圈,发现搜到的都是websocket,所以自己和根据大家的帖子写了一个看看。那就开始吧!
在这里插入图片描述

1.导入依赖

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

2.编写配置类

package com.kuaidian.edu.school.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import javax.websocket.server.ServerEndpoint;


@Description("编写一个websocketconfig配置类,注入对象serverEndpointExporter," +
        "这个bean会自动注册使用@serverEndpoint注解声明的Websocket endpoint")
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

3.接收消息类

package com.kuaidian.edu.school.model;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Set;

@Data
@ApiModel(description = "websocket消息内容")
public class MsgVo {
    @ApiModelProperty(value = "用户id")
    private String  nickName;

    @ApiModelProperty(value = "消息")
    private String msg;

    @ApiModelProperty(value = "在线人数")
    private int count;

    @ApiModelProperty(value = "在线用户")
    private Set<String> onlineList;

    @ApiModelProperty(value = "发送者")
    private String fromUser;

    @ApiModelProperty(value = "发送者房间号")
    private String fromSid;

    @ApiModelProperty(value = "接受者")
    private String toUser;

    @ApiModelProperty(value = "发送者房间号")
    private String ToSid;

    @ApiModelProperty(value = "消息类型")
    private Integer messageType;


}

4.编写controller类

package com.kuaidian.edu.school.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.kuaidian.edu.school.model.MsgVo;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

@Slf4j
@Component
@ServerEndpoint("/groupChat/{sid}/{nickName}")
public class WebSocketServerController {
    public static Map<String, Map<String, Session>> groupMemberInfoMap = new HashMap<String, Map<String, Session>>();
    //房间号---》组成员信息
   // private static ConcurrentHashMap<String,Session> groupMemberInfoMap = new ConcurrentHashMap<>();
    //房间号---》在线人数
    private static ConcurrentHashMap<String, Set<String>> onlineUserMap = new ConcurrentHashMap<>();

    /**
     * 收到消息调用的方法,群成员发送消息
     * @param sid
     * @param nickName
     * @param message
     */
    @OnMessage
    public void onMessage(Session session,@PathParam("sid") String sid, @PathParam("nickName") String  nickName, String message){
        System.out.println("来自客户端消息:"+nickName+message+"客户端的ID是"+session.getId());
        System.out.println("---------------"+message);
        Set<String> onlineUserList = onlineUserMap.computeIfAbsent(sid, k -> new HashSet<>());
        MsgVo msgVo = JSONObject.parseObject(message, MsgVo.class);
        String textMessage=msgVo.getMsg();
        Integer messageType=msgVo.getMessageType();
        String toUser= msgVo.getToUser();
        msgVo.setOnlineList(onlineUserList);
        msgVo.setFromSid(sid);
        msgVo.setFromUser(nickName);
        msgVo.setCount(onlineUserList.size());
        if(messageType == 4){
            sendMessageTo(JSONObject.toJSONString(msgVo),toUser,sid);
        }else{
            sendMessageAll(JSONObject.toJSONString(msgVo),sid);
        }

    }

    /**
     * 建立连接调用的方法,群成员加入
     * @param session
     * @param sid
     * @param nickName
     */

    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid, @PathParam("nickName") String  nickName){
       //如果map中存在指定的key,那么就返回这个key对应的value值;
        //如果指定的key不存在,那么就把key和newvalue存下map,并返回null;null指指定的那个key之前是没有对应值得
        Map<String, Session> SessionMember = groupMemberInfoMap.computeIfAbsent(sid, k -> new HashMap<String, Session>());
        Set<String> onlineUserList = onlineUserMap.computeIfAbsent(sid, k -> new HashSet<>());
        onlineUserList.add(nickName);
        SessionMember.put(nickName,session);
        System.out.println("来自客户端消息:"+nickName+"客户端的ID是"+session.getId());
        MsgVo msgVo = new MsgVo();
        //messageType 1 代表上线 2 代表下线 3代表群发 4代表私发消息
        //先给所有人发送通知,说我上线了
         msgVo.setOnlineList(onlineUserList);
         msgVo.setCount(onlineUserList.size());
         msgVo.setFromSid(sid);
         msgVo.setFromUser(nickName);
         msgVo.setMessageType(1);
         msgVo.setMsg("频道号:"+sid+"用户:"+nickName+"上线了!");
        sendMessageAll(JSONObject.toJSONString(msgVo),sid);
        System.out.println("有连接!当前在线人数"+onlineUserList.size());
    }
   public void sendMessageTo(String message,String Touser,String sid){
       Map<String, Session> SessionMap = groupMemberInfoMap.get(sid);
       //Set<String> onlineUserList = onlineUserMap.get(sid);
       for (String key : SessionMap.keySet()){
           if (key.equals(Touser)) {
               try {
                   SessionMap.get(key).getBasicRemote().sendText(message);
                   break;
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           }
   }
   public void sendMessageAll(String message,String sid){
       Map<String, Session> SessionMap = groupMemberInfoMap.get(sid);
      // Set<String> onlineUserList = onlineUserMap.get(sid);
       for (String key : SessionMap.keySet()){
               try {
                   SessionMap.get(key).getBasicRemote().sendText(message);
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
   }

    /**
     * 关闭连接调用的方法,群成员退出
     * @param session
     * @param sid
     * @param nickName
     */
    @OnClose
    public void onClose(Session session,@PathParam("sid") String sid, @PathParam("nickName") String nickName){
        Map<String, Session> SessionMap = groupMemberInfoMap.get(sid);
        SessionMap.remove(nickName);
        Set<String> onlineUserList = onlineUserMap.get(sid);
        onlineUserList.remove(nickName);
        //messageType 1 代表上线 2 代表下线 3代表群发 4代表私发消息
        //先给所有人发送通知,说我上线了
        MsgVo msgVo = new MsgVo();
        msgVo.setCount(onlineUserList.size());
        msgVo.setOnlineList(onlineUserList);
        msgVo.setMessageType(2);
        msgVo.setNickName(nickName);
        msgVo.setMsg("频道号:"+sid+"用户:"+nickName+"下线了!");
        sendMessageAll(JSONObject.toJSONString(msgVo),sid);
        System.out.println("有连接关闭!当前在线人数"+onlineUserList.size());

        // 发送离线通知
    }
    /**
     * 传输消息错误调用的方法
     *
     * @param error
     */
    @OnError
    public void OnError(Throwable error) {
        log.info("Connection error");
    }


}

4.vue前端页面编写

<template>
  <section >
    <div style="display: flex; flex-direction: column">
      <span >用户:{{nickName}}</span>
      <span>在线人数:{{resData.count}}</span>
      <span>登录用户:</span>
      <span  v-for="(item, index) in onlineUsers" v-bind:key="index" @click="PrivateSendMessage(item)" style="margin-left: 40px">{{item}}</span>
    </div>
    <div>
<!--      <el-input v-model="nickName" placeholder="请输入用户名"  ></el-input>-->
<!--      <el-button @click="initWebSocket">连接</el-button>-->
      <el-input v-model="contentText" placeholder="发送的消息"  ></el-input>
      <el-button @click="sendText">发送</el-button>
      <div  v-for="(item, index) in allList" v-bind:key="index">
          <div  v-if="item.messageType === 4">
            {{item.person}}私聊:{{item.toPerson}}
            <span id="messageTo"  >
               <br/> {{item.message}}</span>
          </div>
        <span id="message" v-else>
            {{item.person}}群聊:<br/> {{item.message}}
          </span>
      </div>
    </div>
  </section>
</template>

<script>
export default {
  name: 'websocketServer',
  data () {
    return {
      ws: null,
      count: 0,
      nickName: '', // 当前用户昵称
      toUser: '',
      onlineUsers: [],
      list: [], // 聊天记录的数组
      contentText: '', // input输入的值
      resData: [], // 服务器返回结果
      allList: [] // 消息数组
    }
  },
  mounted () {
    this.nickName = this.$route.query.nickName
    this.initWebSocket()
  },
  destroyed () {
    // 离开页面时关闭websocket连接
    this.ws.onclose(undefined)
  },
  methods: {
    PrivateSendMessage: function (item) {
      var _this = this
      _this.toUser = item
      console.log('对' + item + '发起私聊')
    },
    // 发送聊天信息
    sendText () {
      let _this = this
      if (!_this.contentText) {
        return
      }
      let params = {
        msg: _this.contentText
      }
      console.log('频道号' + _this.toUser)
      console.log('频道号' + _this.toUse === null)
      if (_this.toUser === '') {
        params.messageType = 3
      } else {
        params.messageType = 4
        params.toUser = _this.toUser
      }
      _this.ws.send(JSON.stringify(params)) // 调用WebSocket send()发送信息的方法
      _this.contentText = ''
    },
    // 进入页面创建websocket连接
    initWebSocket () {
      let _this = this
      // 模拟用户的号码npm
      // 判断页面有没有存在websocket连接
      if (window.WebSocket) {
        let serverHot = window.location.hostname
        let sip = '1010'
        console.log('can')
        if (_this.nickName === '' || _this.nickName === undefined) {
          console.log('_this.nickName爲空')
          return
        }
        // 填写本地IP地址 此处的 :9101端口号 要与后端配置的一致!
        let url = 'ws://' + serverHot + ':8093' + '/groupChat/' + sip + '/' + this.nickName // `ws://127.0.0.1/9101/groupChat/10086/聊天室`
        let ws = new WebSocket(url)
        _this.ws = ws
        ws.onopen = function (e) {
          console.log('服务器连接成功: ' + url)
        }
        ws.onclose = function (e) {
          console.log('服务器连接关闭: ' + url)
        }
        ws.onerror = function () {
          console.log('服务器连接出错: ' + url)
        }
        ws.onmessage = function (e) {
          // 接收服务器返回的数据
          let resData = JSON.parse(e.data)
          _this.resData = resData
          _this.count = resData.count
          _this.onlineUsers = resData.onlineList
          _this.list = [
            _this.list,
            { nickName: resData.nickName, content: resData.msg, onlineUsers: resData.onlineList }
          ]
          // 1 代表上线 2 代表下线 3代表群发 4代表私发消息
          if (resData.messageType === 2) {
            // document.getElementById('message').innerHTML += resData.nickName + ':' + '<br/>' + resData.msg + '<br/>'
            let item = {
              person: resData.nickName,
              message: resData.msg
            }
            _this.allList.push(item)
          }
          if (resData.messageType === 4) {
            // document.getElementById('messageTo').innerHTML += resData.fromUser + ':' + '(私聊)' + resData.toUser + '<br/>' + resData.msg + '<br/>'
            let item = {
              person: resData.fromUser,
              message: resData.msg,
              toPerson: resData.toUser,
              messageType: resData.messageType
            }
            _this.allList.push(item)
            console.log('添加', _this.allList)
          } else {
            let item = {
              person: resData.fromUser,
              message: resData.msg,
              messageType: resData.messageType
            }
            _this.allList.push(item)
            console.log('添加', _this.allList)
          }
          /* if (resData.messageType === 1 || resData.messageType === 3) {
            document.getElementById('message').innerHTML += resData.fromUser + ':' + '(群发)' + '<br/>' + resData.msg + '<br/>'
            let item ={
              person: resData.nickName,
              message: resData.msg
            }
            allList.push(item)
          } */
          console.log('服务器返回的数据', resData)
        }
      }
    }
  }
}
</script>

<style scoped>
</style>

到此结束!

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:49:27  更:2021-08-01 14:50:10 
 
开发: 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年5日历 -2024/5/3 3:33:20-

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