③. SpringBoot集成WebSocket实现在线群聊
1. 什么是WebSocket?
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
2. WebSocket和传统HTTP请求的对比
WebSocket的特点:
- 建立在TCP协议之上,服务端的实现比较容易。
- 握手的时候采用HTTP协议,具有良好的兼容性。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是ws。如果加密,就为wss
客户端主要的API
- 创建WebSocket
new WebSocket("ws://182.92.157.212:8085/websocket/2");
相关监听事件
//打开事件
index.onopen = function () {
console.log("Socket 已打开");
socket = index;
};
//获得消息事件
index.onmessage = function (msg) {
var textInner = document.getElementById("text-inner");
var old = textInner.value;
old += "\r\n";
old += msg.data;
console.log(old);
document.getElementById("text-inner").value = old;
};
//关闭事件
index.onclose = function () {
console.log("Socket已关闭");
};
//发生了错误事件
index.onerror = function () {
alert("Socket发生了错误");
//此时可以尝试刷新页面
}
- 向服务端发送数
socket.send(msg);
4. 服务端配置
导入Maven依赖(前提是SpringBoot的web工程)
<!-- 添加我们websocket的依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
书写WebSocketConfig配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
书写WebSocketServer,响应前端页面消息的类
@ServerEndpoint("/websocket/{sid}")
@Component
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
// private static ConcurrentHashMap<Integer,Session> webSocketSetSession = new ConcurrentHashMap<>(;)
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//接收sid
private String sid="";
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());
this.sid=sid;
try {
sendMessage("连接成功");
} catch (IOException e) {
System.out.println("websocket IO异常");
}
}
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到来自窗口"+sid+"的信息:"+message);
//群发消息
for (WebSocketServer item : webSocketSet) {
try {
// 进行群发送,接收到消息,进行一个群发送。
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {
System.out.println("推送消息到窗口"+sid+",推送内容:"+message);
for (WebSocketServer item : webSocketSet) {
try {
//这里可以设定只推送给这个sid的,为null则全部推送
if(sid==null) {
item.sendMessage(message);
}else if(item.sid.equals(sid)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
return webSocketSet;
}
}
进行相关访问即可。
附录:前端完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"></meta>
<title>Title</title>
<style>
div{
width: 1280px;
text-align: center;
}
#text-inner{
width: 500px;
height: 200px;
margin: 0 auto;
}
</style>
</head>
<body>
<div>
<h2>在线聊天实例(测试)</h2>
<textarea id="text-inner">
</textarea>
<br>
<input type="text" id="msg" placeholder="请输入你要发送的内容!">
<br>
<button id="send-message">点击发送</button>
</div>
</body>
<script>
var socket;
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
//等同于
index = new WebSocket("ws://182.92.157.212:8085/websocket/2");
//打开事件
index.onopen = function () {
console.log("Socket 已打开");
socket = index;
};
//获得消息事件
index.onmessage = function (msg) {
var textInner = document.getElementById("text-inner");
var old = textInner.value;
old += "\r\n";
old += msg.data;
console.log(old);
document.getElementById("text-inner").value = old;
};
//关闭事件
index.onclose = function () {
console.log("Socket已关闭");
};
//发生了错误事件
index.onerror = function () {
alert("Socket发生了错误");
//此时可以尝试刷新页面
}
//离开页面时,关闭socket
//jquery1.8中已经被废弃,3.0中已经移除
// $(window).unload(function(){
// socket.close();
//});
}
document.getElementById("send-message").addEventListener("click",function () {
var msgElem = document.getElementById("msg");
var msg = msgElem.value;
socket.send(msg);
})
</script>
</html>