在 web 开发中,websocket 为客户端和服务端之间提供了实时双向通信的能力。本篇博客介绍如何使用 spring boot 快速搭建一个 websocket 服务器,并支持多客户端的连接和消息广播。
1. websocket 简介
websocket 是 html5 的一种协议,提供了客户端和服务器之间的全双工通信。通过 websocket,客户端可以与服务器进行持续连接,不用反复建立 http 请求,从而降低延迟,提升通信效率。
为什么选择 spring boot 实现 websocket?
spring boot 简化了 websocket 服务器的配置与实现,使我们可以更专注于业务逻辑开发,且配合 @serverendpoint 注解实现更加清晰。
2. 项目环境与依赖配置
项目环境
- java 版本:jdk 8+
- spring boot 版本:2.x
- websocket 依赖:
spring-boot-starter-websocket
maven 依赖
在 pom.xml 文件中添加 websocket 的依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>3. websocket 服务端代码实现
在 spring boot 中,我们可以使用 @serverendpoint 注解创建 websocket 服务器端。以下是一个支持多客户端连接的 websocket 实现。
websocket 服务端代码解析
创建 multiclientwebsocket 类,并实现以下功能:
- 记录当前在线客户端数
- 支持客户端连接、断开、消息接收、群发等功能
- 通过
@onopen、@onmessage、@onclose、@onerror注解处理连接的各个生命周期
完整代码如下:
import lombok.extern.slf4j.slf4j;
import org.springframework.context.annotation.bean;
import org.springframework.stereotype.component;
import org.springframework.web.socket.server.standard.serverendpointexporter;
import javax.websocket.*;
import javax.websocket.server.serverendpoint;
import java.io.ioexception;
import java.util.map;
import java.util.concurrent.concurrenthashmap;
import java.util.concurrent.atomic.atomicinteger;
/**
* websocketconfig
*/
@component
@serverendpoint("/ws/multi")
@slf4j
public class multiclientwebsocket {
@bean
public serverendpointexporter serverendpointexporter() {
log.info("websocketconfig: serverendpointexporter init websocketconfig 注入完成");
return new serverendpointexporter();
}
/**
* 记录当前在线连接数
*/
private static final atomicinteger onlinecount = new atomicinteger(0);
/**
* 存放所有在线的客户端
*/
private static final map<string, session> onlineclients = new concurrenthashmap<>();
@onopen
public void onopen(session session) {
onlinecount.incrementandget();
onlineclients.put(session.getid(), session);
log.info("有新连接加入:{},当前在线客户端数为:{}", session.getid(), onlinecount.get());
}
@onmessage
public void onmessage(string message, session session) throws ioexception {
system.out.println("收到客户端消息:" + message);
session.getbasicremote().sendtext("服务器收到消息:" + message);
}
@onclose
public void onclose(session session) {
onlinecount.decrementandget(); // 在线数减1
onlineclients.remove(session.getid());
log.info("有一连接关闭:{},当前在线客户端数为:{}", session.getid(), onlinecount.get());
}
@onerror
public void onerror(throwable t) {
log.error("websocket 连接出错{}", t.getmessage());
}
/**
* 群发消息
*
* @param message 消息内容
*/
public void sendmessage(string message) {
//log.info("开始给在线的客户端{}群发消息{}",onlineclients,message);
for (map.entry<string, session> sessionentry : onlineclients.entryset()) {
session tosession = sessionentry.getvalue();
log.info("服务端给客户端[{}]发送消息{}", tosession.getid(), message);
tosession.getasyncremote().sendtext(message);
}
}
}代码解析
serverendpointexporter:spring boot 的 websocket 配置类,自动注册@serverendpoint注解声明的 websocket。- 在线客户端管理:使用
concurrenthashmap存储在线客户端的session,通过atomicinteger记录当前连接数。 - 生命周期注解:
@onopen:当客户端连接时触发,增加在线人数。@onmessage:当收到消息时触发,服务端处理消息。@onclose:当连接关闭时触发,减少在线人数。@onerror:当连接出错时触发,记录错误日志。
- 群发消息:
sendmessage方法遍历所有在线客户端的session,实现消息广播。
4. 启动与测试
启动 spring boot 项目后,websocket 服务端地址为:ws://localhost:8080/ws/multi。可以使用 websocket 测试工具(例如 apifox或浏览器控制台)测试 websocket 通信。
测试步骤
- 连接 websocket:客户端连接至
ws://localhost:8080/ws/multi。 - 发送消息:客户端发送消息,服务端接收到消息后回复。
- 断开连接:客户端断开连接,服务端记录连接关闭信息。
import cn.hutool.json.jsonutil;
import com.google.common.collect.lists;
import com.lps.config.multiclientwebsocket;
import com.lps.domain.r;
import lombok.requiredargsconstructor;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
import java.util.list;
/**
* @classname: websocketcontrol
* @description:
* @author: liu
* @date: 2024-10-30
* @version: 1.0
**/
@restcontroller
@requestmapping("/websocket")
@requiredargsconstructor
public class websocketcontrol {
private final multiclientwebsocket multiclientwebsocket;
@getmapping("/sendlist")
public r<string> sad() {
//guava依赖
list<string> strlist = lists.newarraylist("发送", "websocket消息","测试");
string jsonstr = jsonutil.tojsonstr(strlist);
multiclientwebsocket.sendmessage(jsonstr);
return r.ok(jsonstr);
}
}
前端测试demo
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>websocket demo</title>
<style>
#status {
margin-bottom: 10px;
}
</style>
<script>
let ws;
function connectwebsocket() {
// 检查 websocket 是否已连接
if (ws && ws.readystate === websocket.open) {
console.log('websocket 已连接,无需重复连接。');
return;
}
ws = new websocket('ws://localhost:8080/ws/multi');
ws.onopen = function() {
console.log('websocket 连接已经建立。');
document.getelementbyid('status').innertext = 'websocket 连接已建立。';
ws.send('hello, server!');
};
ws.onmessage = function(event) {
console.log('收到服务器消息:', event.data);
document.getelementbyid('messages').innertext += '收到消息:' + event.data + '\n';
};
ws.onerror = function(event) {
console.error('websocket 连接出现错误:', event);
document.getelementbyid('status').innertext = 'websocket 连接出现错误。';
};
ws.onclose = function() {
console.log('websocket 连接已经关闭。');
document.getelementbyid('status').innertext = 'websocket 连接已关闭。';
ws = null; // 连接关闭后将 ws 设置为 null,以便重新连接
};
}
function disconnectwebsocket() {
if (ws) {
ws.close();
}
}
</script>
</head>
<body>
<h1>websocket demo</h1>
<div id="status">websocket 连接状态</div>
<button onclick="connectwebsocket()">连接 websocket</button>
<button onclick="disconnectwebsocket()">断开 websocket</button>
<pre id="messages"></pre>
</body>
</html>5. 总结
通过以上代码示例,我们可以实现一个简单的 websocket 服务端,支持多客户端连接和消息广播。此 websocket 服务端适用于需要实时消息推送的应用场景,比如聊天室、实时通知系统等。
到此这篇关于使用 spring boot 搭建 websocket 服务器实现多客户端连接的文章就介绍到这了,更多相关spring boot 搭建 websocket 服务器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论