https://a.storyblok.com/f/270183/1368x665/fba399d139/java-websockets_24.png

Java API for WebSocketsでWebSocketサーバーを作成する方法

最終更新日 July 5, 2021

所要時間:3 分

この記事は2025年8月に更新されました。

ウェブソケットは、サーバーとクライアント(ブラウザーやモバイルアプリなど)がリアルタイムで会話できるプロトコルだ。RESTfulなHTTPとは異なり、クライアントは更新をチェックし続けなければならない(ポーリングと呼ばれるプロセス)。 ポーリングとは異なり、WebSocketは常に双方向の接続をオープンにしておく。つまり、サーバーは何かが変更されるたびにクライアントに更新を送信できるため、クライアントからの問い合わせを待つ必要はありません。

このチュートリアルでは、Jakarta WebSocket API(JSR 356)を使用してJavaでWebSocketサーバーを実装する方法を説明します。

前提条件

WebSocketsのJava API

Java EE 7で導入された Java API for WebSocketsまたはJSR 356は、Java開発者がアプリケーションにWebSocketを統合するために使用できる仕様である。

これによって開発者は、コンテナの実装から完全に独立してWebSocketベースのアプリケーションを書くことができる。このガイドでは Tomcat.ただし、JSR 356を使用するため、Jakarta EE 9以降をサポートする他のWebコンテナでも動作するはずです。

プロジェクトの作成

Gradleを使って新しいJavaアプリケーションを初期化します。以下のコマンドを使用してプロジェクト用のディレクトリを作成し、そのディレクトリに移動してアプリケーションを初期化します:

mkdir websocket-java-api cd websocket-java-api

新しいGradleプロジェクトを作成する:

  1. 実行 gradle init --type=java-applicationコマンド

  2. 選択 Groovyスクリプト言語として

  3. 選択する JUnit Jupiterテストフレームワークとして

  4. デフォルトのまま Project name

  5. デフォルトのまま Source package

Java WebSocket APIの依存関係を追加する

以下の依存関係を dependenciesブロックに追加する。 app/build.gradleファイルに追加する:

implementation 'jakarta.websocket:jakarta.websocket-api:2.1.1'

Jakarta EE 9+では jakarta.websocketの代わりに javax.websocketの代わりに名前空間を使用し、Tomcat 10+もこの慣例に従っている。

WebSocketエンドポイントの作成

WebSocketメッセージはテキストとバイナリーの両方があります。この両方のメッセージを扱えるエンドポイントを作成することになります。

この @ServerEndpointアノテーションを使用してクラスを装飾し、WebSocket エンドポイントとして宣言します。アノテーションは、エンドポイントへのアクセス先を定義する path 引数を取ります。

という新しいクラスを WebSocketEndpointという新しいクラスを src/main/java/websocket/java/apiフォルダ内に新しいクラスを作成し、以下のコードを追加する:

import jakarta.websocket.server.ServerEndpoint;
import jakarta.websocket.OnMessage;

@ServerEndpoint("/socket")
public class WebSocketEndpoint {
    @OnMessage
    public String handleTextMessage(String message) {
        System.out.println("New Text Message Received");
        return message;
    }

    @OnMessage(maxMessageSize = 1024000)
    public byte[] handleBinaryMessage(byte[] buffer) {
        System.out.println("New Binary Message Received");
        return buffer;
    }
}

アノテーションは @OnMessageアノテーションは、受信するテキストまたはバイナリの WebSocket メッセージに Java メソッドをリンクします。メソッド・シグニチャは、どのタイプのメッセージを処理するかを決定します。例えば Stringはテキストに使用され byte[]はバイナリです。

この例では、受け取ったメッセージと同じものを返すエコー・サーバを作成しています。バイナリハンドラの maxMessageSizeパラメータにより、画像ファイルなどの大きなペイロードを受け付けることができます。チュートリアルの後半で、ブラウザベースのクライアントを使用してこれをテストします。

アプリケーションをテストするクライアントを作成する

WebSocketサーバーをテストするためにクライアントを作成する必要があります。テキスト・メッセージとバイナリ・メッセージの両方を送信するテストが必要です。これはHTMLとJavaScriptで書かれた簡単なアプリケーションで実現できます。

フォルダを webappフォルダーの中に src/mainフォルダーの中に

以下を index.htmlフォルダ内に src/main/webappフォルダーの中に追加する:

<html>
<head>
    <style>
        #messages {
            text-align: left;
            width: 50%;
            padding: 1em;
            border: 1px solid black;
        }
    </style>
    <title>Sample WebSocket Client</title>
</head>
<body>
<div class="container">
    <div id="messages" class="messages"></div>
    <div class="input-fields">
        <p>Type a message and hit send:</p>
        <input id="message"/>
        <button id="send">Send</button>

        <p>Select an image and hit send:</p>
        <input type="file" id="file" accept="image/*"/>

        <button id="sendImage">Send Image</button>
    </div>
</div>
</body>
<script>
    const messageWindow = document.getElementById("messages");

    const sendButton = document.getElementById("send");
    const messageInput = document.getElementById("message");

    const fileInput = document.getElementById("file");
    const sendImageButton = document.getElementById("sendImage");

    const socket = new WebSocket("ws://localhost:8080/socket");
    socket.binaryType = "arraybuffer";

    socket.onopen = function (event) {
        addMessageToWindow("Connected");
    };

    socket.onmessage = function (event) {
        if (event.data instanceof ArrayBuffer) {
            addMessageToWindow('Got Image:');
            addImageToWindow(event.data);
        } else {
            addMessageToWindow(`Got Message: ${event.data}`);
        }
    };

    sendButton.onclick = function (event) {
        sendMessage(messageInput.value);
        messageInput.value = "";
    };

    sendImageButton.onclick = function (event) {
        let file = fileInput.files[0];
        sendMessage(file);
        fileInput.value = null;
    };

    function sendMessage(message) {
        socket.send(message);
        addMessageToWindow("Sent Message: " + message);
    }

    function addMessageToWindow(message) {
        messageWindow.innerHTML += `<div>${message}</div>`
    }

    function addImageToWindow(image) {
        let url = URL.createObjectURL(new Blob([image]));
        messageWindow.innerHTML += `<img src="${url}"/>`
    }
</script>
</html>

Tomcatの組み込みと設定

とは異なる Spring BootでWebSocketサーバーを作成するSpark FrameworkによるWebSocketサーバーの作成とは異なり、アプリケーションを実行するための組み込みサーバーは初期状態では存在しない。

Grettyプラグインを使うと、様々なコンテナを埋め込むことができる。

まず、Grettyプラグインを build.gradleファイルに適用します。 pluginsブロックに追加します:

plugins {
    id 'org.gretty' version '4.1.7'
}

次に、サーブレット・コンテナとしてTomcatを使用するようにGrettyを設定し、コンテキスト・パスを簡単にするために /に設定する必要があります。

次のブロックを build.gradle:

gretty {
    servletContainer = 'tomcat10'
    contextPath = '/'
}

Gretty 3.0.5+ サポート tomcat10Jakarta EE 9+ (jakarta.*名前空間)に対応しました。

デフォルトでは、GrettyはサーブレットコンテナとしてJettyを使うことに注意してほしい。この同じガイドはJettyでも実行されるが、これはSpring BootとSparkフレームワークの両方が埋め込むコンテナと同じであり、異なるものを示したかった。

アプリケーションの開始

これでWebSocketサーバーは完成です。アプリケーションのディレクトリ内で gradle appRunコマンドを使ってアプリケーションを起動します。

アプリケーションを実行する前に JAVA_HOMEがJDK 21に設定されていることを確認してください:

echo $JAVA_HOME

ターミナルウィンドウを開いたままにする。

アプリケーションにアクセスするには http://localhost:8080URL をブラウザで開きます。

次のページが表示されます:

Sample JavaScript-enabled client for testing the WebSocket serverSample JavaScript-enabled client for testing the WebSocket serverconnected "メッセージは、JavaScriptクライアントが接続できたことを示す。

入力フィールドに入力して送信ボタンをクリックし、テキストメッセージを送信してみてください。また、画像をアップロードしてみてください。どちらの場合も、同じメッセージと画像がエコーバックされるはずです。

Sample JavaScript-enabled client showing a text and binary message echoed back.Sample JavaScript-enabled client showing a text and binary message echoed back.

結論

Java API for WebSockets (JSR 356)を使用してWebSocketサーバーを作成し、Grettyを使用してTomcatコンテナに組み込み、簡単なHTMLとJavaScriptクライアントでテストすることに成功しました。

この設定により、サーバーとクライアントの間でテキストとバイナリの双方向通信をリアルタイムで行うことができます。

次のステップとしては、認証の追加、より多くのメッセージタイプの処理、既存のJavaアプリケーションとの統合などが考えられる。

ご質問がある場合、またはあなたが作っているものを共有したい場合は、こちらをクリックしてください。

最新の開発者向けニュース、ヒント、イベント情報をお届けします。

シェア:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Steve Crowヴォネージの卒業生

スティーブは自称数学者で、悪口の王様。グレイハウンド、曲がりくねったパズル、ヨーロッパのボードゲームをこよなく愛する。 非数学系の人には数学を、非Java系の人にはJavaの話をしていないときは、コーヒーを飲みながらコードをハックしている。