本文记录在SpringBoot中使用WebSocket。
一 什么是WebSocket
WebSocket是基于TCP协议的一种网络协议,它实现了浏览器与服务器全双工通信,支持客户端和服务端之间相互发送信息。在有WebSocket之前,如果服务端数据发生了改变,客户端想知道的话,只能采用定时轮询的方式去服务端获取,这种方式很大程度上增大了服务器端的压力,有了WebSocket之后,如果服务端数据发生改变,可以立即通知客户端,客户端就不用轮询去换取,降低了服务器的压力。目前主流的浏览器都已经支持WebSocket协议了。
WebSocket使用ws和wss作资源标志符,它们两个类似于http和https,wss是使用TSL的ws。主要有4个事件:
onopen 创建连接时触发
onclose 连接断开时触发
onmessage 接收到信息时触发
onerror 通讯异常时触发
二 简单使用示例
SpringBoot对WebSocket也做了支持,需要使用的话引入依赖所需要的包spring-boot-starter-websocket就可以了。我们利用它可以双向通信的特性来实现一个简单的聊天室功能。主要功能如下
1 用户在浏览器端进入聊天室(创建WebSocket连接);
2 用户端发送消息到服务端(客户端像服务端发信息);
3 服务端将消息转发到客户端(服务端向客户端发信息);
4 用户退出聊天室(断开WebSocket连接)。
修改pom.xml文件,引入WebSocket的支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
修改application.properties文件,配置服务相关信息
server.port=8090
server.servlet.context-path=/websocket
要使用WebSocket,我们需要在启动来开启对WebSocket的支持功能,使用@EnableWebSocket注解
@SpringBootApplication
@EnableWebSocket
public class WebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(WebSocketApplication.class, args);
}
/**
* 初始化Bean,它会自动注册使用了 @ServerEndpoint 注解声明的 WebSocket endpoint
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
聊天时,我们需要知道有哪些用户在线,所以我们创建一个工具类来记录在线用户和实现服务端向客户端发送消息
public class WebSocketUtil {
/**
* 模拟存储 在线用户
*/
public static final Map<String, Session> USERS_ONLINE = new ConcurrentHashMap<>();
/**
* 向所有在线用户发送消息(遍历 向每一个用户发送)
* @param message
*/
public static void sendMessageToAllOnlineUser(String message){
USERS_ONLINE.forEach((username, Session) -> sendMessage(Session, message));
}
/**
* 向指定用户发送消息
* @param session 用户session
* @param message 发送消息内容
*/
private static void sendMessage(Session session, String message) {
if (session == null) {
return;
}
final RemoteEndpoint.Basic basic = session.getBasicRemote();
if (basic == null) {
return;
}
try {
basic.sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端类,使用@ServerEndpoint("")说明服务端监听此地址的消息
@Controller
@ServerEndpoint("/chat/{username}") //说明创建websocket的endpoint
public class ChatServerEndpoint {
/**
* 访问聊天室页面
* @return
*/
@GetMapping("/chatPage")
public String chatPage(){
return "chat.html";
}
}
WebSocket有4个事件,我们对每个事件做监听,使用对应的注解即可实现监听
onopen 在连接创建(用户进入聊天室)时触发
@OnOpen
public void openSession(@PathParam("username") String username, Session session){
//存储用户
WebSocketUtil.USERS_ONLINE.put(username, session);
//向所有在线用户发送用户上线通知消息
String message = "["+username+"]进入聊天室";
System.out.println(message);
WebSocketUtil.sendMessageToAllOnlineUser(message);
}
onclose 在连接断开(用户离开聊天室)时触发
@OnClose
public void closeSession(@PathParam("username") String username, Session session){
//删除用户
WebSocketUtil.USERS_ONLINE.remove(username);
//向所有在线用户发送用户下线通知消息
String message = "["+username+"]离开了聊天室";
System.out.println(message);
WebSocketUtil.sendMessageToAllOnlineUser(message);
//下线后关闭session
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
onmessage 在接收到消息时触发
@OnMessage
public void onMessage(@PathParam("username") String username, String message){
//向聊天室中的人发送消息
message = "["+username+"]:" + message;
System.out.println(message);
WebSocketUtil.sendMessageToAllOnlineUser(message);
}
orerror 在连接发生异常时触发
@OnError
public void sessionError(Session session, Throwable throwable){
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("WebSocket连接发生异常,message:"+throwable.getMessage());
}
聊天室页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery-1.9.1.min.js"></script>
</head>
<body>
<table>
<tr><td>
<label for="messageArea">聊天信息:</label><textarea id="messageArea" cols="50" rows="30"></textarea></br>
</td></tr>
<tr><td>
<label for="username">用 户 名:</label><input type="text" id="username" ></br>
</td></tr>
<tr><td>
<input type="button" id="joinRoomBtn" value="进入聊天室" />
<input type="button" id="leaveRoomBtn" value="离开聊天室" /></br>
</td></tr>
<tr><td>
<label for="sendMessage">输入消息:</label><textarea id="sendMessage" cols="50" rows="3"></textarea></br>
</td></tr>
<tr><td>
<input type="button" id="sendBtn" value="发送消息" />
</td></tr>
</table>
</body>
</html>
WebSocket客户端连接服务端及相关事件方法
<script> $(function(){ var webSocket; var url = 'ws://localhost:8090/websocket/chat/'; //进入聊天室 $('#joinRoomBtn').click(function(){ var username = $('#username').val(); webSocket = new WebSocket(url+username); webSocket.onopen = function (){ console.log('webSocket连接创建。。。'); } webSocket.onclose = function(){ $('#messageArea').append('['+username+']离开了聊天室\n'); } webSocket.onmessage = function(event){ $('#messageArea').append(event.data + '\n'); } webSocket.onerror = function (event) {
console.log('webSocket连接异常。。。'); } }); //退出聊天室 $('#leaveRoomBtn').click(function(){ if(webSocket){ //关闭连接 webSocket.close(); } }); //发送消息 $('#sendBtn').click(function(){ var msg = $('#sendMessage').val(); webSocket.send(msg); $('#sendMessage').val(''); }); }); </script>
启动项目,访问聊天室页面,先输入用户名加入聊天室,再发送消息及退出聊天室,为了效果,打开两个浏览器,如下图