springboot WebSocket的用法

发布于:2024-04-27 ⋅ 阅读:(23) ⋅ 点赞:(0)

Spring Boot中使用Java API创建WebSocket

添加WebSocket的依赖项
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建WebSocket端点
 import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
    // 连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connected to client, session ID: " + session.getId());
    }
    // 连接关闭调用的方法
    @OnClose
    public void onClose() {
        System.out.println("Connection closed");
    }
    // 收到客户端消息后调用的方法
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Message from client: " + message);
        // 回送消息
        session.getAsyncRemote().sendText("Hello, I got your message: " + message);
    }
    // 发生错误时调用
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("Error occurred");
        error.printStackTrace();
    }
}
配置WebSocket
 import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

优化:支持用户UID来保存WebSocket会话

import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/websocket/{uid}")
@Component
public class WebSocketServer {
    // 使用ConcurrentHashMap来存储用户ID和WebSocket会话对象的映射。
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    @OnOpen
    public void onOpen(@PathParam("uid") String uid, Session session) {
        // 将新建立的会话添加到webSocketMap中
        webSocketMap.put(uid, this);
        // 其他代码...
    }
    @OnClose
    public void onClose(@PathParam("uid") String uid, Session session) {
        // 当会话关闭时,从webSocketMap中移除该会话
        webSocketMap.remove(uid);
        // 其他代码...
    }
    // ...其它方法如onMessage等等
}

优化:建立webscoket连接后,每隔15秒定时发送消息

@ServerEndpoint(value = "/websocket/{uid}")
@Component
public class DevAlarmMessageHandleController {

    private static final Logger logger = LoggerFactory.getLogger(DevAlarmMessageHandleController.class);
    
    private static final ScheduledExecutorService scheduler =
            Executors.newScheduledThreadPool(10); // 支持多个任务并发执行
    private Map<Session, Future<?>> futures = new ConcurrentHashMap<>();
    
    // 使用ConcurrentHashMap来存储用户ID和WebSocket会话对象的映射。
    private static ConcurrentHashMap<String, DevAlarmMessageHandleController> webSocketMap = new ConcurrentHashMap<>();
    @OnOpen
    public void onOpen(@PathParam("uuid") String uuid,  Session session) {
        logger.info("uuid: {}, sessionId: {}" , uuid, session.getId());
        // 将新建立的会话添加到webSocketMap中
        webSocketMap.put(uuid, this);
        // 调用 scheduleAtFixedRate方法时,返回一个Future对象
        Future<?> future =  scheduler.scheduleAtFixedRate(() -> sendMessage(session), 0, 15, TimeUnit.SECONDS);
        futures.put(session, future);
    }

    @OnClose
    public void onClose(@PathParam("uuid") String uuid, Session session) {
        logger.info("uuid: {}, sessionId: {}" , uuid, session.getId());
        // 当会话关闭时,从webSocketMap中移除该会话
        webSocketMap.remove(uuid);
        Future<?> future = futures.remove(session);
        if (future != null) {
            future.cancel(false); // 参数决定是否中断正在执行的任务
        }
        // 其他代码...
    }

    // 收到客户端消息后调用的方法
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("Message from client: " + message);
        // 回送消息
        session.getAsyncRemote().sendText("Hello, I got your message: " + message);
    }

    // 发生错误时调用
    @OnError
    public void onError(Session session, Throwable error) {
        logger.info("Error occurred");
        error.printStackTrace();
    }

    public void sendMessage(Session session){
        session.getAsyncRemote().sendText("current: " + LocalDateTime.now());
    }
}

问题

wss://127.0.0.1:8080/websocket/与ws://127.0.0.1:8080/websocket/的区别

区别在于它们使用的协议不同。“wss”代表WebSocket Secure,它是WebSocket的安全版本,意味着数据传输是加密的,类似于HTTPS在HTTP上增加了安全层。而“ws”则是普通的WebSocket协议,不提供加密,类似于HTTP。简单来说,使用“wss”协议可以更安全地保护数据传输不被监听和篡改。在生产环境中,建议使用“wss”协议以确保安全性。如果你的服务部署在了安全环境中,有时候也被称为是在使用WebSocket over TLS(传输层安全)。

getBasicRemote()和getAsyncRemote()的区别
getBasicRemote()

用 getBasicRemote().sendText(message) 发送消息时,这个调用是阻塞的。这意味着,在消息发送完成之前,代码的执行将会暂停。简单,但是当发送大量消息或者处理多个客户端时可能会影响性能。

getAsyncRemote()

使用 getAsyncRemote().sendText(message) 发送消息时,调用将立即返回,而消息的发送则由另一个线程异步处理。提高了消息发送的效率,允许应用程序同时执行其他任务。异步发送是处理高并发环境或发送大量消息时的理想选择,因为getAsyncRemote().sendText(message) 不会阻塞当前线程。


网站公告

今日签到

点亮在社区的每一天
去签到