The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Using WebSockets with Undertow

This guide explains how your Quarkus application can utilize web sockets to create interactive web applications, in the context of an Undertow-based Quarkus application, or if you rely on Jakarta WebSocket.

If you don’t use Undertow or Jakarta WebSocket, it is recommended to use the more modern WebSockets Next extensions.

Because it’s the canonical web socket application, we are going to create a simple chat application.

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アーキテクチャ

このガイドでは、WebSocketを使用して、接続されている他のユーザーとメッセージを送受信するための簡単なチャットアプリケーションを作成します。

Architecture

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは websockets-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。

コマンドラインインタフェース
Maven
quarkus create app org.acme:websockets-quickstart \ --extension='websockets' \ --no-code cd websockets-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

mvn io.quarkus.platform:quarkus-maven-plugin:3.22.2:create \ -DprojectGroupId=org.acme \ -DprojectArtifactId=websockets-quickstart \ -Dextensions='websockets' \ -DnoCode cd websockets-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=websockets-quickstart"

このコマンドは、Mavenプロジェクト(クラスなし)を生成し、 websockets エクステンションをインポートします。

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに undertow-websockets エクステンションを追加することができます。

コマンドラインインタフェース
Maven
Gradle
quarkus extension add websockets
./mvnw quarkus:add-extension -Dextensions='websockets'
./gradlew addExtension --extensions='websockets'

これにより、ビルドファイルに以下が追加されます:

pom.xml
build.gradle
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-websockets</artifactId> </dependency>
implementation("io.quarkus:quarkus-websockets")
WebSocketクライアントのみを使用したい場合は、代わりに quarkus-websockets-client を含める必要があります。

WebSocketの取り扱い

このアプリケーションには、websocketを処理するクラスが一つ含まれます。 src/main/java ディレクトリーに org.acme.websockets.ChatSocket クラスを作成します。作成したファイルに以下の内容をコピーします。

package org.acme.websockets; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import jakarta.enterprise.context.ApplicationScoped; import jakarta.websocket.OnClose; import jakarta.websocket.OnError; import jakarta.websocket.OnMessage; import jakarta.websocket.OnOpen; import jakarta.websocket.server.PathParam; import jakarta.websocket.server.ServerEndpoint; import jakarta.websocket.Session; @ServerEndpoint("/chat/{username}") (1) @ApplicationScoped public class ChatSocket { Map<String, Session> sessions = new ConcurrentHashMap<>(); (2) @OnOpen public void onOpen(Session session, @PathParam("username") String username) { broadcast("User " + username + " joined"); sessions.put(username, session); } @OnClose public void onClose(Session session, @PathParam("username") String username) { sessions.remove(username); broadcast("User " + username + " left"); } @OnError public void onError(Session session, @PathParam("username") String username, Throwable throwable) { sessions.remove(username); broadcast("User " + username + " left on error: " + throwable); } @OnMessage public void onMessage(String message, @PathParam("username") String username) { broadcast(">> " + username + ": " + message); } private void broadcast(String message) { sessions.values().forEach(s -> { s.getAsyncRemote().sendObject(message, result -> { if (result.getException() != null) { System.out.println("Unable to send message: " + result.getException()); } }); }); } }
1 WebSocketのURLを設定します
2 現在開いているWebSocketを格納します

洗練されたWebフロントエンド

すべてのチャットアプリケーションには 素敵な UIが必要です。 Quarkusは、 META-INF/resources ディレクトリに含まれる静的リソースを自動的に提供します。 src/main/resources/META-INF/resources ディレクトリを作成し、この index.html ファイルをコピーしてください。

アプリケーションの実行

では、実際にアプリケーションを見てみましょう。以下のように実行してみてください:

コマンドラインインタフェース
Maven
Gradle
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev

そして、ブラウザウィンドウを2つ開いて、 http://localhost:8080/ に移動します:

  1. 上部のテキストエリアに名前を入力します(2種類の名前を使用します)。

  2. connectをクリック

  3. メッセージの送受信

Application

いつものように、アプリケーションは以下の方法でパッケージ化されます。

コマンドラインインタフェース
Maven
Gradle
quarkus build
./mvnw install
./gradlew build

そして、 java -jar target/quarkus-app/quarkus-run.jar を使って実行します。

ネイティブ実行可能ファイルを次のようにビルドすることもできます。

コマンドラインインタフェース
Maven
Gradle
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true

また、ここ で説明されたアプローチを使用したWebソケットアプリケーションをテストすることもできます。

WebSocketクライアント

Quarkusには、WebSocketクライアントも含まれています。 ContainerProvider.getWebSocketContainer().connectToServer を呼び出して、WebSocket 接続を作成できます。デフォルトでは、 quarkus-websockets アーティファクトにはクライアントとサーバーの両方が含まれていますが、クライアントのみを必要とする場合は、代わりに quarkus-websockets-client を含めることができます。

サーバーに接続する際、使用するアノテーション付きクライアントエンドポイントのクラス、または jakarta.websocket.Endpoint のインスタンスを渡すことができます。アノテーション付きエンドポイントを使用する場合、 @ServerEndpoint の代わりに @ClientEndpoint でアノテーションする必要がありますが、サーバー上で使用できるものと全く同じアノテーションを使用することができます。

以下の例は、上記のチャットエンドポイントをテストするために使用されるクライアントを示しています。

package org.acme.websockets; import java.net.URI; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import jakarta.websocket.ClientEndpoint; import jakarta.websocket.ContainerProvider; import jakarta.websocket.OnMessage; import jakarta.websocket.OnOpen; import jakarta.websocket.Session; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; @QuarkusTest public class ChatTest { private static final LinkedBlockingDeque<String> MESSAGES = new LinkedBlockingDeque<>(); @TestHTTPResource("/chat/stu") URI uri; @Test public void testWebsocketChat() throws Exception { try (Session session = ContainerProvider.getWebSocketContainer().connectToServer(Client.class, uri)) { Assertions.assertEquals("CONNECT", MESSAGES.poll(10, TimeUnit.SECONDS)); Assertions.assertEquals("User stu joined", MESSAGES.poll(10, TimeUnit.SECONDS)); session.getAsyncRemote().sendText("hello world"); Assertions.assertEquals(">> stu: hello world", MESSAGES.poll(10, TimeUnit.SECONDS)); } } @ClientEndpoint public static class Client { @OnOpen public void open(Session session) { MESSAGES.add("CONNECT"); // Send a message to indicate that we are ready, // as the message handler may not be registered immediately after this callback. session.getAsyncRemote().sendText("_ready_"); } @OnMessage void message(String msg) { MESSAGES.add(msg); } } }

その他のWebSocket情報

Quarkus WebSocketの実装は、 Jakarta Websocket の実装の一つです。

関連コンテンツ