java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot跟JavaScript简单websocket使用

springboot项目跟JavaScript简单websocket使用方式

作者:心之语歌

WebSocket是一种实现客户端与服务器全双工通信的协议,它提供了低延迟和双向数据传输,适用于实时应用,通过Java的Spring框架轻松集成WebSocket,实现服务器端与客户端的实时通信

websocket 简绍

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 的优势包括

创建更丰富的交互体验:实时更新数据的能力,使得应用能够更加流畅地响应用户的动作

可以通过 JavaScript 的 WebSocket 对象来创建一个 WebSocket 连接。

var ws = new WebSocket('ws://localhost:8080');

JavaScript 设置

处理事件

WebSocket 对象提供了几个事件处理器来处理连接的状态变化:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Example</title>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const socket = new WebSocket('ws://localhost:8080/websocket');

            socket.onopen = function (event) {
                console.log('WebSocket connection established.');
            };

            socket.onmessage = function (event) {
                console.log('Received from server:', event.data);
            };

            socket.onclose = function (event) {
                console.log('WebSocket connection closed.');
            };

            socket.onerror = function (error) {
                console.error('WebSocket error:', error);
            };

            function sendMessage() {
                let message = document.getElementById('message').value;
                socket.send(message);
                console.log('Sent message:', message);
            }
        });
    </script>
</head>
<body>
    <input type="text" id="message" placeholder="Type your message here">
    <button onclick="sendMessage()">Send Message</button>
</body>
</html>

确保你的服务器端已正确配置,并且能够接收来自客户端的连接请求。

使用HTTPS和WSS(加密的WebSocket)可以提高安全性,特别是在生产环境中。

如果你的服务器部署在不同的域上,请确保服务器配置允许跨域访问。

Java 服务端设置

导jar包

通过 maven 导入 spring boot 中 集成的 websocket jar 包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

创建WebSocket端点

@EnableWebSocket

@EnableWebSocket 是 Spring 框架中的一个注解,用于启用 WebSocket 支持。当一个类被标记为此注解时,Spring 会自动配置必要的组件来处理 WebSocket 请求。这个注解通常应用在一个配置类上,该类负责设置 WebSocket 的处理逻辑。

registerWebSocketHandlers

接下来,定义一个WebSocket处理器类,并配置一个端点来接受WebSocket连接:

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

    private final WebSocketHandler webSocketHandler;

    public WebSocketConfig(WebSocketHandler webSocketHandler) {
        this.webSocketHandler = webSocketHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler, "/websocket").setAllowedOrigins("*");
    }
}

这里我们定义了一个WebSocket配置类,并注册了WebSocket处理器。/websocket 是WebSocket的端点路径。

实现WebSocket处理器

afterConnectionEstablished

void afterConnectionEstablished(WebSocketSession session) throws Exception;

afterConnectionClosed

void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception;

handleTextMessage

void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception;
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.util.concurrent.ConcurrentHashMap;

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.util.concurrent.ConcurrentHashMap;

public class WebSocketHandler extends TextWebSocketHandler {

    private static final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
		public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
        String id = session.getId();
        sessions.put(id, session);
        System.out.println("WebSocket connection established with session ID: " + id);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        String id = session.getId();
        sessions.remove(id);
        System.out.println("WebSocket connection closed with session ID: " + id);
    }

    public void sendMessageToSession(String sessionId, String message) {
        WebSocketSession session = sessions.get(sessionId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void broadcastMessage(String message) {
        for (WebSocketSession session : sessions.values()) {
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(message));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

现在我们可以使用WebSocketHandler类中的sendMessageToSession或broadcastMessage方法来发送数据给前端。

发送给特定会话:如果想要向特定的客户端发送消息,可以使用sendMessageToSession方法。你需要知道客户端的会话ID。

webSocketHandler.sendMessageToSession(sessionId, "Hello, client!");

广播消息:如果你想向所有已连接的客户端广播消息,可以使用broadcastMessage方法

webSocketHandler.broadcastMessage("Hello, everyone!")

注销WebSocket连接

要在Java后端注销WebSocket连接,可以通过调用 WebSocketHandler 类中的 removeSession 方法来实现。例如,你可以从HTTP请求或其他服务中调用此方法:

@GetMapping("/logout/{sessionId}")
public ResponseEntity<String> logout(@PathVariable String sessionId) {
    WebSocketHandler handler = new WebSocketHandler(); // 或者通过依赖注入获取
    handler.removeSession(sessionId);
    return ResponseEntity.ok("Session " + sessionId + " has been closed.");
}

自己定义一个 固定id 方便使用

前端 JavaScript 代码

后端 Java 代码

前端 javascript

<!DOCTYPE html>
<html l	ang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket Client Example</title>
</head>
<body>
    <input type="text" id="messageInput" placeholder="Enter your message here">
    <button id="sendButton">Send Message</button>
    <div id="log"></div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const socket = new WebSocket('ws://example.com/websocket');

            socket.onopen = function (event) {
                console.log('WebSocket connection established.');

                // 固定的客户端ID
                const clientId = 'client-123';

                // 发送握手消息
                socket.send(JSON.stringify({
                    type: 'handshake',
                    clientId: clientId,
                    message: 'Hello, server!'
                }));
            };

            socket.onmessage = function (event) {
                console.log('Received from server:', event.data);
                document.getElementById('log').textContent += 'Received from server: ' + event.data + '\n';
            };

            socket.onclose = function (event) {
                console.log('WebSocket connection closed.');
                document.getElementById('log').textContent += 'WebSocket connection closed.\n';
            };

            socket.onerror = function (error) {
                console.error('WebSocket error:', error);
                document.getElementById('log').textContent += 'WebSocket error: ' + error + '\n';
            };

            document.getElementById('sendButton').addEventListener('click', function () {
                let message = document.getElementById('messageInput').value;
                if (socket.readyState === WebSocket.OPEN) {
                    socket.send(message);
                    document.getElementById('log').textContent += 'Sent message: ' + message + '\n';
                } else {
                    alert('WebSocket connection is not open.');
                }
            });
        });
    </script>
</body>
</html>

java 服务器端配置

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.socket.HandshakeMessage;
import org.springframework.stereotype.Component;
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.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebSocketHandler extends TextWebSocketHandler {

    private static final Map<String, WebSocketSession> clientSessions = new ConcurrentHashMap<>();
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
        String sessionId = session.getId();
        System.out.println("WebSocket connection established with session ID: " + sessionId);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        HandshakeMessage handshakeMessage = objectMapper.readValue(payload, HandshakeMessage.class);

        if ("handshake".equals(handshakeMessage.getType())) {
            String clientId = handshakeMessage.getClientId();
            String sessionId = session.getId();

            // 存储clientId与sessionId的映射关系
            clientSessions.put(clientId, session);

            // 可以选择回复客户端确认握手成功的消息
            session.sendMessage(new TextMessage("Handshake successful"));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        String sessionId = session.getId();
        System.out.println("WebSocket connection closed with session ID: " + sessionId);

        // 移除会话
        clientSessions.values().removeIf(s -> s.getId().equals(sessionId));
    }

    public void sendMessageToClient(String clientId, String message) {
        WebSocketSession session = clientSessions.get(clientId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new TextMessage(message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 定义握手消息模型
    private static class HandshakeMessage {
        private String type;
        private String clientId;
        private String message;

        // Getters and setters
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文