WebSocketServer的目的是为了实时推送数据到客户端,才使用webSocket的双全工的方式
spring简单实现有两种方式
在Spring框架中配置WebSocket服务器时,您可以选择使用WebSocketConfigurer接口或者通过@ServerEndpoint注解配合ServerEndpointExporter bean来配置WebSocket端点。这两种方式各有优缺点,适用于不同的场景。
优点:
缺点:
学习曲线: 需要熟悉Spring WebSocket的配置和使用方式。
优点:
缺点:
然而,如果您的项目比较简单,或者您更熟悉Java EE WebSocket API的标准实现方式,并且不需要与Spring框架进行深度集成,那么使用@ServerEndpoint注解和ServerEndpointExporter也是一种可行的选择。
springBoot项目需要引入spring的webSocket依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
配置类
java
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
webSocket服务
java
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* webSocket服务器
*/
@ServerEndpoint("/websocket/rob")
@Component
@Slf4j
public class WsRobServer {
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全集合,也可以map改成set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static CopyOnWriteArrayList<WsRobServer> webSocketList = new CopyOnWriteArrayList<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
if (!webSocketList.contains(session)) {
//加入集合中
webSocketList.add(this);
//在线数加1
WsRobServer.onlineCount++;
}
log.info("当前连接人数为:" + onlineCount);
try {
//socket客户端链接到服务器就立即发送一次机器人信息
sendMessage(JSON.toJSONString(WsRobClient.wsRobInfos));
} catch (IOException e) {
log.error("网络异常!!!!!!");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if (webSocketList.contains(this)) {
webSocketList.remove(this);
//从集合中删除
WsRobServer.onlineCount--;
}
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException {
log.info("收到客户端发来的消息:" + message);
//通过消息类型返回对应的消息
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("链接关闭,原因:" + error.getMessage());
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发消息
*/
public static void sendsInfo(String message) {
log.info("开始群发消息!");
if (CollUtil.isEmpty(webSocketList)) {
log.error("没有用户在线,不需要发送!");
} else {
for (WsRobServer server : webSocketList) {
if (server != null) {
try {
server.sendMessage(message); // 调用 WebSocket 的 sendMessage 方法发送消息
} catch (IOException e) {
log.error("消息发送失败!");
e.printStackTrace();
}
}
}
}
}
}
端点配置WebSocketConfig
javaimport org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册一个 /notification 端点
// registry.addHandler(new MyWebSocketHandler(), "/notification")
// .setAllowedOrigins("*");
// 注册另一个 /chat 端点
registry.addHandler(new MyWebSocketHandler(), "/chat")
.setAllowedOrigins("*");
// 注册第三个 /updates 端点
registry.addHandler(new MyWebSocketHandler(), "/updates")
.setAllowedOrigins("*");
}
}
MyWebSocketHandler编写
javaimport org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final Logger logger = LoggerFactory.getLogger(StairLiftSocketHandler.class);
private static CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
/**
* 在WebSocket连接建立后调用
* 该方法用于处理连接建立后的操作,主要是将当前会话添加到会话列表中,并记录日志
*
* @param session 当前的WebSocket会话
* @throws Exception 如果处理过程中发生异常,则抛出异常
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
logger.info("新的用户加入,session id: {} ,当前用户数:{}", session.getId(),sessions.size());
}
/**
* 发送消息给所有活动的WebSocket会话
*
* @param msg 要发送的消息内容
*/
public static void sendMsg(String msg) {
// 如果sessions集合不为空
if (!sessions.isEmpty()) {
// 筛选并遍历所有打开状态的会话
sessions.stream()
.filter(WebSocketSession::isOpen)
.forEach(session -> {
try {
// 尝试发送消息
session.sendMessage(new TextMessage(msg));
} catch (IOException e) {
// 捕获并记录发送消息时可能发生的IO异常
logger.error("发送消息失败,session Id: {}, 异常信息: {}", session.getId(), e.getMessage(), e);
}
});
}
}
/**
* 处理文本消息
* 当通过WebSocket接收到文本消息时,此方法将被调用
*
* @param session WebSocket会话对象,表示与客户端的连接
* @param message 文本消息对象,包含从客户端接收到的消息内容
* @throws Exception 如果处理过程中出现异常,将被抛出
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
logger.info("记录接收到的消息: {} ,session Id: {}", payload, session.getId());
}
/**
* 在WebSocket连接关闭后调用此方法
* 主要用于清理会话以及记录关闭状态
*
* @param session 关闭的WebSocket会话
* @param status 会话关闭的状态
* @throws Exception 抛出异常,但具体类型未指定
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// 从会话集合中移除关闭的会话
sessions.remove(session);
// 记录会话移除的信息,包括会话ID和关闭状态
logger.info("会话移除, session Id: {}, 关闭状态: {}", session.getId(), status);
}
/**
* 处理传输错误
* 当与客户端的WebSocket连接出现传输错误时,此方法将被调用
* 它记录错误信息,并关闭WebSocket会话
*
* @param session 发生错误的WebSocket会话
* @param exception 引发的异常
* @throws Exception 如果在关闭会话过程中发生错误,可能会抛出异常
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
// 记录传输错误的日志,包括会话ID和异常信息
logger.error("Transport error for session: {}, exception: {}", session.getId(), exception.getMessage(), exception);
// 关闭发生错误的WebSocket会话,指定关闭状态为服务器错误
session.close(CloseStatus.SERVER_ERROR);
}
}
不同的端口需要编写不同的MyWebSocketHandler,不然发送消息时只要是通过这三个端点接入的session的都会收到消息的推送。
本文作者:Weee
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!