WebアプリケーションでのWebSocket APIの使用

このチュートリアルでは、1つのサーバー・アプリケーションに接続されているクライアント・ブラウザの間のコラボレーションを可能にする単純なWebアプリケーションを作成する方法を示します。ユーザーがクライアント・ブラウザでキャンバスにグラフィック要素を描画すると、接続されているすべてのクライアントのキャンバスにその要素が表示されます。使用方法ブラウザがWebページをロードすると、クライアント側のスクリプトはWebSocketハンドシェイク・リクエストをアプリケーション・サーバーに送信します。アプリケーションは、セッションで接続されているクライアントからJSONおよびバイナリ・メッセージを受け付けて、接続されているすべてのクライアントにメッセージをブロードキャストできます。

このチュートリアルでは、ブラウザ・クライアントとアプリケーション・サーバーとの間の双方向の通信を可能にするJava API for WebSocket (JSR 356)を使用してWebアプリケーションを作成します。Java API for WebSocketでは、WebSocket Javaコンポーネントの作成、WebSocketイベントの開始とインターセプト、WebSocketのテキストおよびバイナリのメッセージの作成と消費のサポートが提供されます。チュートリアルでは、Java API for JSON Processing (JSR 353)を使用してJSONを生成および消費する方法も示します。Java API for WebSocketおよびJava API for JSON ProcessingはJava EE 7プラットフォーム(JSR 342)の一部です。

アプリケーションには、WebSocketエンドポイント、デコーダおよびエンコーダのインタフェース、Webページ、およびページのロード時またはWebページのフォームからの起動時にクライアント・ブラウザで実行されるJavaScriptファイルが含まれます。Java EE 7テクノロジのリファレンス実装であるGlassFish Server Open Source Edition 4にアプリケーションをデプロイします。

注意:このチュートリアルは、Arun Gupta氏のブログで見ることができるブログ投稿 Collaborative Whiteboard using WebSocket in GlassFish 4 - Text/JSON and Binary/ArrayBuffer Data Transfer (TOTD #189)およびその他のブログ・エントリに基づいています。このブログにアクセスして、WebSocket APIやGlassFish 4の使用に関するその他の多くの有用なエントリをぜひ参照してください。

「WebアプリケーションでのWebSocket APIの使用のビデオ」も参照できます。

チュートリアルの課題

このページの内容は、NetBeans IDE 7.3、7.4および8.0に適用されます

このチュートリアルに従うには、次のソフトウェアとリソースが必要です。

ソフトウェアまたはリソース 必須バージョン
NetBeans IDE 7.3.1、7.4、8.0、Java EEバージョン
Java Development Kit (JDK) バージョン7または8
GlassFish Server Open Source Edition 4

注意:GlassFish 4は、NetBeans IDEのJava EEダウンロード・バンドルにバンドルされています。

前提条件

このドキュメントは、次のテクノロジについて基本的な知識またはプログラミング経験を持つ読者を想定して書かれています。

  • Javaプログラミング
  • JavaScript/HTMLプログラミング
  • NetBeans IDE

このチュートリアルを開始する前に、必要に応じて次のドキュメントをお読みください。

終了したプロジェクトのZIPアーカイブはダウンロードできます。

Webアプリケーション・プロジェクトの作成

この課題の目標は、IDEで新規プロジェクト・ウィザードを使用してWebアプリケーション・プロジェクトを作成することです。プロジェクトを作成する際、Java EEバージョンとして「Java EE 7」を、アプリケーション・サーバーとしてGlassFish 4を選択します。GlassFish 4はJava EE 7プラットフォームのリファレンス実装です。このチュートリアルでアプリケーションを作成するには、IDEに登録されたJava EE 7をサポートするアプリケーション・サーバーが必要です。

  1. メイン・メニューから「ファイル」>「新規プロジェクト」(Windowsの場合は[Ctrl]-[Shift]-[N]、Macの場合は[⌘]-[Shift]-[N])を選択します。
  2. 「Maven」カテゴリから「Webアプリケーション」を選択します。「次」をクリックします。
  3. 「プロジェクト名」に「WhiteboardApp」と入力し、プロジェクトの場所を設定します。
  4. 「グループID」に「org.sample」と入力します。「次」をクリックします。
  5. 「サーバー」に「GlassFish Server 4.0」を選択します。
  6. 「Java EEバージョン」を「Java EE 7 Web」に設定します。「終了」をクリックします。
    新規プロジェクト・ウィザードのプロジェクトの詳細

「終了」をクリックすると、IDEがプロジェクトを作成し、そのプロジェクトが「プロジェクト」ウィンドウで開きます。

WebSocketエンドポイントの作成

この項では、WebSocketエンドポイント・クラスおよびJavaScriptファイルを作成します。WebSocketエンドポイント・クラスには、セッションのオープン時に実行される基本的なメソッドを含めます。次に、ページのロード時にサーバーとのハンドシェイクを開始するJavaScriptファイルを作成します。次に、接続が正常であることをテストするアプリケーションを実行します。

WebSocket APIおよび注釈の使用の詳細は、 javax.websocketパッケージのサマリーを参照してください。

エンドポイントの作成

この課題では、IDEのウィザードを利用してWebSocketエンドポイント・クラスを作成します。

  1. 「プロジェクト」ウィンドウで「ソース・パッケージ」ノードを右クリックし、「新規」>「その他」を選択します。
  2. 「Web」カテゴリで「WebSocketエンドポイント」を選択します。「次」をクリックします。
  3. 「クラス名」に「MyWhiteboard」と入力します。
  4. 「パッケージ」ドロップダウン・リストで「org.sample.whiteboardapp」を選択します。
  5. 「WebSocket URI」に「/whiteboardendpoint」と入力します。「終了」をクリックします。
    新規ファイル・ウィザードのWebSocketエンドポイント

    「終了」をクリックすると、IDEによってWebSocketエンドポイント・クラスが生成され、ソース・エディタでファイルが開きます。エディタで、IDEによってWebSocket APIの一部である注釈が生成されたことを確認できます。クラスには、クラスがエンドポイントであることを識別する@ServerEndpointという注釈が付けられ、注釈のパラメータとしてWebSocket URIが指定されています。IDEによって@OnMessageという注釈が付けられたデフォルトのonMessageメソッドも生成されました。@OnMessageという注釈が付けられたメソッドは、クライアントがWebSocketメッセージを受信するたびに起動されます。

    @ServerEndpoint("/whiteboardendpoint")
    public class MyWhiteboard {
    
        @OnMessage
        public String onMessage(String message) {
            return null;
        }
        
    }
  6. 次のフィールド(太字部分)をクラスに追加します。
    @ServerEndpoint("/whiteboardendpoint")
    public class MyWhiteboard {
        private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
    
        @OnMessage
        public String onMessage(String message) {
            return null;
        }
    }
  7. 次のonOpenおよびonCloseメソッドを追加します。
        @OnOpen
        public void onOpen (Session peer) {
            peers.add(peer);
        }
    
        @OnClose
        public void onClose (Session peer) {
            peers.remove(peer);
        }

    onOpenおよびonCloseメソッドには、@OnOpenおよび@OnCloseのWebSocket API注釈が付けられています。@OnOpenという注釈が付けられたメソッドは、Webソケット・セッションが開かれたときにコールされます。この例では、注釈の付いたonOpenメソッドでブラウザ・クライアントを現在のセッションのピアのグループに追加し、onCloseメソッドでブラウザをグループから削除します。

    メソッドの生成には、ソース・エディタのヒントとコード補完を使用すると便利です。クラスの宣言の横の左マージンのヒント・グリフをクリックし(または、カーソルをクラスの宣言内に置いて[Alt]-[Enter])、ポップアップ・メニューでメソッドを選択します。コード補完をメソッドのコーディングに使用すると便利です。

    ソース・エディタのコード・ヒントのスクリーンショット
  8. エディタで右クリックし、「インポートを修正」を選択します([Alt]-[Shift]-[I]、Macの場合は[⌘]-[Shift]-[I])。変更を保存します。

    javax.websocketのクラスのインポート文がファイルに追加されます。

これでエンドポイントが作成されました。次にWebSocketセッションを開始するためのJavaScriptファイルを作成する必要があります。

WebSocketセッションの開始

この課題では、WebSocketセッションを開始するJavaScriptファイルを作成します。ブラウザ・クライアントは、サーバーとのHTTPハンドシェイクを使用し、TCPを介してセッションに参加します。JavaScriptファイルで、エンドポイントのwsURIの名前を指定し、WebSocketを宣言します。wsURI URIスキームはWebSocketプロトコルの一部で、アプリケーションのエンドポイントのパスを指定します。

  1. 「プロジェクト」ウィンドウでプロジェクト・ノードを右クリックし、「新規」>「その他」を選択します。
  2. 新規ファイル・ウィザードの「Web」カテゴリで「JavaScriptファイル」を選択します。「次」をクリックします。
  3. 「JavaScriptファイル名」に「websocket」と入力します。「終了」をクリックします。
  4. 次のコードをJavaScriptファイルに追加します。
    var wsUri = "ws://" + document.location.host + document.location.pathname + "whiteboardendpoint";
    var websocket = new WebSocket(wsUri);
    
    websocket.onerror = function(evt) { onError(evt) };
    
    function onError(evt) {
        writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
    }

    このスクリプトは、ブラウザによってwebsocket.jsがロードされる際、サーバーとセッション・ハンドシェイクを開始します。

  5. index.htmlを開き、ページのロードの終了時にwebsocket.jsをロードする次のコード(太字部分)をファイルの最後に追加します。
    <body>
        <h1>Collaborative Whiteboard App</h1>
            
        <script type="text/javascript" src="websocket.js"></script>
    </body>

これで、WebSocketエンドポイントが機能していること、セッションが開始されたこと、およびクライアントがセッションに追加されたことをテストできます。

エンドポイントのテスト

この課題では、ブラウザがエンドポイントに接続されたら、ブラウザ・ウィンドウにwsURIを出力するよう、簡単なメソッドをいくつかJavaScriptに追加します。

  1. 次の<div>タグ(太字部分)をindex.htmlに追加します。
    <h1>Collaborative Whiteboard App</h1>
            
    <div id="output"></div>
    <script type="text/javascript" src="websocket.js"></script>
  2. 次の宣言とメソッドをwebsocket.jsに追加します。変更を保存します。
    // For testing purposes
    var output = document.getElementById("output");
    websocket.onopen = function(evt) { onOpen(evt) };
    
    function writeToScreen(message) {
        output.innerHTML += message + "<br>";
    }
    
    function onOpen() {
        writeToScreen("Connected to " + wsUri);
    }
    // End test functions

    ページがロードされると、JavaScript関数は、ブラウザがエンドポイントに接続されていることを示すメッセージを出力します。エンドポイントが正しく実行されていることを確認したら、関数を削除できます。

  3. 「プロジェクト」ウィンドウでプロジェクトを右クリックし、「実行」を選択します。

アプリケーションを実行すると、IDEでGlassFishサーバーが起動され、アプリケーションがビルドおよびデプロイされます。ブラウザでindexページが開かれ、ブラウザ・ウィンドウに次のメッセージが表示されます。

ブラウザ・ウィンドウ内のエンドポイントへの接続メッセージ

ブラウザ・ウィンドウに、メッセージが受け付けられたエンドポイント(http://localhost:8080/WhiteboardApp/whiteboardendpoint)が表示されます。

ホワイトボードの作成

この項では、JSONテキスト・メッセージを送受信するクラスおよびJavaScriptファイルを作成します。コンテンツ、およびペイントブラシの形状と色を指定するラジオ・ボタンを含むHTML<form>を描画および表示するためのHTML5 Canvas要素も追加します。

Webページへのキャンバスの追加

この課題では、canvas要素およびform要素をデフォルトのindexページに追加します。フォームのチェックボックスによって、キャンバスのペイントブラシのプロパティが決まります。

  1. ソース・エディタでindex.htmlを開きます。
  2. エンドポイントのテスト用に追加した<div>タグを削除し、開始のbodyタグの後に次の<table>および<form>要素(太字部分)を追加します。
    <h1>Collaborative Whiteboard App</h1>
            
        <table>
            <tr>
                <td>
                </td>
                <td>
                    <form name="inputForm">
                        
    
                    </form>
                </td>
            </tr>
        </table>
        <script type="text/javascript" src="websocket.js"></script>
        </body>
  3. canvas要素用に次のコード(太字部分)を追加します。
            <table>
                <tr>
                    <td>
                        <canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas>
                    </td>
  4. 次の<table>を追加して、色と形状を選択するラジオ・ボタンを追加します。変更を保存します。
            <table>
                <tr>
                    <td>
                        <canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas>
                    </td>
                    <td>
                        <form name="inputForm">
                            <table>
    
                                <tr>
                                    <th>Color</th>
                                    <td><input type="radio" name="color" value="#FF0000" checked="true">Red</td>
                                    <td><input type="radio" name="color" value="#0000FF">Blue</td>
                                    <td><input type="radio" name="color" value="#FF9900">Orange</td>
                                    <td><input type="radio" name="color" value="#33CC33">Green</td>
                                </tr>
    
                                <tr>
                                    <th>Shape</th>
                                    <td><input type="radio" name="shape" value="square" checked="true">Square</td>
                                    <td><input type="radio" name="shape" value="circle">Circle</td>
                                    <td> </td>
                                    <td> </td>
                                </tr>
    
                            </table>
                        </form>

    キャンバス上に描画された図形の形状、色、および座標は、JSONの構造の文字列に変換され、WebSocketエンドポイントにメッセージとして送信されます。

POJOの作成

この課題では、単純なPOJOを作成します。

  1. プロジェクト・ノードを右クリックし、「新規」>「Javaクラス」を選択します。
  2. 「クラス名」に「Figure」と入力し、「パッケージ」ドロップダウン・リストで「org.sample.whiteboardapp」を選択します。「終了」をクリックします。
  3. ソース・エディタで、次のコード(太字部分)を追加します。
    public class Figure {
        private JsonObject json;
    }

    コードを追加すると、javax.json.JsonObjectのインポート文を追加するよう求められます。求められない場合は、[Alt]-[Enter]を押します。

    javax.json.JsonObjectの詳細は、Java EE 7仕様の一部であるJava API for JSON Processing (JSR 353)を参照してください。

  4. jsonの取得および設定メソッドを作成します。

    「コードを挿入」ポップアップ・メニュー(Windowsの場合は[Alt]-[Insert]、Macの場合は[Ctrl]-[I])で取得および設定メソッドを選択すると、「取得メソッドおよび設定メソッドの生成」ダイアログ・ボックスが開きます。または、メイン・メニューから「ソース」>「コードを挿入」を選択します。

    「取得メソッドおよび設定メソッドの生成」ダイアログ・ボックス
  5. jsonのコンストラクタを追加します。
        public Figure(JsonObject json) {
            this.json = json;
        }

    「コードを挿入」ポップアップ・メニュー([Ctrl]-[I])で「コンストラクタ」を選択します。

    「コンストラクタの生成」ポップアップ・メニュー
  6. 次のtoStringメソッドを追加します。
        @Override
        public String toString() {
            StringWriter writer = new StringWriter();
            Json.createWriter(writer).write(json);
            return writer.toString();
        }
  7. エディタで右クリックし、「インポートを修正」を選択します([Alt]-[Shift]-[I]、Macの場合は[⌘]-[Shift]-[I])。変更を保存します。

座標クラスの作成

ここで、キャンバスに描画される図形の座標のクラスを作成します。

  1. プロジェクト・ノードを右クリックし、「新規」>「Javaクラス」を選択します。
  2. 新規Javaクラス・ウィザードで「クラス名」に「Coordinates」と入力し、「パッケージ」ドロップダウン・リストで「org.sample.whiteboardapp」を選択します。「終了」をクリックします。
  3. ソース・エディタで、次のコードを追加します。変更を保存します。
        private float x;
        private float y;
    
        public Coordinates() {
        }
    
        public Coordinates(float x, float y) {
            this.x = x;
            this.y = y;
        }
    
        public float getX() {
            return x;
        }
    
        public void setX(float x) {
            this.x = x;
        }
    
        public float getY() {
            return y;
        }
    
        public void setY(float y) {
            this.y = y;
        }
                    

クラスにはxy座標のフィールドおよび取得と設定のメソッドのみが含まれます。

JSON文字列の生成

この課題では、canvas要素に描画される図形の詳細を、websocketエンドポイントに送信されるJSON構造にするJavaScriptファイルを作成します。

  1. プロジェクト・ノードを右クリックし、「新規」>「JavaScriptファイル」を選択して新規JavaScriptファイル・ウィザードを開きます。
  2. 「ファイル名」に「whiteboard」と入力します。「終了」をクリックします。

    「終了」をクリックすると、IDEで空のJavaScriptファイルが作成され、エディタでこのファイルが開きます。「プロジェクト」ウィンドウの「Webページ」ノードの下に新規ファイルが表示されます。

  3. キャンバスを初期化し、イベント・リスナーを追加する次のコードを追加します。
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
    canvas.addEventListener("click", defineImage, false);

    ユーザーがcanvas要素内をクリックすると、defineImageメソッドが起動されることがわかります。

  4. 次のgetCurrentPosdefineImageおよびdrawImageTextメソッドを追加して、JSON構造を作成し、エンドポイントに送信します(sendText(json))。
    function getCurrentPos(evt) {
        var rect = canvas.getBoundingClientRect();
        return {
            x: evt.clientX - rect.left,
            y: evt.clientY - rect.top
        };
    }
                
    function defineImage(evt) {
        var currentPos = getCurrentPos(evt);
        
        for (i = 0; i < document.inputForm.color.length; i++) {
            if (document.inputForm.color[i].checked) {
                var color = document.inputForm.color[i];
                break;
            }
        }
                
        for (i = 0; i < document.inputForm.shape.length; i++) {
            if (document.inputForm.shape[i].checked) {
                var shape = document.inputForm.shape[i];
                break;
            }
        }
        
        var json = JSON.stringify({
            "shape": shape.value,
            "color": color.value,
            "coords": {
                "x": currentPos.x,
                "y": currentPos.y
            }
        });
        drawImageText(json);
            sendText(json);
    }
    
    function drawImageText(image) {
        console.log("drawImageText");
        var json = JSON.parse(image);
        context.fillStyle = json.color;
        switch (json.shape) {
        case "circle":
            context.beginPath();
            context.arc(json.coords.x, json.coords.y, 5, 0, 2 * Math.PI, false);
            context.fill();
            break;
        case "square":
        default:
            context.fillRect(json.coords.x, json.coords.y, 10, 10);
            break;
        }
    }

    送信されるJSONの構造は次のようになります。

    {
     "shape": "square",
     "color": "#FF0000",
     "coords": {
     "x": 31.59999942779541,
     "y": 49.91999053955078
     }
    } 

    websocket.send()を使用してJSON文字列を送信するsendText(json)メソッドを追加する必要があります。

  5. エディタでwebsocket.jsを開き、JSONをエンドポイントに送信するためのメソッドおよびエンドポイントからメッセージを受信したらイメージを描画するためのメソッドを追加します。
    websocket.onmessage = function(evt) { onMessage(evt) };
    
    function sendText(json) {
        console.log("sending text: " + json);
        websocket.send(json);
    }
                    
    function onMessage(evt) {
        console.log("received: " + evt.data);
        drawImageText(evt.data);
    }

    注意:エンドポイントのテスト用にwebsocket.jsに追加したコードは削除できます。

  6. whiteboard.jsをロードする次の行(太字部分)をindex.htmlの最後に追加します。
            </table>
        <script type="text/javascript" src="websocket.js"></script>
        <script type="text/javascript" src="whiteboard.js"></script>
    <body>
                    

エンコーダおよびデコーダ・インタフェースの実装

この課題では、デコーダおよびエンコーダ・インタフェースを実装するクラスを作成し、Webソケット・メッセージ(JSON)をPOJOクラスFigureにデコードし、エンドポイントに送信するためにFigureをJSON文字列としてエンコードします。

詳細は、技術記事JSR 356、Java API for WebSocketのメッセージ・タイプおよびエンコーダ、デコーダに関する項を参照してください。

  1. プロジェクト・ノードを右クリックし、「新規」>「Javaクラス」を選択します。
  2. 「クラス名」に「FigureEncoder」と入力し、「パッケージ」ドロップダウン・リストで「org.sample.whiteboardapp」を選択します。「終了」をクリックします。
  3. ソース・エディタで次のコード(太字部分)を追加し、WebSocket Encoderインタフェースを実装します。
                
    public class FigureEncoder implements Encoder.Text<Figure> {
        
    }
  4. javax.websocket.Encoderのインポート文を追加し、抽象メソッドを実装します。

    クラスの宣言にカーソルを置き、[Alt]-[Enter]を押して、ポップアップ・メニューから「すべての抽象メソッドを実装」を選択します。

  5. 次の変更(太字部分)を加えて、生成された抽象メソッドを変更します。変更を保存します。
        @Override
        public String encode(Figure figure) throws EncodeException {
            return figure.getJson().toString();
        }
    
        @Override
        public void init(EndpointConfig ec) {
            System.out.println("init");
        }
    
        @Override
        public void destroy() {
            System.out.println("destroy");
        }
  6. プロジェクト・ノードを右クリックし、「新規」>「Javaクラス」を選択します。
  7. 「クラス名」に「FigureDecoder」と入力し、「パッケージ」ドロップダウン・リストで「org.sample.whiteboardapp」を選択します。「終了」をクリックします。
  8. ソース・エディタで、次のコード(太字部分)を追加し、WebSocket Decoderインタフェースを実装します。
                
    public class FigureDecoder implements Decoder.Text<Figure> {
        
    }
  9. javax.websocket.Decoderのインポート文を追加し、抽象メソッドを実装します。
  10. 生成された抽象メソッドに次の変更(太字部分)を加えます。
        @Override
        public Figure decode(String string) throws DecodeException {
            JsonObject jsonObject = Json.createReader(new StringReader(string)).readObject();
            return  new Figure(jsonObject);
        }
    
        @Override
        public boolean willDecode(String string) {
            try {
                Json.createReader(new StringReader(string)).readObject();
                return true;
            } catch (JsonException ex) {
                ex.printStackTrace();
                return false;
            }
        
        }
    
        @Override
        public void init(EndpointConfig ec) {
            System.out.println("init");
        }
    
        @Override
        public void destroy() {
            System.out.println("destroy");
        }
  11. インポートを修正して変更内容を保存します。

次に、MyWhiteboard.javaを変更して、エンコーダとデコーダを指定する必要があります。

アプリケーションの実行

これでアプリケーションを実行する準備がほぼ整いました。この課題では、WebSocketエンドポイント・クラスを変更してJSON文字列のエンコーダとデコーダを指定し、メッセージを受信したら、接続されているクライアントにJSON文字列を送信するメソッドを追加します。

  1. エディタでMyWhiteboard.javaを開きます。
  2. @ServerEndpoint注釈を変更し、エンドポイントのエンコーダとデコーダを指定します。エンドポイントの名前のパラメータvalueを明示的に指定する必要があります。
    @ServerEndpoint(value="/whiteboardendpoint", encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class})
            
  3. デフォルトで生成されたonMessageメソッドを削除します。
  4. 次のbroadcastFigureメソッドを追加し、メソッドに@OnMessageの注釈を付けます。
        @OnMessage
        public void broadcastFigure(Figure figure, Session session) throws IOException, EncodeException {
            System.out.println("broadcastFigure: " + figure);
            for (Session peer : peers) {
                if (!peer.equals(session)) {
                    peer.getBasicRemote().sendObject(figure);
                }
            }
        }
  5. エディタで右クリックし、「インポートを修正」を選択します([Alt]-[Shift]-[I]、Macの場合は[⌘]-[Shift]-[I])。変更を保存します。
  6. 「プロジェクト」ウィンドウでプロジェクトを右クリックし、「実行」を選択します。

「実行」をクリックすると、IDEはブラウザ・ウィンドウでhttp://localhost:8080/WhiteboardApp/を開きます。

注意:以前のアプリケーションをアプリケーション・サーバーからアンデプロイするか、ブラウザでページを強制的に再ロードする必要がある場合があります。

ブラウザ・メッセージを確認すると、キャンバスをクリックするたびに、文字列がJSONを介してエンドポイントに送信されていることがわかります。

ブラウザ内のアプリケーションのスクリーンショット

別のブラウザでhttp://localhost:8080/WhiteboardApp/を開くと、一方のブラウザのキャンバス内をクリックするたびに新しい円や正方形が他方のブラウザのキャンバスに複製されることがわかります。

2つのブラウザ内のアプリケーションのスクリーンショット

エンドポイントへのバイナリ・データの送信

これで、アプリケーションで文字列を処理し、JSONを介してエンドポイントに送信できます。文字列は、接続されているクライアントに送信されます。この項では、バイナリ・データを送受信するようJavaScriptファイルを変更します。

バイナリ・データをエンドポイントに送信するために、WebSocketのbinaryTypeプロパティをarraybufferに設定する必要があります。これによって、WebSocketを使用したバイナリ転送はArrayBufferを介して行われることが保証されます。バイナリ・データ変換は、whiteboard.jsdefineImageBinaryメソッドによって行われます。

  1. websocket.jsを開き、WebSocketのbinaryTypeプロパティをarraybufferに設定する次のコードを追加します。
    websocket.binaryType = "arraybuffer";
  2. バイナリ・データをエンドポイントに送信する次のメソッドを追加します。
    function sendBinary(bytes) {
        console.log("sending binary: " + Object.prototype.toString.call(bytes));
        websocket.send(bytes);
    }
  3. onMessageメソッドを変更し、受信メッセージのデータ型に応じてキャンバスを更新するメソッドを選択する次のコード(太字部分)を追加します。
    function onMessage(evt) {
        console.log("received: " + evt.data);
        if (typeof evt.data == "string") {
            drawImageText(evt.data);
        } else {
            drawImageBinary(evt.data);
        }
    }

    バイナリ・データのメッセージを受信すると、drawImageBinaryメソッドが起動されます。

  4. whiteboard.jsを開いて、次のメソッドを追加します。受信バイナリ・データの解析後、drawImageBinaryメソッドを起動してキャンバスを更新します。defineImageBinaryメソッドを使用して、バイナリ・データとしてキャンバスのスナップショットを準備します。
    function drawImageBinary(blob) {
        var bytes = new Uint8Array(blob);
    //    console.log('drawImageBinary (bytes.length): ' + bytes.length);
        
        var imageData = context.createImageData(canvas.width, canvas.height);
        
        for (var i=8; i<imageData.data.length; i++) {
            imageData.data[i] = bytes[i];
        }
        context.putImageData(imageData, 0, 0);
        
        var img = document.createElement('img');
        img.height = canvas.height;
        img.width = canvas.width;
        img.src = canvas.toDataURL();
    }
                        
    function defineImageBinary() {
        var image = context.getImageData(0, 0, canvas.width, canvas.height);
        var buffer = new ArrayBuffer(image.data.length);
        var bytes = new Uint8Array(buffer);
        for (var i=0; i<bytes.length; i++) {
            bytes[i] = image.data[i];
        }
        sendBinary(buffer);
    }

    バイナリ・データをArrayBuffer型として生成し、エンドポイントに送信する場合にdefineImageBinaryを起動する方法を追加する必要があります。

  5. index.htmlを開き、<table>要素を変更して、フォームの表に次の行を追加します。
    <tr>
        <th> </th>
        <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td>
        <td> </td>
        <td> </td>
        <td> </td>
    </tr>
                    

    新しい行には、接続されているピアにキャンバスのバイナリ・スナップショットを送信する「Send Snapshot」ボタンが含まれます。ボタンがクリックされると、whiteboard.jsdefineImageBinaryメソッドが起動されます。

  6. MyWhiteboard.javaを開き、エンドポイントがバイナリ・データのメッセージを受信すると、ピアにバイナリ・データを送信する次のメソッドを追加します。
    @OnMessage
    public void broadcastSnapshot(ByteBuffer data, Session session) throws IOException {
        System.out.println("broadcastBinary: " + data);
        for (Session peer : peers) {
            if (!peer.equals(session)) {
                peer.getBasicRemote().sendBinary(data);
            }
        }
    }

    注意:java.nio.ByteBufferのインポート文を追加する必要があります。

アプリケーションを変更して、ユーザーがエンドポイントへのデータの送信を停止できるようにできます。デフォルトでは、すべてのピアはページを開くとすぐに接続され、データはブラウザからすべての接続されているピアに送信されます。オプションが選択されていない場合にデータがエンドポイントに送信されないよう単純な条件文を追加できます。これは、受信するデータに影響しません。データは引き続き、エンドポイントから受信されます。

  1. whiteboard.jsdefineImageメソッドを変更し、次のコード(太字部分)を追加します。
            drawImageText(json);
        if (document.getElementById("instant").checked) {
            sendText(json);
        }
    }

    id checkedの要素をチェックする条件コード

  2. index.htmlを開き、<table>要素を変更してフォームにチェックボックスを追加します。
    <tr>
        <th> </th>
        <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td>
        <td><input type="checkbox" id="instant" value="Online" checked="true">Online</td>
        <td> </td>
        <td> </td>
    </tr>
                    

    「Online」チェックボックスが選択解除されている場合、データは送信されませんが、クライアントは引き続きエンドポイントからデータを受信します。

「Send Snapshot」ボタンおよび「Online」チェックボックスを追加してアプリケーションを再度実行すると、indexページに新しい要素が表示されます。別のブラウザを開いて「Online」ボタンを選択解除すると、キャンバス内をクリックしたときにJSONメッセージが送信されないことがわかります。

ブラウザ内のアプリケーションのスクリーンショット

「Send Snapshot」をクリックすると、バイナリ・データがエンドポイントに送信され、接続されているクライアントにブロードキャストされます。



関連項目

NetBeans IDEを使用したJava EEアプリケーションの開発方法の詳細は、次のリソースを参照してください。

Java EEの使用に関する詳細は、Java EEチュートリアルを参照してください。

nbj2eeメーリング・リストに登録することによって、NetBeans IDE Java EE開発機能に関するご意見やご提案を送信したり、サポートを受けたり、最新の開発情報を入手したりできます。

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo