在运行时从后端连接到 Web-Socket-Server java class

Connect to Web-Socket-Server at runtime from back-end java class

我已经使用 spring 实现了以下 Web-Socket-Server。我们不想使用 STOMP 和 JSocks。

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    registry.addHandler(new WebSocketServerHandler(), "/websocket/user/{userId}");
  }

}




@Service
public class WebSocketServerHandler extends TextWebSocketHandler {

   private List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();

   @Override
   public void handleTextMessage(WebSocketSession session, TextMessage message)
        throws Exception {

        session.sendMessage(message);           
   }

   @Override
   public void afterConnectionEstablished(WebSocketSession session) throws Exception {
     sessions.add(session);
   }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
      sessions = null;
    }

}

现在我可以从前端客户端(浏览器)成功连接到 Web-Socket-Server。现在我想在 运行 时间从我的一些 java class 连接到该 Web-Socket-Server,然后想将消息发送到该 Web-Socket-Server。有人知道我该怎么做吗?

我添加了一个测试 Rest Controller,如下所示:

 @RequestMapping(value = "/web-socket/message/{message}")
 public void sendMessage(@PathVariable("message") final String message) throws Exception {
   final String WS_URI = "ws://localhost:8080/web-socket/user/23";

   final CountDownLatch latch = new CountDownLatch(1);
   WebSocketClientHandler handler = new WebSocketClientHandler(latch);
   WebSocketClient client = new StandardWebSocketClient();
   WebSocketSession session = client.doHandshake(handler, WS_URI).get();
   session.sendMessage(new TextMessage(message));
   latch.await(5, TimeUnit.SECONDS);
   session.close();

}

我成功地能够将消息发送到 websocket 服务器,这只是第一次通过使用 google 休息客户端调用此测试 RestController。如果我需要再次发送消息,那么我必须重新启动 tomcat 服务器。我在这里做什么有什么问题吗?

spring-websocket 支持 WebSocket 客户端。基本合同是WebSocketClient. Spring doesn't implement the entire WebSocket support, but offers an abstraction layer over other implementations. The common Spring client abstraction is the StandardWebSocketClient。一个简单的例子看起来像

public static void main(String... args) throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    EchoHandler handler = new EchoHandler(latch);
    WebSocketClient client = new StandardWebSocketClient();
    WebSocketSession session = client.doHandshake(handler, ECHO_URL).get();
    session.sendMessage(new TextMessage("Hello World"));
    latch.await(5000, TimeUnit.SECONDS);
    session.close();
}

其中 EchoHandler 是客户端 WebSocketHandler(与服务器端相同)。

public class EchoHandler extends TextWebSocketHandler {

    private final CountDownLatch latch;

    public EchoHandler(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        System.out.println("------- received client message ------");
        System.out.println(message.getPayload());
        System.out.println("--------- end client message ---------");
        latch.countDown();
    }
}

如果您是字符串环境中的 运行 客户端,您也可以将 WebSocketClient 包装在 WebSocketConnectionManager 中。如果需要,这将为您提供一些生命周期助手。请参阅 Spring Boot sample.

中的示例

至于依赖项,就像我说的,Spring 没有实现整个 WebSocket 客户端支持,所以您需要一个实现。如果您是 运行 支持 WebSocket 的服务器中的客户端,则无需添加任何内容。支持实现应该已经在服务器的类路径中。主要支持的 WebSocket 实现是 Jetty、Tomcat、Undertow(主要是 Wildfly 或独立的 Undertow)、Tyrus(即 Glassfish、WebLogic)。

如果您是 运行 独立应用程序中的客户端,则需要添加 WebSocket 实现。不幸的是,根据我的测试,none 实现提供了一个完整的可用 "client-only" jar。他们需要或已经引入完整的(包括服务器)实现。所以只使用客户端,仍然需要拉入一堆服务器 jar。这是我从测试中得出的结论

人人通用

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>${websocket.version}</version>
</dependency>

Tomcat

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-websocket</artifactId>
    <version>${tomcat.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>${tomcat.version}</version>
</dependency>

暗流

<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-websockets-jsr</artifactId>
    <version>${undertow.version}</version>
</dependency>

泰鲁斯

<!-- tyrus-client is pulled in by this. -->
<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-server</artifactId>
    <version>${tyrus.version}</version>
</dependency>

码头

<dependency>
    <groupId>org.eclipse.jetty.websocket</groupId>
    <artifactId>websocket-client</artifactId>
    <version>${jetty.version}</version>
</dependency>

对于 Jetty,它不使用标准的 Java WebSocket API,因此它不会在 StandardWebSocketClient 中使用。您将需要改为

JettyWebSocketClient client = new JettyWebSocketClient();
client.start();

上面的其他都是一样的。

我只是查看了 Spring 源代码以查看它们使用的所有不同的依赖项。您可以检查它并尝试使用依赖项。也许有不同的更有效(更轻)的依赖组合仍然有效。以上只是我测试过的并且能够开始工作。