SpringBoot(WebSocket聊天室)

WebSocket 事件

Websocket 使用 ws 或 wss 的统⼀资源标志符,类似于 HTTPS,其中 wss 表示在 TLS 之上的 Websocket。

ws://example.com/wsapi
wss://secure.example.com/

Websocket 使用和 HTTP 相同的 TCP 端⼝口,可以绕过大多数防⽕墙的限制。默认情况下,Websocket 协议使用80 端口;运行在 TLS 之上时,默认使用 443 端口。、

事件事件处理理程序描述
openSokcket onopen连接建⽴立时触发
messageSokcket onopen客户端接收服务端数据时触发
errorSokcket onerror通讯发⽣生错误时触发
closeSokcket onclose链接关闭时触发

Spring Boot 提供了 Websocket 组件 spring-boot-starter-websocket,⽤来支持在 Spring Boot 环境下对Websocket 的使⽤。
下面是⼀个页面使用 Websocket 的示例:

var ws = new WebSocket("ws://localhost:8080");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};

Websocket 聊天室

  • ⽀持用户加入聊天室,对应到 Websocket 技术就是建⽴立连接 onopen
  • ⽀持用户退出聊天室,对应到 Websocket 技术就是关闭连接 onclose
  • ⽀持用户在聊天室发送消息,对应到 Websocket 技术就是调用 onmessage 发送消息
  • 支持异常时提示,对应到 Websocket 技术 onerror

⻚面开发

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>chat room websocket</title>
<link rel="stylesheet" href="bootstrap.min.css">
<script src="jquery-3.2.1.min.js" ></script>
</head>
<body class="container" style="width: 60%">
<div class="form-group" ></br>
<h5>聊天室</h5>
<textarea id="message_content" class="form-control" readonly="readonly" cols="50"
rows="10"></textarea>
</div>
<div class="form-group" >
<label for="in_user_name">⽤用户姓名 &nbsp;</label>
<input id="in_user_name" value="" class="form-control" /></br>
<button id="user_join" class="btn btn-success" >加⼊入聊天室</button>
<button id="user_exit" class="btn btn-warning" >离开聊天室</button>
</div>
<div class="form-group" >
<label for="in_room_msg" >群发消息 &nbsp;</label>
<input id="in_room_msg" value="" class="form-control" /></br>
<button id="user_send_all" class="btn btn-info" >发送消息</button>
</div>
</body>
</html>

接下来在页面添加 WebSocket 通讯代码:

<script type="text/javascript">
$(document).ready(function(){
var urlPrefix ='ws://localhost:8080/chat-room/';
var ws = null;
$('#user_join').click(function(){
var username = $('#in_user_name').val();
var url = urlPrefix + username;
ws = new WebSocket(url);
ws.onopen = function () {
console.log("建⽴立 websocket 连接...");
};
ws.onmessage = function(event){
//服务端发送的消息
$('#message_content').append(event.data+'\n');
};
ws.onclose = function(){
$('#message_content').append('⽤用户['+username+'] 已经离开聊天室!');
console.log("关闭 websocket 连接...");
}
});
//客户端发送消息到服务器器
$('#user_send_all').click(function(){
var msg = $('#in_room_msg').val();
if(ws){
ws.send(msg);
}
});
// 退出聊天室
$('#user_exit').click(function(){
if(ws){
ws.close();
}
});
})
</script>

服务端开发

引入依赖

<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>

启动类
启动类需要添加 @EnableWebSocket 开启 WebSocket 功能。

@EnableWebSocket
@SpringBootApplication
public class WebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(WebSocketApplication.class, args);
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

请求接收
在创建服务端消息接收功能之前,我们先创建一个 WebSocketUtils ⼯具类,⽤来存储聊天室在线的用户信息,以及发送消息的功能。首先定义一个全局变量ONLINE_USER_SESSIONS 用来存储在线⽤户,使⽤
ConcurrentHashMap 提升高并发时效率。

public static final Map<String, Session> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>
();

封装消息发送⽅法,在发送之前首先判单⽤户是否存在再进行发送:

public 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) {
logger.error("sendMessage IOException ",e);
}
}

聊天室的消息是所有在线用户可见,因此每次消息的触发实际上是遍历所有在线用户,给每个在线⽤户发送消息。

public static void sendMessageAll(String message) {
ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message))
;
}

这样我们在创建 ChatRoomServerEndpoint 类的时候就可以直接将⼯具类的方法和全局变量量导入:

import static com.neo.utils.WebSocketUtils.ONLINE_USER_SESSIONS;
import static com.neo.utils.WebSocketUtils.sendMessageAll;

接收类上需要添加 @ServerEndpoint("url") 代表监听此地址的 WebSocket 信息

@RestController
@ServerEndpoint("/chat-room/{username}")
public class ChatRoomServerEndpoint {
}

用户登录聊天室时,将⽤户信息添加到 ONLINE_USER_SESSIONS 中,同时通知聊天室中的人。

@OnOpen
public void openSession(@PathParam("username") String username, Session session) {
ONLINE_USER_SESSIONS.put(username, session);
String message = "欢迎用户[" + username + "] 来到聊天室!";
logger.info("用户登录:"+message);
sendMessageAll(message);
}

当聊天室某个用户发送消息时,将此消息同步给聊天室所有人。

@OnMessage
public void onMessage(@PathParam("username") String username, String message) {
logger.info("发送消息:"+message);
sendMessageAll("⽤户[" + username + "] : " + message);
}

当⽤户离开聊天室后,需要将⽤户信息从 ONLINE_USER_SESSIONS 移除,并且通知到在线的其他⽤户

@OnClose
public void onClose(@PathParam("username") String username, Session session) {
//当前的Session 移除
ONLINE_USER_SESSIONS.remove(username);
//并且通知其他⼈人当前用户已经离开聊天室了了
sendMessageAll("⽤户[" + username + "] 已经离开聊天室了了!");
try {
session.close();
} catch (IOException e) {
logger.error("onClose error",e);
}
}

其中,@OnClose 监听用户断开连接事件。

OnError
public void onError(Session session, Throwable throwable) {
try {
session.close();
} catch (IOException e) {
logger.error("onError excepiton",e);
}
logger.info("Throwable msg "+throwable.getMessage());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值