我写的一坨屎,看起来有点乱,只需要看websocket的js代码和java代码就行了,最重要的是理解。
WebSocket是一种基于TCP/IP的双向通信协议,主要用于在单个TCP连接上进行全双工通信。
WebSocket的出现主要是为了解决HTTP等传统协议在实时交互方面的局限性。以下是WebSocket的一些主要特点和优势:
- 持久化连接:与HTTP这种非持久化的协议不同,WebSocket提供了一个持久化的连接,这意味着一旦建立了连接,客户端和服务器可以持续交换数据,而不需要每次都重新建立连接。
- 双向通信:WebSocket支持服务器和客户端之间的双向通信,这使得服务器可以在任何时候将数据推送到客户端,而不需要客户端发起请求。
- 实时性:由于WebSocket的持久化连接和双向通信能力,它非常适合需要实时数据交换的应用,如在线游戏、股票交易平台、聊天室等。
- 低延迟:WebSocket减少了因多次建立连接而产生的延迟,因为一旦握手成功,连接就会保持打开状态,直到显式地关闭为止。
- 轻量级:WebSocket的头部信息相对较小,这使得它在传输数据时更加高效。
- 兼容性:WebSocket是HTML5的一部分,大多数现代浏览器都支持WebSocket协议。
- 安全性:WebSocket通过TLS/SSL加密提供了安全的通信机制,确保数据传输的安全性。
综上所述,WebSocket作为一种先进的通信协议,为实时应用提供了强大的支持,使得开发具有实时交互功能的网站和应用程序变得更加容易和高效。
效果图
前端代码
html部分
<div>
<!-- <div style="float: left;height: 100vh;width: 1%"></div>-->
<div style="float: left;width: 20%;height: 96vh;border-radius: 0.5rem;">
<div class="el-dropdown-link" style="margin-left: 1.6vh;margin-top: 0.7vw;margin-bottom: 0.7vw">返回</div>
<div class="info" style="height: 9vh;width: 100%;text-align: center;border-radius: 10px;">
<div style="width: 95%;height: 8vh;border-radius: 0.5rem;margin-left: 3vw;">
<div style="float: left">
<img style="border-radius: 50%;height: 7vh;width: 3.5vw;margin-left: 1rem;margin-right: 0.7rem;margin-top: 1vh;" src="https://cloud-secondhand-trading.oss-cn-shanghai.aliyuncs.com/u%3D3030190913%2C291621981%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG.webp">
</div>
<div style="float: left;margin-top: 2vh;font-size: 2.5vh">
{{ userName }}
</div>
</div>
</div>
<hr/>
<div style="height: 4vh;width: 100%;text-align: center">
<div style="margin-top: 2vh;font-weight: bold;font-size: 2.5vh">消息列表</div>
</div>
<hr/>
<div v-for="(name,index) in userList" :key="name.id">
<div :id="'id'+name.id" class="messagediv" style="width: 95%;height: 7.7vh;border-radius: 0.5rem;" tabindex="2" @click="getStyMessage(name)">
<div style="float: left">
<img style="border-radius: 50%;height: 6.3vh;width: 3vw;margin-left: 1rem;margin-right: 0.7rem;margin-top: 5px;" src="https://cloud-secondhand-trading.oss-cn-shanghai.aliyuncs.com/u%3D3030190913%2C291621981%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG.webp">
</div>
<div style="float: left;margin-top: 2vh;font-size: 2.5vh">
{{ name.sender }}
</div>
</div>
<div style="width: 19.5vw">
<hr v-if="index!=list.length-1"
style="font-size: 0.001rem;margin-left: 9vh;color: gray;width: 70%;top: -10px"/>
</div>
</div>
</div>
<div style="float: left;height: 96vh;width: 0.5%"></div>
<div style="float: left;width: 78%;background-color: rgb(250,250,249);height: 96vh;">
<div style="width: 100%;height: 3rem;float: left;
text-align: center;background-color: #f0f0f0;border-radius: 0.5rem;">
<div style="margin-top: 0.8rem;font-size: 2.5vh">{{name}}</div>
</div>
<div style="float: left;clear: left;width: 100%;margin-top: 0.8rem;height: 80vh;overflow: auto">
<div v-for="message in list" :key="message.id">
<div style="text-align: center;width: 100%;font-size: 1.6vh;">{{ message.date }}</div>
<div v-if="message.sender!=userName" style="width: 100%;height: 3rem">
<div style="float: left">
<img style="border-radius: 50%;height: 6.3vh;width: 3vw;margin-left: 4rem;margin-right: 0.7rem" src="https://cloud-secondhand-trading.oss-cn-shanghai.aliyuncs.com/u%3D3030190913%2C291621981%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG.webp">
</div>
<div>
<!-- <div style="margin-left: 0.7rem;font-size: 0.5rem">nih</div>-->
<div style="float: left;background-color: white;height: 4.6vh;;border-radius: 10px;margin-top: 0.9vh">
<div style="margin-left: 0.8vw;margin-right: 0.8vw;margin-top:0.68vh;font-size: 2.5vh">{{message.message}}</div>
</div>
</div>
</div>
<div v-if="message.sender==userName" style="width: 100%;height: 3rem">
<div style="float: right">
<img style="border-radius: 50%;height: 6.3vh;width: 3vw;margin-right: 4rem;margin-left: 0.7rem" src="https://cloud-secondhand-trading.oss-cn-shanghai.aliyuncs.com/u%3D3030190913%2C291621981%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG.webp">
</div>
<div>
<!-- <div style="margin-left: 0.7rem;font-size: 0.5rem">nih</div>-->
<div style="float: right;background-color: cornflowerblue;height: 4.6vh;border-radius: 10px;margin-top: 0.4rem;">
<div style="margin: 0.27rem;margin-left: 0.7rem;margin-right: 0.7rem;font-size: 2.5vh">{{message.message}}</div>
<!-- <div style="font-size: 1.8vh;margin-left: 0.5rem;color: gray;margin-top: 0.2rem">-->
<!-- <span v-if="true">已读</span>-->
<!-- <span v-if="false">未读</span>-->
<!-- </div>-->
</div>
</div>
</div>
</div>
<div style="width: 100%;height: 4vh"></div>
</div>
<div v-if="name!=''" style="clear: left;position:absolute;bottom: 10px;width: 100%;height: 5vh;background-color: white">
<input v-model="message" type="text" name="message" style="float: left;width: 55%;margin-left: 7vw;height: 4.7vh;border-radius: 0.5rem;">
<div style="float: left">
<input @click="addMessage" value="发送" type="button" style="height: 5vh;width: 5vw;border-radius: 0.5rem;margin-left: 0.7vw;
font-size: 2.5vh;margin-top: 0.1vh;"/>
</div>
</div>
</div>
</div>
js部分
mounted部分:页面加载就连接,然后就实时接收消息
mounted() {
var socket = new WebSocket("ws://localhost:8818/ws/2");
console.log(this)
const data = this;
socket.onmessage = function(event) {
data.setMessage( name, event.data )
console.log("收到服务器消息: " + event.data);
console.log(data);
};
},
方法部分
// 接收消息
setMessage(name,message){
console.log(this.list)
//date: "2023-10-26T14:06:06.387", read: 0, sender: "李四", name: "张三", id: 1, message: "你好2
this.list.push({date: new Date(),read: 0,sender: this.userName,name: name,id: this.list.length+1, message: message })
this.getMessages();
},
// 发送消息
addMessage(){
var i =1;
console.log(this.list)
const message = this.message;
if (message!=null&&message!=''){
this.$http.post('/api/cloud-member/member/webSocket',{
'id': this.id,'message':message,'name':this.name,sender: this.userName
}).then(response => {
console.log(response);
if (i<=1){
// 请求成功处理
this.getMessages();
const date = new Date();
console.log(new Date());
console.log(this.date);
if (date.getTime()-this.date>=300000){
var month = date.getMonth() + 1
const year = date.getFullYear()+"-"+month+"-"+date.getDate()+" "
+date.getHours()+":"+date.getMinutes();
this.list.push({date: year, read: 0,sender: this.userName, name: this.name, id: this.list.length+1, message: message});
}else{
this.list.push({date: '', read: 0,sender: this.userName, name: this.name, id: this.list.length+1, message: message});
}
// this.getMessage({name: this.userName,sender: this.name})
i++;
}
}).catch(error => {
// 请求失败处理
console.log(error);
});
}
this.message = '';
},
getMessage(name){
// console.log(name);
// this.getMessages();
this.name = name.sender
this.list = [];
},
// 修改时间
getDateTime(name){
this.lists.forEach(list=>{
if ((list.sender==name.sender&&list.name==name.name)||(list.sender==name.name&&list.name==name.sender)){
// 5分钟 300000
let date = new Date(list.date).getTime();
console.log(date)
if (date-this.date>300000){
this.date = date;
list.date = list.date.substring(0,16).replace('T',' ');
// if (id==1){
// //date: "2023-10-26T14:06:06.387", read: 0, sender: "李四", name: "张三", id: 1, message: "你好2
// this.list.push({date: item.date,read: item.read,sender: this.userName,name: this.name,id: this.list.length+1, message: item.message,})
// }
}else{
list.date = '';
}
//date: "2023-10-26T14:06:06.387", read: 0, sender: "李四", name: "张三", id: 1, message: "你好2
this.list.push({date: list.date, read: 0,sender: list.sender, name: list.name, id: this.list.length+1, message: list.message});
console.log(this.list)
}
})
},
getStyMessage(name){
// console.log(name);
this.getMessages();
this.name = name.sender
this.list = [];
this.getStyle(name.id)
this.getDateTime(name);
},
// 消息列表选中变颜色
getStyle(id){
let classNames = document.getElementsByClassName("messagediv");
for (let i = 0; i < classNames.length; i++) {
classNames[i].style.backgroundColor = "white"
}
const ids = document.getElementById("id"+id);
ids.style.backgroundColor = "#e1e1e1";
},
getMessages(){
this.$http.get('/api/cloud-member/member/getMessage/'+this.userName).then(response => {
// console.log(Array.from(response.data.data));
const m = response.data.data;
if (Array.from(m).length>0){
const list = Array.from(response.data.data);
this.lists = list;
}
this.userList = [];
const set = new Set();
this.lists.forEach(item=>{
// 必须要跟我聊过天的才显示 过滤掉自己
if (item.sender==this.userName||item.name==this.userName){
if (item.sender!=this.userName){
set.add(item.sender)
}
}
})
const name = Array.from(set)
for (let i = 0; i < name.length; i++) {
this.userList.push({id: i+1,sender: name[i],name:this.userName});
}
}).catch(error => {
// 请求失败处理
console.log(error);
});
}
后端java代码
websocket类
/**
* WebSocket服务
*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象
private static Map<String, Session> sessionMap = new HashMap();
private Map<String, Object> map = new HashMap();
private List<String> list = new ArrayList<>();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
System.out.println("客户端:" + sid + "建立连接");
list.add(session.getId());
sessionMap.put(sid, session);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
map.put(sid,(map.get(sid)==null?"":(map.get(sid)+","))+message);
System.out.println("收到来自客户端:" + sid + "的信息:" + map);
}
/**
* 连接关闭调用的方法
*
* @param sid
*/
@OnClose
public void onClose(@PathParam("sid") String sid) {
System.out.println("连接断开:" + sid);
sessionMap.remove(sid);
}
/**
* 群发
*
* @param message
*/
public void sendToAllClients(String message) {
Collection<Session> sessions = sessionMap.values();
for (Session session : sessions) {
try {
//服务器向客户端发送消息
session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 私发
*
* @param message
*/
public void sendToAllClient(String id,String message) {
Session session = sessionMap.get(id);
if (session != null) {
try {
// 向客户发送消息
session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("找不到该客户的会话信息");
}
}
}
websocket配置类
/**
* @Author: xhj
* @Date: 2023/10/23/20:15
* @Description:
*/
/**
* WebSocket配置类,用于注册WebSocket的Bean
*/
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
发送消息
@PostMapping("/webSocket")
public R webSocket(@RequestBody Map<String,Object> objectMap){
// Map<String, Object> map = new HashMap<>();
// map.put("id",objectMap.get("id"));
// map.put("message",objectMap.);
// map.put("sender",sender);
// map.put("name",name);
objectMap.put("date", LocalDateTime.now());
objectMap.put("read",0);
//基于WebSocket实现发送消息
webSocketServer.sendToAllClient(objectMap.get("id")+"", objectMap.get("message")+"");
objectMap.put("id",list.size()+1);
list.add(objectMap);
return R.ok(list);
}
获取消息
@GetMapping("/getMessage/{sender}")
public R getMessage(@PathVariable("sender") String sender){
List<Map<String,Object>> list1 = new ArrayList<>();
for (Map<String, Object> map : list) {
if (map.get("sender").equals(sender)||map.get("name").equals(sender)){
list1.add(map);
}
}
System.out.println(list1);
return R.ok(list1);
}
因为没有对接数据库所以我就使用了map来放数据
private List<Map<String,Object>> list = new ArrayList<>();
public MemberController(){
HashMap<String, Object> map = new HashMap<>();
map.put("id",this.list.size()+1);
map.put("message","你好2");
map.put("sender","李四");
map.put("name","张三");
map.put("date", LocalDateTime.now());
map.put("read",0);
HashMap<String, Object> map2 = new HashMap<>();
map2.put("id",this.list.size()+1);
map2.put("message","你好2");
map2.put("sender","张三");
map2.put("name","李四");
map2.put("date", LocalDateTime.now());
map2.put("read",0);
HashMap<String, Object> map3 = new HashMap<>();
map3.put("id",this.list.size()+1);
map3.put("message","你好2");
map3.put("sender","张三");
map3.put("name","王五");
map3.put("date", LocalDateTime.now());
map3.put("read",0);
list.add(map);
list.add(map2);
list.add(map3);
}
现在能简单的通讯了,最重要的是理解,有可能放入你的电脑执行会有bug
如果你对接数据库,前端就不需要写这么麻烦了
后续我对此进行了优化和对接数据库,最重要的就是websocket类里面的几个方法,最后我前端写了个websocket.js,全局使用。