SpringBoot整合websocket實現(xiàn)即時通信聊天
一、技術介紹
線上演示地址:http://chat.breez.work

實時通信(Instant Messaging,簡稱IM)是一個實時通信系統(tǒng),允許兩人或多人使用網(wǎng)絡實時的傳遞文字消息、文件、語音與視頻交流。[4]
場景再現(xiàn):
- 微信聊天
- QQ聊天
- 網(wǎng)站在線客服
1.1 客戶端WebSocket
WebSocket對象提供了用于創(chuàng)建和管理 WebSocket 連接,以及可以通過該連接發(fā)送和接收數(shù)據(jù)的 API。使用 WebSocket() 構造函數(shù)來構造一個 WebSocket。[1]
構造函數(shù)如下所示:
const webSocket = WebSocket(url[, protocols])
例子如下:
const webSocket = new WebSocket("ws://42.193.120.86:3688/ws/小明/翠花")1.1.1 函數(shù)
1、 webSocket.send()
該函數(shù)用于向服務端發(fā)送一條消息,例子如下:
webSocket.send("Hello server!");2、 webSocket.close()
該函數(shù)用于關閉客戶端與服務端的連接,例子如下:
webSocket.close();
1.1.2 事件
1、webSocket.onopen
該事件用于監(jiān)聽客戶端與服務端的連接狀態(tài),如果客戶端與服務端連接成功則該事件觸發(fā),例子如下:
webSocket.onopen = function(event) {
console.log("連接已經建立,可以進行通信");
};2、webSocket.onclose
如果服務端與客戶端連接斷開,那么此事件出發(fā),例子如下:
webSocket.onclose = function(event) {
console.log("連接已經關閉");
};3、webSocket: message event
該事件用于監(jiān)聽服務端向客戶端發(fā)送的消息,例子如下:
webSocket.addEventListener('message', function (event) {
console.log('來自服務端的消息:', event.data);
});4、webSocket:error event
如果客戶端與服務端發(fā)生錯誤時,那么此事件將會觸發(fā),例子如下:
webSocket.addEventListener('error', function (event) {
console.log('連接出現(xiàn)錯誤', event);
});1.2 服務端WebSocket
@ServerEndpoint用于聲明一個socket服務,例子如下:
@ServerEndpoint(value = "/ws/{userId}/{targetId}")幾個重要的方法注解:
@OnOpen打開連接@OnClose監(jiān)聽關閉@OnMessage發(fā)送消息@OnError監(jiān)聽錯誤
二、實戰(zhàn)
2.1、服務端
2.1.1引入maven依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
2.1.2 編寫配置類
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}2.1.3 編寫WebSocketService服務類
下面的userId代表發(fā)送者的ID號,target代表發(fā)送目標ID號。
@Component
@ServerEndpoint(value = "/ws/{userId}/{target}")
public class WebSocketService {
//用于保存連接的用戶信息
private static ConcurrentHashMap<String, Session> SESSION = new ConcurrentHashMap<>();
//原子遞增遞減,用于統(tǒng)計在線用戶數(shù)
private static AtomicInteger count = new AtomicInteger();
//消息隊列,用于保存待發(fā)送的信息
private Queue<String> queue = new LinkedBlockingDeque<>();
//onOpen()
//onClose()
//onMessage()
//onError()
}2.1.4 建立連接
建立連接之前,判斷用戶是否已經連接,如果沒有連接,那么將用戶session信息保存到集合,然后計數(shù)器遞增。
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
if (!SESSION.containsKey(userId)) {
SESSION.put(userId, session);
count.incrementAndGet();
}
}2.1.5 關閉連接
關閉連接的時候,將用戶session刪除和計數(shù)器遞減。
@OnClose
public void onClose(@PathParam("userId") String userId) {
SESSION.remove(userId);
count.decrementAndGet();
}2.1.6 發(fā)送消息
發(fā)送采用的方法是:session.getBasicRemote().sendText("你好");
@OnMessage
public void onMessage(String message, @PathParam("userId") String userId, @PathParam("target") String target) throws IOException {
queue.add(message);
Session s = SESSION.get(target);
if (s == null) {
Session b = SESSION.get(userId);
b.getBasicRemote().sendText("對方不在線");
} else {
for (int i = 0; i < queue.size(); i++) {
String msg = queue.poll();
Message m = new Message();
m.setUserId(userId);
s.getBasicRemote().sendText(msg);
}
}
}2.1.7 監(jiān)聽錯誤
出現(xiàn)錯誤,刪除用戶session信息和計數(shù)器遞減
@OnError
public void onError(Throwable error, @PathParam("userId") String userId) {
SESSION.remove(userId);
count.decrementAndGet();
error.printStackTrace();
}2.2 客戶端
本案例中客戶端采用Nuxt編寫,相關代碼如下
2.2.1 主頁面
運行截圖如圖所示:

<template>
<div style="padding-left: 20%;">
<div style="padding-left: 20%;padding-top: 30px;">
<div style="font-size: 30px;">歡迎使用喵喵號聊天</div>
</div>
<div style="padding-top: 20%;">
<el-form :rules="rules" ref="formInline" :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="我的喵喵號" prop="userId">
<el-input v-model="formInline.userId" placeholder="喵喵號"></el-input>
</el-form-item>
<el-form-item label="對方喵喵號" prop="targetId">
<el-input v-model="formInline.targetId" placeholder="喵喵號"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('formInline')">聊一下</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: 'IndexPage',
data() {
return {
formInline: {
userId: '',
targetId: ''
},
rules: {
userId: [{
required: true,
message: '請輸入你的喵喵號',
trigger: 'blur'
}],
targetId: [{
required: true,
message: '請輸入對方喵喵號',
trigger: 'blur'
}]
}
}
},
methods: {
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$router.push({
name: 'chat',
params: this.formInline
})
} else {
console.log('error submit!!');
return false;
}
});
}
},
created() {
}
}
</script>
<style>
body {
background: url('../static/img/cat.jpg');
}
</style>
2.2.1 聊天頁面
運行截圖如下:
小明

翠花

<template>
<div>
<el-row :gutter="20" style="padding-top: 20px;">
<div style="padding-left: 35%;">
<div style="padding-bottom: 15px">
<div style="float: left;padding-right: 30px;">
我的喵喵號:<el-tag type="warning">{{user.userId}}</el-tag>
</div>
<div>
對方喵喵號:<el-tag type="success">{{user.targetId}}</el-tag>
<el-link @click="clearMsg()" :underline="false" style="padding-left: 30px;" type="danger">清空消息</el-link>
</div>
</div>
<div style="border: 1px green solid;width: 400px;height: 400px;border-radius: 10px;">
<div v-for="(m,index) in msgList" :key="index++">
<el-row :gutter="20">
<div v-if="m.type===1" style="padding-left: 10px;">
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>
{{m.msg}}
</div>
<div v-if="m.type===2" style="padding-right: 15px;float: right;">
{{m.msg}}
<el-avatar src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"></el-avatar>
</div>
<div v-if="m.type===3" style="padding-left: 15px;padding-top: 15px;">系統(tǒng)消息:{{m.msg}}</div>
</el-row>
</div>
</div>
</div>
</el-row>
<el-row :gutter="5" style="padding-top: 20px;padding-left: 35%;">
<el-col :span="9" :xs="9" :sm="9" :md="9" :lg="9" :xl="9">
<el-input :disabled="msg_status" v-model="msg" placeholder="消息"></el-input>
</el-col>
<el-col :span="2">
<el-button @click="sendMessage()" type="primary">發(fā)送</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: 'ChatPage',
data() {
return {
url: 'localhost:3688/ws/1001/1002',
msg: '',
socket: {},
msg_status: true,
msgList: [],
initList: [],
count: 0,
user: {
userId: '',
targetId: ''
}
}
},
created() {
const userId = this.$route.params.userId
const targetId = this.$route.params.targetId
if (userId !== undefined && targetId !== undefined) {
this.user.userId = userId
this.user.targetId = targetId
this.connect()
} else {
this.$router.push("/")
}
},
methods: {
//創(chuàng)建socket客戶端
connect() {
var that = this
this.socket = new WebSocket("ws://42.193.120.86:3688/ws/" + this.user.userId + "/" + this.user.targetId);
this.socket.onclose = function(event) {
that.$message('連接關閉');
};
this.socket.addEventListener('error', function(event) {
that.$message.error('出現(xiàn)錯誤');
});
// 監(jiān)聽消息
this.socket.addEventListener('message', function(event) {
that.msgList.push({
type: 2,
msg: event.data
})
console.log(event.data);
console.log({
type: 2,
msg: event.data
});
});
this.socket.onopen = function(event) {
that.msg_status = false
that.msgList.push({
type: 3,
msg: '連接成功'
})
};
},
clearMsg() {
this.$confirm('確認清空?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.msgList = []
})
},
//發(fā)送消息
sendMessage() {
this.socket.send(this.msg)
this.msgList.push({
type: 1,
msg: this.msg
})
this.msg = ''
}
}
}
</script>
<style>
</style>
三、開源地址
Gitee:https://gitee.com/BreezAm/websocket
四、參考文獻
[1]MDN:WebSocket
[2]Nuxt:https://nuxtjs.org
[3]Vue:https://cn.vuejs.org
[4]百度百科:及時通信
到此這篇關于SpringBoot整合websocket實現(xiàn)即時通信聊天的文章就介紹到這了,更多相關SpringBoot websocket即時通信內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- springboot結合websocket聊天室實現(xiàn)私聊+群聊
- SpringBoot+WebSocket實現(xiàn)多人在線聊天案例實例
- SpringBoot中webSocket實現(xiàn)即時聊天
- Springboot+WebSocket實現(xiàn)一對一聊天和公告的示例代碼
- Springboot基于websocket實現(xiàn)簡單在線聊天功能
- SpringBoot+WebSocket搭建簡單的多人聊天系統(tǒng)
- SpringBoot+Websocket實現(xiàn)一個簡單的網(wǎng)頁聊天功能代碼
- SpringBoot結合WebSocket實現(xiàn)聊天功能
相關文章
MyBatis 添加元數(shù)據(jù)自定義元素標簽的實現(xiàn)代碼
這篇文章主要介紹了MyBatis 添加元數(shù)據(jù)自定義元素標簽的實現(xiàn)代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
springBoot 插件工具熱部署 Devtools的步驟詳解
這篇文章主要介紹了springBoot 插件工具 熱部署 Devtools,本文分步驟給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Java中的springboot監(jiān)聽事件和處理事件詳解
這篇文章主要介紹了Java中的springboot監(jiān)聽事件和處理事件,這個示例展示了如何在Spring Boot應用中定義自定義事件、發(fā)布事件以及監(jiān)聽事件,需要的朋友可以參考下2024-07-07
Spring Cloud Alibaba配置多環(huán)境管理詳解與實戰(zhàn)代碼
本文通過實際案例詳細介紹了springboot配置多環(huán)境管理的使用,以及基于nacos的配置多環(huán)境管理的實踐,在實際開發(fā)中,配置多環(huán)境管理是一個很難避開的問題,同時也是微服務治理中一個很重要的內容,感興趣的朋友跟隨小編一起看看吧2024-06-06

