前情描述
最近想了解websocket的相关原理,于是写了一个极简版的程序,后端使用springboot集成websocket模块,前端手敲了一个html页面(页面很丑很丑很丑,勿喷勿喷),整个程序仅支持简单的websocket通信。
websocket优势
百度百科对websocket的定义是:WebSocket是一种在单个TCP连接上进行全双工通信的协议。
websocket的优势:
1:数据包更小,创建连接后数据包头部较小,减少网络传输的开销,提高了传输效率;
2:实时性更强,webwocket是全双工协议,服务器和客户端可以同时相互发送数据;
3:保持连接状态,websocket创建连接之后,会保持服务器和客户端的联系状态,之后通信可以省略部分状态信息。
效果展示
下面是use_one和user_two的聊天记录:
两个相互发送消息,消息内容会显示在聊天框
spring-boot后端
一: 依赖
在springboot的基础上引入websocket相关依赖
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
二: 重要代码
1:向springboot容器注入ServerEnpointExporter实例
该实例是spring集成websocket的重要内容,它可以将标注有@ServerEndpoint的类注册到websocket服务器中,从而让客户端可以正常访问到websocket服务器。
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
2:创建websocket服务器
在类上标注@ServerEnpoint(“/url”),需要注意的是不同的url会由不同的实例来维护,然后需要我们实现@OnOpen【开始链接】,@OnClose【结束链接】,@OnMessage【客户端向服务器发送消息】,@OnError【链接发生错误】注解的方法,这些方法参数会带有一个Session,我们可以将session保存起来,当需要向客户端发送信信息可以调用session.getBasicRemote().sendText(message);
@ServerEndpoint("/person/{userId}")
@Component
@Slf4j
public class WebSocketServer {
private static Map<String, WebSocketServer> SOCKET_MAP = new ConcurrentHashMap<>();
@Getter
private Session session;
@OnOpen
public void open(Session session, @PathParam("userId") String userId) {
this.session = session;
SOCKET_MAP.put(userId, this);
log.info("用户{}连接成功,当前链接总人数{}", userId, SOCKET_MAP.size());
}
@OnClose
public void close(Session session, @PathParam("userId") String userId) {
SOCKET_MAP.remove(userId);
log.info("用户{}断开连接,当前链接总人数{}", userId, SOCKET_MAP.size());
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到用户{}的消息:{}", session.getId(), message);
ChatEntityStr chatEntity = JSONObject.parseObject(message, ChatEntityStr.class);
WebSocketServer socketServer = SOCKET_MAP.get(chatEntity.getTo());
if (null == socketServer) {
//用户不在线
log.info("用户{}不在线", chatEntity.getTo());
return;
}
SendHelper.sendToPersonStr(message, socketServer.getSession());
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误:{}", session.getId());
error.printStackTrace();
}
}
html前端代码
这里写了两个html,one.html【代表user_one】,two.html【代表user_two】,下面仅展示了one.html,前端代码在项目目录下,one.html和two.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>简易聊天框</title>
<style type="text/css">
</style>
</head>
<body>
<div style="flex-direction: column">
<div>
<label>
<textarea rows="3" id="chatMsg" style="height: 500px;width: 500px;resize: none;"></textarea>
</label>
</div>
<div>
<label>
<input type="text" style="width: 400px" name="inputMsg" id="inputMsg" onkeyup="inputChange(this.value)">
<button type="button" onclick="sendMsg()">发送</button>
</label>
</div>
</div>
</body>
<script type="application/javascript">
/**
* 一般情况下,只需要改动self,other,websocket服务器地址即可使用
*/
const self = "user_one";
const other = "user_two";
const message = {attr: ""};
const input = document.getElementById("inputMsg");
const chatMsg = document.getElementById("chatMsg");
let websocket = {
send: function (str) {
}
};
window.onload = function () {
if (!'WebSocket' in window) return;
webSocketInit();
};
//初始化websocket
function webSocketInit() {
websocket = new WebSocket("ws://127.0.0.1:7777/person/" + self);
//成功建立连接
websocket.onopen = function () {
linkSuccess(self, self, "链接成功");
};
//接收到消息
websocket.onmessage = function (event) {
const data = JSON.parse(event.data);
chatMsg.value = chatMsg.value + data.from + " >>> " + data.message + "\n";
};
//连接发生错误
websocket.onerror = function () {
alert("WebSocket连接发生错误");
};
//连接关闭
websocket.onclose = function () {
alert("WebSocket连接关闭");
};
//监听窗口关闭事件,当窗口关闭时,主动关闭websocket连接
window.onbeforeunload = function () {
websocket.close()
};
}
//对message.attr进行绑定
Object.defineProperty(message, "attr", {
configurable: true,
enumerable: true,
set: function (newValue) {
attr = newValue;
input.value = newValue
},
get: function () {
return attr;
},
});
function inputChange(newValue) {
message.attr = newValue
if (event.keyCode === 13 &&
message.attr !== undefined && message.attr !== null && message.attr.length > 0) {
sendMsg();
}
}
//发送消息
function sendMsg() {
if (message.attr.length <= 0) {
return
}
const msg = {
from: self,
to: other,
createTime: new Date(),
message: message.attr
};
chatMsg.value = chatMsg.value + msg.from + " >>> " + msg.message + "\n";
websocket.send(JSON.stringify(msg))
message.attr = ""
}
//链接成功
function linkSuccess(from, to, msg) {
const successMsg = {
from: from,
to: to,
createTime: new Date(),
message: msg
};
websocket.send(JSON.stringify(successMsg))
}
</script>
</html>
资源地址
项目地址:https://gitee.com/ryfz-git/springboot-websocket.git
结语
共同学习,共同进步,欢迎交流。