聊天廣場(Vue+WebSocket+SpringBoot)

由于心血來潮想要做個聊天室項目 ,但是仔細找了一下相關教程,卻發現這么多的WebSocket教程里面,很多都沒有介紹詳細,代碼都有所殘缺,所以這次帶來一個比較完整得使用WebSocket的項目。

目錄

一、效果展示

二、準備工作

一、前端框架,Vue + elementUI組件 +JsCookie

二、后端 SpringBoot + websocket包

三、前端代碼

四、后端代碼


一、效果展示

1.用戶交流


二、準備工作

一、前端框架,Vue + elementUI組件 +JsCookie

新建一個vue項目

引入以下組件與依賴

npm i element-ui -S
npm install js-cookie

二、后端 SpringBoot + websocket包

創建SpringBoot項目后

在pom.xml文件中引入以下依賴:

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

注意項目前端為8081端口,后端為8080端口,所以先運行后端再運行前端


三、前端代碼

在App.vue中即可引入以下代碼:

html:

<template><div id="Layout"><el-container><el-aside width="200px">Aside</el-aside><el-container><el-header style="background-color: rgb(245, 245, 245); border-bottom: 1px solid grey;"><h3>聊天廣場</h3></el-header><el-main style="background-color: rgb(244, 245, 247);min-height: 700px; max-height: 700px; "><div id="chatContent" style="padding-left: 10px; line-height: normal; "><!-- 循環輸出對話內容 --><el-scrollbar v-for="(message, index) in messages" :key="index"><div ref="scrollbar" v-if="message.sender !== senderName" class="chat-message" id="ChatContentCard" style=" background-color: white;margin-top: 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)  "><el-avatar :size="40"src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png"></el-avatar><div class="message-content" style="width: 100%;"><div style="text-align: left; text-indent: 1em;"> {{ message.sender }}</div><div id="chatContentText">{{ message.text }}</div></div></div><div ref="scrollbar" v-if="message.sender === senderName" id="myChatContentCard"><el-avatar :size="40"src="https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg"></el-avatar><div class="message-content" style="width: 100%;"><div style="text-align: left; text-indent: 1em;"> {{ message.sender }}</div><div id="chatContentText">{{ message.text }}</div></div></div></el-scrollbar></div></el-main><!-- 底層交互框 --><el-footer style="height: 190px; background-color: rgb(244, 245, 247); "><div id="Gadget" style="background-color: rgb(244, 245, 247); height: 35px; margin-bottom: 10px;"><el-upload class="upload-demo" ref="upload" action="https://jsonplaceholder.typicode.com/posts/":on-preview="handlePreview" :on-remove="handleRemove" :file-list="fileList" :auto-upload="false" style="float: left;"><el-button slot="trigger" size="small" type="primary"><i class="el-icon-picture-outline-round"></i></el-button><el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上傳到服務器</el-button></el-upload></div><el-form @submit.native.prevent="sendMessage"style="background-color: rgb(244, 245, 247); height: 80%; width: 100%; position: relative;"><el-input v-model="messageInput" rows="4" resize="none" type="textarea" placeholder="請輸入內容......."@keyup.enter="sendMessage" style="height: 100%; max-height: 60px; "></el-input><div style="text-align: right; background-color: rgb(244, 245, 247); margin-top: 34px;"><el-button type="primary" @click="sendMessage">發送</el-button></div></el-form></el-footer></el-container></el-container></div>
</template>

script:

<script>
import Cookies from 'js-cookie';export default {computed: {senderName() {return Cookies.get('account') || '游客';}},name: 'App',data() {return {messages: [],messageInput: '',ws: null,fileList: []};},mounted() {this.initWebSocket();},beforeDestroy() {this.closeWebSocket();},methods: {initWebSocket() {this.ws = new WebSocket('ws://localhost:8080/chat');this.ws.onopen = () => {console.log('Connected to server.');};this.ws.onmessage = (event) => {try {let messageData;if (isJson(event.data)) {messageData = JSON.parse(event.data);} else {messageData = { text: event.data };}this.messages.push({sender: messageData.sender || 'Anonymous',text: messageData.text,});// 使用Vue.nextTick確保DOM更新后再執行滾動操作this.$nextTick(() => {// 確保scrollbar存在且已渲染if (this.$refs.scrollbar) {// 直接滾動到底部,不需要使用contentSize// this.$refs.scrollbar.$el.scrollTop = this.$refs.scrollbar.$el.scrollHeight;}});} catch (error) {console.error('Error parsing message:', error);}};// 輔助函數,檢查字符串是否可能是JSON格式function isJson(str) {try {JSON.parse(str);} catch (e) {return false;}return true;}this.ws.onerror = (error) => {console.error('WebSocket error:', error);};this.ws.onclose = () => {console.log('Disconnected from server.');};},sendMessage() {console.log('調用sendMessage');const senderName = Cookies.get('account');if (senderName === null) {this.senderName = "游客";}if (this.messageInput.trim() !== '') {this.ws.send(JSON.stringify({ sender: senderName, text: this.messageInput }));this.messageInput = ''; // 清空輸入框}},closeWebSocket() {if (this.ws && this.ws.readyState === WebSocket.OPEN) {this.ws.close();}},// 文件上傳函數
submitUpload() {this.$refs.upload.submit();},handleRemove(file, fileList) {console.log(file, fileList);},handlePreview(file) {console.log(file);}},
};
</script>

css:

<style scoped>
.chat-message {display: flex;align-items: center;margin-bottom: 10px;
}.message-content {margin-left: 10px;
}#Layout {line-height: normal;
}/* 添加動畫關鍵幀 */
@keyframes slideInFromLeft {0% {transform: translateX(-100%);opacity: 0;}100% {transform: translateX(0);opacity: 1;}
}#ChatContentCard {min-height: 80px;width: 50%;/* 應用動畫 */animation: slideInFromLeft 0.3s ease-in-out forwards;border-radius: 30px
}#chatContentText {width: 99%;overflow-wrap: break-word;}.el-header,
.el-footer {background-color: #B3C0D1;color: #333;text-align: center;line-height: 60px;
}.el-aside {background-color: #D3DCE6;color: #333;text-align: center;line-height: 200px;
}.el-main {background-color: #E9EEF3;color: #333;text-align: center;line-height: 160px;
}body>.el-container {margin-bottom: 40px;
}.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {line-height: 260px;
}.el-container:nth-child(7) .el-aside {line-height: 320px;
}#myChatContentCard{display: flex;align-items: center;margin-bottom: 10px;margin-left: 50%;min-height: 80px;width: 50%;/* 應用動畫 */animation: slideInFromRight 0.3s ease-in-out forwards;border-radius: 30px;background-color: rgb(149, 236, 105);margin-top: 20px; box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) }@keyframes slideInFromRight {0% {transform: translateX(100%);opacity: 0;}100% {transform: translateX(0);opacity: 1;}
}</style>

注意: 這個項目中如果script需要進行修改,由于我這里完成了一個登陸系統,所以采用了對Cookie的使用,而如果只是體驗的話,只需要把Cookie去掉將其改為游客+隨機字符串去替代即可。

前端啟動

npm run serve


四、后端代碼

WebSocket配置:

1.WebSocketConfig.java

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new ChatWebSocketHandler(), "/chat").setAllowedOrigins("*");}
}

?2.ChatWebSocketHandler.java

@Slf4j
public class ChatWebSocketHandler extends TextWebSocketHandler {private static final Set<WebSocketSession> sessions = Collections.synchronizedSet(new HashSet<>());@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {sessions.add(session);broadcast("歡迎新的小伙伴加入");}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {broadcast(message.getPayload());}private void broadcast(String message) {log.info("服務器廣播數據:"+message);sessions.forEach(session -> {try {session.sendMessage(new TextMessage(message));} catch (Exception e) {e.printStackTrace();}});}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {sessions.remove(session);}
}

?后端啟動:

?


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/41020.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/41020.shtml
英文地址,請注明出處:http://en.pswp.cn/web/41020.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

html+css+js圖片手動輪播

源代碼在界面圖片后面 輪播演示用的幾張圖片是Bing上的&#xff0c;直接用的幾張圖片的URL&#xff0c;誰加載可能需要等一下&#xff0c;現實中替換成自己的圖片即可 關注一下點個贊吧&#x1f604; 謝謝大佬 界面圖片 源代碼 <!DOCTYPE html> <html lang&quo…

內存對齊宏ALIGN的理解

內存對齊宏ALIGN的理解 在Android Camera HAL代碼中經常看到ALIGN這個宏&#xff0c;主要用來進行內存對齊&#xff0c;下面是v4l2_wrapper.cpp中ALIGN的一些定義 //v4l2_wrapper.cpp中內存分配進行對其的操作和定義#define ALIGN( num, to ) (((num) (to-1)) & (~(to-1)…

【Android】自定義換膚框架03之自定義LayoutInflaterFactory

AppCompatActivity是如何創建View的 Activity通過LayoutInflater解析出XmlLayout相關信息LayoutInflater內部維護了一個InflaterFactory對象InflaterFactory接口包含了一個onCreateView方法&#xff0c;用于創建View將解析出的Xml信息轉為AttributeSet&#xff0c;交給Inflate…

安全測試之使用Docker搭建SQL注入安全測試平臺sqli-labs

1 搜索鏡像 docker search sqli-labs 2 拉取鏡像 docker pull acgpiano/sqli-labs 3 創建docker容器 docker run -d --name sqli-labs -p 10012:80 acgpiano/sqli-labs 4 訪問測試平臺網站 若直接使用虛擬機&#xff0c;則直接通過ip端口號訪問若通過配置域名&#xff0…

PyQt多線程詳解

PyQt多線程是在PyQt框架中利用多線程技術來提高應用程序的響應性和性能的一種方法。下面將詳細說明PyQt多線程的基本概念、應用場景以及實現方式。 一、PyQt多線程的基本概念 在PyQt中&#xff0c;多線程指的是在單個程序實例內同時運行多個線程。每個線程都可以執行不同的任…

第十五章 Nest Pipe(內置及自定義)

NestJS的Pipe是一個用于數據轉換和驗證的特殊裝飾器。Pipe可以應用于控制器&#xff08;Controller&#xff09;的處理方法&#xff08;Handler&#xff09;和中間件&#xff08;Middleware&#xff09;&#xff0c;用于處理傳入的數據。它可以用來轉換和驗證數據&#xff0c;確…

【Linux進階】文件系統5——ext2文件系統(inode)

1.再談inode (1) 理解inode&#xff0c;要從文件儲存說起。 文件儲存在硬盤上&#xff0c;硬盤的最小存儲單位叫做"扇區"&#xff08;Sector&#xff09;。每個扇區儲存512字節&#xff08;相當于0.5KB&#xff09;。操作系統讀取硬盤的時候&#xff0c;不會一個個…

記錄excel表生成一列按七天一個周期的方法

使用excel生成每七天一個周期的列。如下圖所示&#xff1a; 針對第一列的生成辦法&#xff0c;使用如下函數&#xff1a; TEXT(DATE(2024,1,1)(ROW()-2)*7,"yyyy/m/d")&" - "&TEXT(DATE(2024,1,1)(ROW()-1)*7-1,"yyyy/m/d") 特此記錄。…

charles使用教程

安裝與配置 下載鏈接&#xff1a;https://www.charlesproxy.com/download/ 進行移動端抓包&#xff1a; 電腦端配置&#xff1a; 關閉防火墻 Proxy–>勾選 macOS Proxy Proxy–>Proxy Setting–>填入代理端口8888–>勾選Enable transparent http proxying 安裝c…

俄羅斯方塊的python實現

俄羅斯方塊游戲是一種經典的拼圖游戲&#xff0c;玩家需要將不同形狀的方塊拼接在一起&#xff0c;使得每一行都被完全填滿&#xff0c;從而清除這一行并獲得積分。以下是該游戲的算法描述&#xff1a; 1. 初始化 初始化游戲界面&#xff0c;設置屏幕大小、方塊大小、網格大小…

昇思25天學習打卡營第1天|初識MindSpore

# 打卡 day1 目錄 # 打卡 day1 初識MindSpore 昇思 MindSpore 是什么&#xff1f; 昇思 MindSpore 優勢|特點 昇思 MindSpore 不足 官方生態學習地址 初識MindSpore 昇思 MindSpore 是什么&#xff1f; 昇思MindSpore 是全場景深度學習架構&#xff0c;為開發者提供了全…

女生學計算機好不好?感覺計算機分有點高……?

眾所周知&#xff0c;在國內的高校里&#xff0c;計算機專業的女生是非常少的&#xff0c;很多小班30人左右&#xff0c;但是每個班女生人數只有個位數。這就給很多人一個感覺&#xff0c;是不是女生天生就不適合學這個東西呢&#xff1f;女生是不是也應該放棄呢&#xff1f;當…

ubuntu 進入命令行

在Ubuntu中&#xff0c;有幾種方法可以進入命令行界面&#xff1a; 啟動時選擇命令行模式&#xff1a; 在計算機啟動時&#xff0c;如果安裝了GRUB引導加載器&#xff0c;可以通過GRUB菜單選擇進入命令行模式。這通常涉及到在啟動時按下Shift鍵或其他指定鍵來顯示GRUB菜單&…

常見算法和Lambda

常見算法和Lambda 文章目錄 常見算法和Lambda常見算法查找算法基本查找&#xff08;順序查找&#xff09;二分查找/折半查找插值查找斐波那契查找分塊查找擴展的分塊查找&#xff08;無規律的數據&#xff09; 常見排序算法冒泡排序選擇排序插入排序快速排序遞歸快速排序 Array…

SpringBoot新手快速入門系列教程二:MySql5.7.44的免安裝版本下載和配置,以及簡單的Mysql生存指令指南。

我們要如何選擇MySql 目前主流的Mysql有5.0、8.0、9.0 主要區別 MySQL 5.0 發布年份&#xff1a;2005年特性&#xff1a; 基礎事務支持存儲過程、觸發器、視圖基礎存儲引擎&#xff08;如MyISAM、InnoDB&#xff09;外鍵支持基本的全文搜索性能和擴展性&#xff1a; 相對較…

2024年江蘇省研究生數學建模競賽B題火箭煙幕彈運用策略優化論文和代碼分析

經過不懈的努力&#xff0c; 2024年江蘇省研究生數學建模競賽B題火箭煙幕彈運用策略優化論文和代碼已完成&#xff0c;代碼為B題全部問題的代碼&#xff0c;論文包括摘要、問題重述、問題分析、模型假設、符號說明、模型的建立和求解&#xff08;問題1模型的建立和求解、問題2模…

[學習筆記]SQL學習筆記(連載中。。。)

學習視頻&#xff1a;【數據庫】SQL 3小時快速入門 #數據庫教程 #SQL教程 #MySQL教程 #database#Python連接數據庫 目錄 1.SQL的基礎知識1.1.表(table)和鍵(key)1.2.外鍵、聯合主鍵 2.MySQL安裝&#xff08;略&#xff0c;請自行參考視頻&#xff09;3.基本的MySQL語法3.1.規…

進程控制-fork函數

一個進程&#xff0c;包括代碼、數據和分配給進程的資源。 fork &#xff08;&#xff09;函數通過系統調用創建一個與原來進程幾乎完全相同的進程&#xff0c;也就是兩個進程可以做完全相同的事&#xff0c;但如果初始參數或者傳入的變量不同&#xff0c;兩個進程也可以做不同…

DatawhaleAI夏令營2024 Task2

#AI夏令營 #Datawhale #夏令營 賽題解析一、Baseline詳解1.1 環境配置1.2 數據處理任務理解2.3 prompt設計2.4 數據抽取 二、完整代碼總結 賽題解析 賽事背景 在數字化時代&#xff0c;企業積累了大量對話數據&#xff0c;這些數據不僅是交流記錄&#xff0c;還隱藏著寶貴的信…

【鴻蒙學習筆記】@Link裝飾器:父子雙向同步

官方文檔&#xff1a;Link裝飾器&#xff1a;父子雙向同步 目錄標題 [Q&A] Link裝飾器作用 [Q&A] Link裝飾器特點樣例&#xff1a;簡單類型樣例&#xff1a;數組類型樣例&#xff1a;Map類型樣例&#xff1a;Set類型樣例&#xff1a;聯合類型 [Q&A] Link裝飾器作用…