欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot+WebSocket實現(xiàn)在線聊天功能

 更新時間:2023年02月14日 10:42:04   作者:代碼界小菜鳥  
WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。這篇文章主要為大家介紹了如何利用Springboot和WebSocket實現(xiàn)在線聊天功能,感興趣的小伙伴可以了解一下

一、后端

1.在Springboot項目的pom.xml中添加依賴

<!--websocket協(xié)議-->
<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.4.3</version>
</dependency>

2.要想使用WebSocket配置config配置類

package com.websocket.config;

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 bean對象,他會自動注冊使用@ServerEndpoint
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

3.新建component問價夾,下方新建WebSocketServer核心代碼

package com.websocket.component;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
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;

/**
 * @author websocket服務(wù)
 */
@ServerEndpoint(value = "/imserver/{username}")
@Component
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 記錄當(dāng)前在線連接數(shù)
     */
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 連接建立成功調(diào)用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        sessionMap.put(username, session);
        log.info("有新用戶加入,username={}, 當(dāng)前在線人數(shù)為:{}", username, sessionMap.size());
        JSONObject result = new JSONObject();
        JSONArray array = new JSONArray();
        result.set("users", array);
        for (Object key : sessionMap.keySet()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("username", key);
            // {"username", "zhang", "username": "admin"}
            array.add(jsonObject);
        }
//        {"users": [{"username": "zhang"},{ "username": "admin"}]}
        sendAllMessage(JSONUtil.toJsonStr(result));  // 后臺發(fā)送消息給所有的客戶端
    }

    /**
     * 連接關(guān)閉調(diào)用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("username") String username) {
        sessionMap.remove(username);
        log.info("有一連接關(guān)閉,移除username={}的用戶session, 當(dāng)前在線人數(shù)為:{}", username, sessionMap.size());
    }

    /**
     * 收到客戶端消息后調(diào)用的方法
     * 后臺收到客戶端發(fā)送過來的消息
     * onMessage 是一個消息的中轉(zhuǎn)站
     * 接受 瀏覽器端 socket.send 發(fā)送過來的 json數(shù)據(jù)
     * @param message 客戶端發(fā)送過來的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("username") String username) {
        log.info("服務(wù)端收到用戶username={}的消息:{}", username, message);
        JSONObject obj = JSONUtil.parseObj(message);
        String toUsername = obj.getStr("to"); // to表示發(fā)送給哪個用戶,比如 admin
        String text = obj.getStr("text"); // 發(fā)送的消息文本  hello
        // {"to": "admin", "text": "聊天文本"}
        Session toSession = sessionMap.get(toUsername); // 根據(jù) to用戶名來獲取 session,再通過session發(fā)送消息文本
        if (toSession != null) {
            // 服務(wù)器端 再把消息組裝一下,組裝后的消息包含發(fā)送人和發(fā)送的文本內(nèi)容
            // {"from": "zhang", "text": "hello"}
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("from", username);  // from 是 zhang
            jsonObject.set("text", text);  // text 同上面的text
            this.sendMessage(jsonObject.toString(), toSession);
            log.info("發(fā)送給用戶username={},消息:{}", toUsername, jsonObject.toString());
        } else {
            log.info("發(fā)送失敗,未找到用戶username={}的session", toUsername);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("發(fā)生錯誤");
        error.printStackTrace();
    }

    /**
     * 服務(wù)端發(fā)送消息給客戶端
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服務(wù)端給客戶端[{}]發(fā)送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服務(wù)端發(fā)送消息給客戶端失敗", e);
        }
    }

    /**
     * 服務(wù)端發(fā)送消息給所有客戶端
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服務(wù)端給客戶端[{}]發(fā)送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服務(wù)端發(fā)送消息給客戶端失敗", e);
        }
    }
}

4.如果有攔截就放開攔截

我沒有設(shè)置攔截,全部都是放開的

二、Websocket

1.Websocket 屬性

屬性描述
Socket.readyState只讀屬性 ready State 表示連接狀態(tài),可以是以下值:
0 - 表示連接尚未建立
1 - 表示連接已經(jīng)建立,可以進(jìn)行通信。
2 - 表示連接正在關(guān)閉
3 - 表示連接已經(jīng)關(guān)閉或者連接不能打開
Socket.buffereAmount只讀屬性 buffereAmount 已被 send()放入隊列中等待傳輸,但是還沒有發(fā)出的utf-8文本字節(jié)數(shù)

2.WebSocket 事件

事件事件處理程序描述
openSocket.onopen連接建立時觸發(fā)
messageSocket.onmessage客戶端接受服務(wù)端數(shù)據(jù)時觸發(fā)
errorSocket.onerror通信發(fā)生錯誤時觸發(fā)
closeSocket.onclose連接關(guān)閉時觸發(fā)

3.WebSocket 方法—一下是 WebSocket對象的相關(guān)方法,假定我們使用了以上代碼創(chuàng)建Socket 對象

方法描述
Socket.send()使用連接發(fā)送數(shù)據(jù)
Socket.close()關(guān)閉連接

三、前端

<template>
  <div style="padding: 10px; margin-bottom: 50px">
    <el-row>
      <el-col :span="4">
        <el-card style="width: 300px; height: 300px; color: #333">
         <div style="padding-bottom: 10px; border-bottom: 1px solid #ccc">在線用戶<span style="font-size: 12px">(點擊聊天氣泡開始聊天)</span></div>
          <div style="padding: 10px 0" v-for="user in users" :key="user.username">
            <span>{{ user.username }}</span>
            <i class="el-icon-chat-dot-round" style="margin-left: 10px; font-size: 16px; cursor: pointer"
               @click="chatUser = user.username"></i>
            <span style="font-size: 12px;color: limegreen; margin-left: 5px" v-if="user.username === chatUser">chatting...</span>
          </div>
        </el-card>
      </el-col>

      <el-col :span="20">
        <div style="width: 800px; margin: 0 auto; background-color: white;
                    border-radius: 5px; box-shadow: 0 0 10px #ccc">
          <div style="text-align: center; line-height: 50px;">
            Web聊天室({{ chatUser }})
          </div>
          <div style="height: 350px; overflow:auto; border-top: 1px solid #ccc" v-html="content"></div>
          <div style="height: 200px">
            <textarea v-model="text" style="height: 160px; width: 100%; padding: 20px; border: none; border-top: 1px solid #ccc;
             border-bottom: 1px solid #ccc; outline: none"></textarea>
            <div style="text-align: right; padding-right: 10px">
              <el-button type="primary" size="mini" @click="send">發(fā)送</el-button>
            </div>
          </div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>

import request from "@/utils/request";

let socket;

export default {
  name: "Im",
  data() {
    return {
      circleUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
      user: {},
      isCollapse: false,
      users: [],
      chatUser: '',
      text: "",
      messages: [],
      content: ''
    }
  },
  created() {
    this.init()
  },
  methods: {
    send() {
      if (!this.chatUser) {
        this.$message({type: 'warning', message: "請選擇聊天對象"})
        return;
      }
      if (!this.text) {
        this.$message({type: 'warning', message: "請輸入內(nèi)容"})
      } else {
        if (typeof (WebSocket) == "undefined") {
          console.log("您的瀏覽器不支持WebSocket");
        } else {
          console.log("您的瀏覽器支持WebSocket");
          // 組裝待發(fā)送的消息 json
          // {"from": "zhang", "to": "admin", "text": "聊天文本"}
          let message = {from: this.user.username, to: this.chatUser, text: this.text}
          socket.send(JSON.stringify(message));  // 將組裝好的json發(fā)送給服務(wù)端,由服務(wù)端進(jìn)行轉(zhuǎn)發(fā)
          this.messages.push({user: this.user.username, text: this.text})
          // 構(gòu)建消息內(nèi)容,本人消息
          this.createContent(null, this.user.username, this.text)
          this.text = '';
        }
      }
    },
    createContent(remoteUser, nowUser, text) {  // 這個方法是用來將 json的聊天消息數(shù)據(jù)轉(zhuǎn)換成 html的。
      let html
      // 當(dāng)前用戶消息
      if (nowUser) { // nowUser 表示是否顯示當(dāng)前用戶發(fā)送的聊天消息,綠色氣泡
        html = "<div class=\"el-row\" style=\"padding: 5px 0\">\n" +
            "  <div class=\"el-col el-col-22\" style=\"text-align: right; padding-right: 10px\">\n" +
            "    <div class=\"tip left\">" + text + "</div>\n" +
            "  </div>\n" +
            "  <div class=\"el-col el-col-2\">\n" +
            "  <span class=\"el-avatar el-avatar--circle\" style=\"height: 40px; width: 40px; line-height: 40px;\">\n" +
            "    <img src=\"https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png\" style=\"object-fit: cover;\">\n" +
            "  </span>\n" +
            "  </div>\n" +
            "</div>";
      } else if (remoteUser) {   // remoteUser表示遠(yuǎn)程用戶聊天消息,藍(lán)色的氣泡
        html = "<div class=\"el-row\" style=\"padding: 5px 0\">\n" +
            "  <div class=\"el-col el-col-2\" style=\"text-align: right\">\n" +
            "  <span class=\"el-avatar el-avatar--circle\" style=\"height: 40px; width: 40px; line-height: 40px;\">\n" +
            "    <img src=\"https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png\" style=\"object-fit: cover;\">\n" +
            "  </span>\n" +
            "  </div>\n" +
            "  <div class=\"el-col el-col-22\" style=\"text-align: left; padding-left: 10px\">\n" +
            "    <div class=\"tip right\">" + text + "</div>\n" +
            "  </div>\n" +
            "</div>";
      }
      console.log(html)
      this.content += html;
    },
    init() {
      this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {}
      let username = this.user.username;
      let _this = this;
      if (typeof (WebSocket) == "undefined") {
        console.log("您的瀏覽器不支持WebSocket");
      } else {
        console.log("您的瀏覽器支持WebSocket");
        let socketUrl = "ws://localhost:9090/imserver/" + username;
        if (socket != null) {
          socket.close();
          socket = null;
        }
        // 開啟一個websocket服務(wù)
        socket = new WebSocket(socketUrl);
        //打開事件
        socket.onopen = function () {
          console.log("websocket已打開");
        };
        //  瀏覽器端收消息,獲得從服務(wù)端發(fā)送過來的文本消息
        socket.onmessage = function (msg) {
          console.log("收到數(shù)據(jù)====" + msg.data)
          let data = JSON.parse(msg.data)  // 對收到的json數(shù)據(jù)進(jìn)行解析, 類似這樣的: {"users": [{"username": "zhang"},{ "username": "admin"}]}
          if (data.users) {  // 獲取在線人員信息
            _this.users = data.users.filter(user => user.username !== username)  // 獲取當(dāng)前連接的所有用戶信息,并且排除自身,自己不會出現(xiàn)在自己的聊天列表里
          } else {
            // 如果服務(wù)器端發(fā)送過來的json數(shù)據(jù) 不包含 users 這個key,那么發(fā)送過來的就是聊天文本json數(shù)據(jù)
            //  // {"from": "zhang", "text": "hello"}
            if (data.from === _this.chatUser) {
              _this.messages.push(data)
              // 構(gòu)建消息內(nèi)容
              _this.createContent(data.from, null, data.text)
            }
          }
        };
        //關(guān)閉事件
        socket.onclose = function () {
          console.log("websocket已關(guān)閉");
        };
        //發(fā)生了錯誤事件
        socket.onerror = function () {
          console.log("websocket發(fā)生了錯誤");
        }
      }
    }

  }
}

</script>

<style>
.tip {
  color: white;
  text-align: center;
  border-radius: 10px;
  font-family: sans-serif;
  padding: 10px;
  width:auto;
  display:inline-block !important;
  display:inline;
}

.right {
  background-color: deepskyblue;
}
.left {
  background-color: forestgreen;
}
</style>

以上就是Springboot+WebSocket實現(xiàn)在線聊天功能的詳細(xì)內(nèi)容,更多關(guān)于Springboot WebSocket在線聊天的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java自定義線程模型處理方法分享

    java自定義線程模型處理方法分享

    本文給大家總結(jié)分享了下個人關(guān)于java處理自定義線程模型的一些經(jīng)驗和處理方法,有需要的小伙伴可以參考下
    2016-08-08
  • java設(shè)計模式之觀察者模式學(xué)習(xí)

    java設(shè)計模式之觀察者模式學(xué)習(xí)

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計模式之觀察者模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Spring?Boot多數(shù)據(jù)源事務(wù)@DSTransactional的使用詳解

    Spring?Boot多數(shù)據(jù)源事務(wù)@DSTransactional的使用詳解

    本文主要介紹了Spring?Boot多數(shù)據(jù)源事務(wù)@DSTransactional的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 淺談Java面向接口編程

    淺談Java面向接口編程

    本文通過結(jié)合接口的本質(zhì)、面向?qū)ο缶幊膛c面向接口編程的關(guān)系以及一些作者自身的理解,向大家介紹了面向接口編程的一些東西,需要的朋友可以了解下。
    2017-09-09
  • Java spring AOP基礎(chǔ)

    Java spring AOP基礎(chǔ)

    本篇文章主要介紹了深入理解spring的AOP機(jī)制基礎(chǔ)原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-11-11
  • Maven的概述及基本使用示例詳解

    Maven的概述及基本使用示例詳解

    MApache Maven是一個項目管理和構(gòu)建工具,它基于項目對象模型POM的概念,通過一小段描述信息來管理項目的構(gòu)建、報告和文檔,aven是專門用于管理和構(gòu)建Java項目的工具,本文給大家介紹Maven的概述及基本使用,感興趣的朋友一起看看吧
    2023-07-07
  • Spring框架花式創(chuàng)建Bean的n種方法(小結(jié))

    Spring框架花式創(chuàng)建Bean的n種方法(小結(jié))

    這篇文章主要介紹了Spring框架花式創(chuàng)建Bean的n種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之二叉樹

    Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之二叉樹

    今天給大家?guī)淼氖顷P(guān)于Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識,文章圍繞著Java二叉樹展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java簡單工廠模式定義與用法實例分析

    Java簡單工廠模式定義與用法實例分析

    這篇文章主要介紹了Java簡單工廠模式定義與用法,結(jié)合實例形式分析了java簡單工廠模式的相關(guān)定義與使用技巧,并給出了原理類圖進(jìn)行總結(jié),需要的朋友可以參考下
    2019-07-07
  • IDEA中設(shè)置代碼自動提示為Alt+/的具體做法

    IDEA中設(shè)置代碼自動提示為Alt+/的具體做法

    很多公司都強(qiáng)制性要求使用Intellij?IDEA,其實Intellij?IDEA也確實很好用,但是一下子從Eclipse跳轉(zhuǎn)到Intellij?IDEA轉(zhuǎn)也是需要一段時間的,為了迎合之前的習(xí)慣,就需要在Intellij?IDEA中改變一些設(shè)置,如代碼自動生成,本文給大家分享設(shè)置方法,感興趣的朋友一起看看吧
    2023-01-01

最新評論