SpringBoot集成WebSocket
1、导包
在pom.xml中引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、新增WebSocketConfig配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Description: WebSocket配置类。开启WebSocket的支持
* @Author: mzq
* @date: 2024-10-29
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
注意:
即使导包后也可能会出现
import org.springframework.web.socket.server.standard.ServerEndpointExporter;找不到和
ServerEndpointExporter找不到的问题
解决方法:
进入阿里云maven仓库,找到对应maven手动下载并手动导入依赖
3、配置WebSocketServer服务
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* WebSocket服务器类,用于处理WebSocket连接、消息、错误等事件。
*
* @author mzq
* @date 2024-10-29
*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServer {
// 记录当前在线客户端的数量
private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
// 存储在线会话的映射表
private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();
// 当前连接的标识符
private String sid;
// 当前会话对象
private Session session;
/**
* 当WebSocket连接打开时调用的方法。
* @param sid 客户端的唯一标识符
* @param session 当前WebSocket会话
*/
@OnOpen
public void onOpen(@PathParam("sid") String sid, Session session) {
log.info("连接建立中 ==> session_id = {}, sid = {}", session.getId(), sid);
// 将当前会话添加到在线会话映射表中
onlineSessionClientMap.put(sid, session);
// 在线数量+1
onlineSessionClientCount.incrementAndGet();
// 设置当前连接的标识符及会话
this.sid = sid;
this.session = session;
// 发送消息给当前连接
sendToOne(sid, "连接成功");
// 输出当前在线数量以及连接信息
log.info("连接建立成功,当前在线数为:{} ==> 开始监听新连接:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), sid);
}
/**
* 当WebSocket连接关闭时调用的方法。
* @param sid 客户端的唯一标识符
* @param session 当前WebSocket会话
*/
@OnClose
public void onClose(@PathParam("sid") String sid, Session session) {
// 移除当前会话
onlineSessionClientMap.remove(sid);
// 在线数量-1
onlineSessionClientCount.decrementAndGet();
// 输出当前在线数量以及关闭的连接信息
log.info("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), sid);
}
/**
* 当从客户端接收到消息时调用的方法。
* @param message 接收到的消息
* @param session 当前WebSocket会话
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("服务端收到客户端消息 ==> fromSid = {}, message = {}", sid, message);
}
/**
* 当WebSocket发生错误时调用的方法。
* @param session 当前WebSocket会话
* @param error 错误信息
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("WebSocket发生错误,错误信息为:" + error.getMessage());
error.printStackTrace();
}
/**
* 向所有在线客户端发送消息。
* @param message 要发送的消息
*/
public void sendToAll(String message) {
// 遍历在线会话映射表
onlineSessionClientMap.forEach((onlineSid, toSession) -> {
try {
log.info("服务端给客户端群发消息 ==> toSid = {}, message = {}", onlineSid, message);
toSession.getAsyncRemote().sendText(message);
} catch (Exception e) {
log.error("发送消息给客户端时发生错误:{}", onlineSid, e);
onlineSessionClientMap.remove(onlineSid);
}
});
}
/**
* 向单个客户端发送消息。
* @param toSid 目标客户端的唯一标识符
* @param message 要发送的消息
*/
public void sendToOne(String toSid, String message) {
Session toSession = onlineSessionClientMap.get(toSid);
if (toSession == null) {
log.error("服务端给客户端发送消息 ==> toSid = {} 不存在, message = {}", toSid, message);
return;
}
// 使用异步方式发送消息
log.info("服务端给客户端发送消息 ==> toSid = {}, message = {}", toSid, message);
toSession.getAsyncRemote().sendText(message);
// 下面是同步发送消息的备用方法
// try {
// toSession.getBasicRemote().sendText(message);
// } catch (IOException e) {
// log.error("发送消息失败,WebSocket IO异常");
// e.printStackTrace();
// }
}
}
4、服务测试
此时可启动对应服务,使用WebSocket在线测试工具进行测试
5、前端配置
// 创建WebSocket URL并为每个会话附加随机字符串作为ids
const getRandomString = length => [...Array(length)].map(() => Math.floor(Math.random() * 36).toString(36)).join('');
let ws;
//在onMounted中挂载WebSocket
onMounted(() => {
const ws_url = `ws://127.0.0.1:9406/websocket/${getRandomString(8)}`;
console.log('----------WebSocket连接地址----------',ws_url);
ws = new WebSocket(ws_url);
ws.onopen = function () {
console.log('----------WebSocket连接成功----------');
};
ws.onmessage = function (event) {
console.log('收到服务器消息:', event.data);
const webSocketData = JSON.parse(event.data);
console.log('----------解析后的数据:----------' , webSocketData)
}
});
//关闭页面时销毁WebSocket
onUnmounted(() => {
ws.close();
console.log('----------WebSocket连接已关闭----------');
});
6、部署服务器端
1、 在 nacos 中网关部分增加配置
#这里以pmccsoft-heatingbusinesspro服务为例
- id: pmccsoft-heatingbusinesspro-websocket
uri: lb:ws://pmccsoft-heatingbusinesspro
predicates:
- Path=/websocket/**
注意配置中不要添加以下内容
filters:
- StripPrefix=1
不需要鉴权配置则在网关最后添加白名单,例如:
security:
ignore:
whites:
- /websocket/**
前端连接请求地址
const ws_url = `ws://127.18.177.208:8080/websocket/${getRandomString(8)}`

浙公网安备 33010602011771号