WebSocket实现聊天室功能(springboot+vue3+vite)
WebSocket实现聊天室功能(springboot+vue3+vite)
·
1、项目展示图
登录
登录成功
互动
2、websocket介绍
websocket是一种全双工的连接,即服务器和客户端之间建立了一次连接后,两者之间就会一直打开这个通道,就可以相互进行通信。相对于传统单双工的http请求,节省很多资源,不需要一直轮询服务器。
3、springboot代码(主要是写websocket相关的方法,比如创建连接事件,接收消息以及发送消息事件,关闭连接事件)
package com.example.message.WebSocket;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gcp.basicproject.util.ParamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Admin
*/
@ServerEndpoint("/chat/{name}")
@Component
public class AllWebSocketService {
static Logger log = LoggerFactory.getLogger(AllWebSocketService.class);
private static int onlineCount = 0;
private static ConcurrentHashMap<String,AllWebSocketService> webSocketServerMap = new ConcurrentHashMap<>();
private Session session;
private String name = "";
private static ApplicationContext applicationContext;
/**
* 解决引入外部类方法
* @param context
*/
public static void setApplicationContext(ApplicationContext context){
applicationContext = context;
}
/**
* 建立连接
* @param session
* @param name
*/
@OnOpen
public void onOpen(Session session,@PathParam("name") String name){
this.session = session;
webSocketServerMap.put(name,this);
this.name = name;
addOnlineCount();
log.info("用户连接:"+name+",当前在线人数为:"+getOnlineCount());
try{
sendMessage("进入聊天室成功");
}catch (IOException e){
log.error("用户:"+name+",连接失败!!");
}
}
/**
* 关闭连接
*/
@OnClose
public void onClose(){
subOnlineCount();
webSocketServerMap.remove(name);
log.info("用户退出:"+name+",当前在线人数为:"+getOnlineCount());
}
@OnMessage
public void onMessage(String message){
log.info("用户消息:"+name+",报文:"+message);
if(ParamUtil.notEmpty(message)){
log.info(message);
JSONObject jsonObject = JSON.parseObject(message);
jsonObject.put("name",this.name);
webSocketServerMap.forEach((u,m)->{
if(name.contains(u)){
return;
}
try {
m.sendMessage(jsonObject.toJSONString());
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
/**
* 服务器推送消息
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 获取在线人数
* @return
*/
public static synchronized int getOnlineCount(){
return onlineCount;
}
/**
* 上线
*/
public static synchronized void addOnlineCount(){
AllWebSocketService.onlineCount++;
}
/**
* 离线
*/
public static synchronized void subOnlineCount(){
AllWebSocketService.onlineCount--;
}
}
4、vue代码(主要是写连接本地的websocket,接收、发送和显示消息)
<!-- 聊天室 -->
<template>
<h1>聊天室</h1>
<el-scrollbar height="400px" style="border:1px solid #1813131f">
<el-tag v-for="item in list" :key="item" class="scrollbar-demo-item" :style="`justify-content: ${item.type}`">{{
item.name
}}:{{ item.content }}</el-tag>
</el-scrollbar>
发送消息:<el-input v-model="msg"></el-input>
<el-button @click="sendMesage(msg)">发送消息</el-button>
<el-button text @click="dialogFormVisible = true">登录</el-button>
<el-dialog v-model="dialogFormVisible" title="登录">
请输入用户昵称:
<el-input v-model="name" autocomplete="off" />
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="login()">确认</el-button>
</span>
</template>
</el-dialog>
<router-link to="/">返回首页</router-link>
</template>
<script>
import { onBeforeUnmount, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
export default {
name: "chat",
setup() {
const list = reactive([]);
let socket = null;
// Websoket连接成功事件
const websocketonopen = (res) => {
ElMessage.success("WebSocket连接成功");
};
// Websoket接收消息事件
const websocketonmessage = (res) => {
if (res.data) {
ElMessage.success("接收到消息:" + JSON.parse(res.data).content);
message.content = JSON.parse(res.data).content;
message.name = JSON.parse(res.data).name;
message.type = 'left';
list.push(JSON.parse(JSON.stringify(message)));
console.log(list);
}
};
// Websoket连接错误事件
const websocketonerror = (res) => {
ElMessage.error("连接错误");
};
// Websoket断开事件
const websocketclose = (res) => {
ElMessage.error("断开连接");
};
let message = reactive(
{
name: "",
content: "",
type: ''
}
);
let msg = ref("");
let name = ref("");
const dialogFormVisible = ref(false);
const sendMesage = (m) => {
if (name.value == "") {
ElMessage.warning("未登录,无法发送消息");
} else {
ElMessage.success("发送消息:" + m)
message.content = m;
message.name = name.value;
message.type = 'right';
socket.send(JSON.stringify(message));
//解决message对象只有一个,push修改所有message对象的问题
list.push(JSON.parse(JSON.stringify(message)));
console.log(list);
}
}
// 创建 websocket 的实例
const createSocket = () => {
const wsurl = "ws://localhost:8075/chat/" + name.value;
socket = new WebSocket(wsurl);
socket.onopen = websocketonopen;
socket.onmessage = websocketonmessage;
socket.onerror = websocketonerror;
socket.onclose = websocketclose;
};
//登录聊天室
const login = () => {
console.log(name);
createSocket();
dialogFormVisible.value = false;
}
// 组件被销毁之前,清空 sock 对象
onBeforeUnmount(() => {
// 关闭连接
websocketclose;
// 销毁 websocket 实例对象
socket = null;
});
//建立连接,创建websocket实例
return {
name,
list,
msg,
message,
dialogFormVisible,
sendMesage,
createSocket,
login
};
},
};
</script>
<style scoped>
.read-the-docs {
color: #888;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
height: 30px;
margin: 10px;
text-align: left;
border-radius: 4px;
}
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)