You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过main()方法部署Jakarta WebSocket @ServerEndpoint类

问题:如何通过Main.java启动Jakarta WebSocket服务器并部署端点

我在网上未找到Jakarta仓库中关于部署WebSocket端点的有效文档,端点不部署无法发挥作用。我已编写WebSocket服务器端点代码,但不知道如何通过Main.java启动监听,目标是像我的WebSocket客户端那样,用Main.java直接启动服务器。


现有WebSocket服务器端点代码

package com.wsserver;

import java.io.IOException;

import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;

@ServerEndpoint("/ws")
public class WebSocketEndpoint {

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("WebSocket opened: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Message received: " + message);
        try {
            session.getBasicRemote().sendText("Echo: " + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println("WebSocket closed: " + session.getId());
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("WebSocket error: " + session.getId());
        throwable.printStackTrace();
    }
}

现有Main.java代码(存在问题)

package com.wsserver;

import jakarta.websocket.ContainerProvider;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.Session;
import jakarta.websocket.WebSocketContainer;
import jakarta.websocket.server.ServerEndpoint;
import jakarta.websocket.server.ServerEndpointConfig;

import java.net.URI;
import java.net.http.WebSocket;

@ServerEndpoint("/ws")
public class Main {
    
    public static void main(String[] args) throws Exception {
        ServerEndpointConfig serverEndpoint = ServerEndpointConfig.Builder.create(WebsocketEndpoint.class, "/pathToRoot/").build();
    }
}

服务器pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wsserver</groupId>
    <artifactId>server</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Jackson相关 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.18.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.18.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.18.2</version>
        </dependency>

        <!-- Jakarta WebSocket API -->
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-api</artifactId>
            <version>2.2.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.11.0</version>
        </dependency>

        <!-- Jakarta WebSocket Client API -->
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-client-api</artifactId>
            <version>2.2.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Tyrus Standalone Client -->
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!-- JSON -->
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20241224</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>9.1.0</version>
        </dependency>
    </dependencies>
</project>

可正常运行的WebSocket客户端代码

客户端端点代码

package com.wsclient;

import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;

import jakarta.websocket.ClientEndpoint;
import jakarta.websocket.CloseReason;
import jakarta.websocket.ContainerProvider;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.WebSocketContainer;

@ClientEndpoint
public class WebsocketClientEndpoint {

    Session userSession = null;
    private MessageHandler messageHandler;

    public WebsocketClientEndpoint(URI endpointURI) {
        try {
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            container.connectToServer(this, endpointURI);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @OnOpen
    public void onOpen(Session userSession) {
        System.out.println("opening websocket");
        this.userSession = userSession;
    }

    @OnClose
    public void onClose(Session userSession, CloseReason reason) {
        System.out.println("closing websocket");
        this.userSession = null;
    }

    @OnMessage
    public void onMessage(String message) throws IOException {
        if (this.messageHandler != null) {
            this.messageHandler.handleMessage(message);
        }
    }

    @OnMessage
    public void onMessage(ByteBuffer bytes) {
        System.out.println("Handle byte buffer");
    }
    
    public void addMessageHandler(MessageHandler msgHandler) {
        this.messageHandler = msgHandler;
    }

    public void sendMessage(String message) {
        this.userSession.getAsyncRemote().sendText(message);
    }

    public static interface MessageHandler {
        public void handleMessage(String message) throws IOException;
    }
}

客户端Main.java代码

package com.wsclient;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        try {
            // 连接WebSocket服务器
            final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI("wss://somedomain.com/ws"));

            clientEndPoint.addMessageHandler(
                new WebsocketClientEndpoint.MessageHandler() {
                    public void handleMessage(String packet) {
                        System.out.println(packet);
                    }
                }
            );

            clientEndPoint.sendMessage(payload);
            
            // 保持客户端运行
            while (true) {
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>rtw</groupId>
    <artifactId>rtw</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Jackson相关 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.18.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.18.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.18.2</version>
        </dependency>

        <!-- Jakarta WebSocket API -->
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-api</artifactId>
            <version>2.2.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.11.0</version>
        </dependency>

        <!-- Jakarta WebSocket Client API -->
        <dependency>
            <groupId>jakarta.websocket</groupId>
            <artifactId>jakarta.websocket-client-api</artifactId>
            <version>2.2.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- Tyrus Standalone Client -->
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client</artifactId>
            <version>2.2.0</version>
        </dependency>

        <!-- JSON -->
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20241224</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>9.1.0</version>
        </dependency>
    </dependencies>
</project>

解决方案

Jakarta WebSocket仅提供标准API,需要依赖具体实现(如Tyrus,GlassFish官方的WebSocket参考实现)来启动独立服务器。

步骤1:修改服务器pom.xml,添加Tyrus服务器依赖

移除原有的tyrus-standalone-client,替换为Tyrus服务器相关依赖:

<!-- Tyrus Server核心依赖 -->
<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-server</artifactId>
    <version>2.2.0</version>
</dependency>
<!-- Grizzly容器,用于启动服务器监听端口 -->
<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-container-grizzly</artifactId>
    <version>2.2.0</version>
</dependency>

步骤2:重写Main.java,启动Tyrus服务器

删除原错误代码,替换为以下内容,直接启动服务器并注册端点:

package com.wsserver;

import org.glassfish.tyrus.server.Server;

public class Main {
    public static void main(String[] args) {
        // 定义服务器监听地址和端口
        String host = "localhost";
        int port = 8080;
        
        // 创建Tyrus服务器,指定端点类
        Server server = new Server(host, port, "/", null, WebSocketEndpoint.class);
        
        try {
            // 启动服务器
            server.start();
            System.out.println("WebSocket服务器已启动,连接地址:ws://" + host + ":" + port + "/ws");
            
            // 阻塞主线程,保持服务器运行,按回车停止
            System.out.println("按回车键停止服务器...");
            System.in.read();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 停止服务器
            server.stop();
        }
    }
}

步骤3:修正类名拼写问题

原Main.java中误写的WebsocketEndpoint(小写s)已修正为实际类名WebSocketEndpoint(大写S)。

测试验证

  1. 运行服务器Main.java,控制台会输出服务器启动信息。
  2. 修改客户端Main.java的连接地址为ws://localhost:8080/ws,启动客户端。
  3. 客户端发送消息后,服务器会返回Echo: [消息内容],双方控制台均能看到对应日志。

关键说明

  • 独立WebSocket服务器必须依赖具体实现,Jakarta API本身不包含服务器运行时。
  • Tyrus的Server类负责启动监听端口,并自动扫描注册带有@ServerEndpoint注解的端点类。
  • 服务器启动后需保持主线程不退出,这里用System.in.read()阻塞主线程,避免程序直接终止。

内容的提问来源于stack exchange,提问作者thegillionaire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 22:39:49