Vue3+springboot通过websocket实现实时通信

本文章使用vue3+springboot通过websocket实现两个用户之间的实时通信,聊天信息使用mongodb非关系型数据库进行存储。

效果图如下:

用户发送信息

 农户收到信息并发送回去

后台消息打印

Springboot

引入依赖

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

<!--hutool工具用来处理数据-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.7</version>
</dependency>

<!--slf4j打印窗口日志-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>

 配置

在config目录下,创建WebSocketConfig类

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

@Configuration
public class WebSocketConfig{


    /*
    * 注入一个ServerEndpointExporter,该ean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
    * */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

创建一个WebSocketServer来处理连接

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/chat/{userId}")    // 这里设置的是访问后端接口
@Component
public class WebSocketServer {

    // 这部分是日志打印
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    // 在线连接数
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    // 这里我是采用mongodb去存储聊天数据
    private MongoCollection<Document> collection;

    public WebSocketServer() {
        initializeMongoCollection();
    }

    private void initializeMongoCollection() {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("farmer");    // 这里设置mongodb数据库名
        collection = database.getCollection("chat");    // 设置集合名称
    }

    // 当有用户建立连接到服务器的时候触发
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId){
        // 建立连接的时候就将该用户的session存起来,方便后续的信息返回
        sessionMap.put(userId, session);
        log.info("新聊天用户={},当前在线人数:{}",userId, sessionMap.size());
    }

    // 关闭时触发
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId){
        sessionMap.remove(userId);
        log.info("有一连接关闭,移除聊天用户={},当前在线人数为:{}", userId, sessionMap.size());
    }

    // 当用户发送消息时触发
    @OnMessage
    public void onMessage(String parmas, Session session, @PathParam("userId") String userId){
        log.info("服务器收到聊天用户={}的消息:{}", userId, parmas);
        // 将收到前端的消息解析取出
        JSONObject object = JSONUtil.parseObj(parmas);
        String chatId = object.getStr("chatId");    // 聊天id
        String toUserId = object.getStr("to");      // 发送给谁
        String text = object.getStr("text");        // 文本信息
        String time = object.getStr("time");        // 发送时间

        Session toSession = sessionMap.get(toUserId);    // 查询要发送的人是否在线
        // 新建对象将要存储到数据库的内容封装到一起
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("from", userId);
        jsonObject.set("to", toUserId);
        jsonObject.set("text", text);
        jsonObject.set("time", time);
        
        // 如果toSession为空,则说明对面没在线,直接存到数据库
        // 若不为空,则说明对面在线,将数据存到数据库并且通过sendMessage实时发送给目标客户
        if(toSession != null){
            sendMessage(jsonObject.toString(), toSession);
            log.info("发送给用户username={},消息:{}", toUserId, jsonObject.toString());
            insertChatData(jsonObject, chatId);
        }else{
            log.info("用户{}不在线", toUserId);
            insertChatData(jsonObject, chatId);
        }
    }

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

    // 服务器发送消息给客户端
    private void sendMessage(String message, Session toSession){
        try {
            log.info("服务器给用户【{}】发送消息:{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        }catch (Exception e){
            log.error("服务器发送消息给客户端失败");
        }
    }

    // 服务器发送信息给所有客户端(这步可拓展到群聊)
    private void sendAllMessage(String message){
        try {
            for(Session session : sessionMap.values()){
                log.info("服务器给全用户【{}】发送消息:{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        }catch (Exception e){
            log.error("服务器发送消息给客户端失败");
        }
    }


    // 这是mongodb存到数据库的操作
    private void insertChatData(JSONObject chatData, String chatId) {
        Document document = Document.parse(chatData.toString());

        Document query = new Document("chatId", chatId);
        Document update = new Document("$push", new Document("chatData", document));

        UpdateResult updateResult = collection.updateOne(query, update, new UpdateOptions().upsert(true));
        System.out.println(updateResult);
    }
}

Vue3

用户部分IndexMessage:

在script中先定义一个

let socket;

在methods中

init() {
  let _this = this
  let userId = this.user.userId;    // 当前本用户的id
  if (this.supportWebSocket()) {
    let socketUrl = "ws://localhost:8090/chat/" + userId;
    if (socket != null) {
        socket.close();
        socket = null;
    }
    // 开启一个websocket服务
    socket = new WebSocket(socketUrl);
    //打开事件
    socket.onopen = function () {
        console.log("websocket已打开");
    };
    // 监听数据
    // 浏览器端收消息,获得从服务端发送过来的文本消息
    socket.onmessage = function (msg) {
        console.log("收到数据====" + msg.data)
        let data = JSON.parse(msg.data)

        // 收到最新消息的时候,更新左侧聊天导航的文本内容
        _this.chatNav.forEach(item => {
            if(item.farmerId == data.from){
                item.text = data.text
            }
        })

        // 收到消息的时候去更新chatData中的数据
        _this.addToConetnt(data)

    };
    //关闭事件
    socket.onclose = function () {
        console.log("websocket已关闭");
    };
    //发生了错误事件
    socket.onerror = function (e) {
        console.log(e)
        console.log("websocket发生了错误");
    }
  }
},

send() {
  if (!this.text) {
    // 若为空,提示为空,此处使用elementUI的消息提示
    this.$message({type: 'warning', message: "请输入内容"})
  } else {
    // 封装了一个查看是否支撑websocket的方法
    if(this.supportWebSocket()){

      // 发送的消息
      let message = {
          from: this.user.userId,
          to: this.toUser.toUserId,
          text: this.text,
          time: moment().format('x')    // 使用moment包生成一个时间戳
      }
      this.addToConetnt(message)

      this.text = '';
      this.$refs.messageInput.innerHTML = ""    // 将输入的值设置为空

      // 整合发送消息
      message["chatId"] = this.chatId
      socket.send(JSON.stringify(message));  // 将组装好的json发送给服务端,由服务端进行转发

      // 发送消息的时候,更新左侧聊天导航的文本内容
      this.chatNav.forEach(item => {
          if(item.farmerId == message.to){
              item.text = message.text
          }
      })

      // 将展示内容的div设置滚动到底部
      this.$nextTick(()=>{
          this.$refs.messageContent.scrollTop = this.$refs.messageContent.scrollHeight
      })
    }
  }
},

// 是否支撑websocket
supportWebSocket(){
  if(typeof (WebSocket) == "undefined"){
      console.log("您的浏览器不支持WebSocket");
      return false
  }else{
      return true
  }
},

// 新增记录判断
addToConetnt(message){
  let arr = this.chatData[this.chatData.length - 1]

  const startTime = moment(parseInt(arr.chatItem[arr.chatItem.length - 1].time));    // 最近一条消息的时间
  const endTime = moment();                 // 当前时间

  const duration = moment.duration(endTime.diff(startTime));
  const minutes = duration.asMinutes();

  // 判断最近的消息和上一条消息是否超过3分钟,超过三分钟则重新创建一个对象存储
  if(minutes > 3){
      this.chatData.push({
          time: moment(endTime).format("HH:mm"),
          chatItem: [message]
      })
  }else{
      this.chatData[this.chatData.length - 1].chatItem.push(message)
  }

  this.$nextTick(()=>{
      this.$refs.messageContent.scrollTop = this.$refs.messageContent.scrollHeight
  })
},

重点部分在init中几个socket事件的写法和send发送中scoket的写法,其他的是自己项目的功能实现,按照自己的需求去写就好了

一些chatData的数据类型如下:

 

mongdb的数据库类型如下:

mongodb只是作为参考,若你想使用关系型数据库mysql也是可以,修改具体逻辑就行

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,具体实现步骤如下: 1. 在后端Java应用程序中,使用Java WebSocket API创建WebSocket服务器。 2. 在服务器端实现一个WebSocket端点,用于接收和处理客户端的连接请求和消息。在这个端点中,可以将预警信息条数发送给已连接的客户端。 3. 在前端页面中,使用JavaScript创建WebSocket客户端,连接到WebSocket服务器。在连接成功后,客户端可以接收到从服务器端发送过来的预警信息条数。 4. 在页面通知栏处,使用HTML、CSS和JavaScript实现一个通知栏组件,用于展示预警信息条数的实时变化。 下面是一个简单的Java WebSocket服务器端实现示例: ```java import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint("/alert") public class AlertWebSocket { private static int alertCount = 0; private static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>(); @OnOpen public void onOpen(Session session) { sessions.add(session); } @OnMessage public void onMessage(String message, Session session) { // do nothing } @OnClose public void onClose(Session session) { sessions.remove(session); } public static void sendAlertCount() { for (Session session : sessions) { try { session.getBasicRemote().sendText(String.valueOf(alertCount)); } catch (IOException e) { e.printStackTrace(); } } } public static void increaseAlertCount() { alertCount++; sendAlertCount(); } public static void decreaseAlertCount() { alertCount--; sendAlertCount(); } } ``` 在这个示例中,我们定义了一个WebSocket端点 "/alert",用于接收和处理客户端的连接请求和消息。我们还定义了一个静态变量 alertCount,用于保存预警信息条数,并提供了两个静态方法 increaseAlertCount 和 decreaseAlertCount,用于增加和减少预警信息条数。这些方法还会调用 sendAlertCount 方法,向所有已连接的客户端发送最新的预警信息条数。 下面是一个简单的JavaScript WebSocket客户端实现示例: ```javascript let webSocket = new WebSocket("ws://localhost:8080/alert"); webSocket.onmessage = function(event) { let alertCount = parseInt(event.data); updateAlertCount(alertCount); } function updateAlertCount(alertCount) { let alertCountElem = document.getElementById("alert-count"); alertCountElem.innerText = alertCount.toString(); } ``` 在这个示例中,我们创建了一个WebSocket客户端,连接到WebSocket服务器端口8080上的 "/alert" 端点。在客户端收到来自服务器的消息时,我们会解析出预警信息条数,并调用 updateAlertCount 方法,更新页面通知栏中的预警信息条数显示。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值