ITブログ   HTML5.asia

JSF2.3の新機能 <f:websocket>について

1. WebSocketのエンドポイントの定義

          package html5.asia.push;
          
          import java.io.Serializable;
          import javax.enterprise.context.ApplicationScoped;
          import javax.faces.push.Push;
          import javax.faces.push.PushContext;
          import javax.inject.Inject;
          import javax.inject.Named;
          
          @Named("samplePush")
          @ApplicationScoped
          public class SamplePushBean implements Serializable {
            
            @Inject
            @Push(channel = "sample")
            private PushContext push;
            
            synchronized public void sendMessage(String message) {
              push.send(message);
            }
          }
        

16行目で、PushContextクラスのメンバ変数を定義します。Pushアノテーションを付加することにより、エンドポイントが定義されます(エンドポイントは、[サーバ名:ポート番号/コンテキスト名/javax.faces.push/sample]となります)。19行目のsendメソッドを使用することで、WebSocket経由でメッセージを送ることができます。すごくシンプルですね。WebSocket通信するのに、メンバ変数を定義してメソッドを呼んだいるだけです。たったそれだけでWebSocket通信できるのだから。

2. APIをJCDI対応化する

          package html5.asia.api;
          
          import html5.asia.push.SamplePushBean;
          import javax.enterprise.context.RequestScoped;
          import javax.inject.Inject;
          import javax.ws.rs.GET;
          import javax.ws.rs.Path;
          import javax.ws.rs.Produces;
          import javax.ws.rs.QueryParam;
          
          @RequestScoped
          @Path("/v1/api_demo")
          public class SampleApi {
            
            @Inject
            SamplePushBean samplePushBean;
            
            @GET
            @Produces("text/json")
            public String sendMessage(@QueryParam("message") String message) {
              samplePushBean.sendMessage(message);
              return "{}";
            }
          }
        

APIの処理しては、21行目で、messageリクエストパラメータの値をそのまま、WebSocket通信経由で送信しているだけです。SampleApiのインスタンスは、11行の「RequestScoped」アノテーションを付加することにより、JCDI対応化します。よってsamplePushBeanには、JCDI管理されたBeanが割り当てられます。何が便利だというと、外部からのAPI呼出しで、WebSocket機能の使用を、より簡単に、より少ないコーディングで実現することがでます。当初、samplePushBeanにインスタンスが割当られなくて大変苦労しましたが、IBMの「依存性の注入を使用した JAX-RS リソースの実装」のブログで見つけた、「RequestScoped」アノテーションを付加してJCDI対応化するという発想は、目からうろこが落ちた感じです。IBMのブログは、10数年前から利用していますが、質がともて高く英語版もあるので、英語の勉強にもなります。

3. JSF側の実装

          <!DOCTYPE html>
          <html xmlns="http://www.w3.org/1999/xhtml"
              xmlns:h="http://java.sun.com/jsf/html"
              xmlns:f="http://java.sun.com/jsf/core">
            <h:head>
              <meta charset="utf-8" />
              <meta name="viewport" content="width=device-width; initial-scale=1.0" />
              <title>Websocketのサンプル</title>
            </h:head>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
            <script>
              //<![CDATA[
              function socketListener(message, channel, event) {
                message = message
                        .replace(/&/g, '&amp;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;')
                        .replace(/"/g, '&quot;')
                        .replace(/'/g, '&#39;');
                $('#message').append(message + '<br/>');
              }
            //]]>
            </script>
            <h:body>
              初めての「f:websocket」
              <f:websocket channel="sample" onmessage="socketListener"/>
              <div id="message"/>
            </h:body>
          </html>
        

26行目を解説すると、「channel="sample"」は、SamplePushBeanの「@Push(channel = "sample")」に対応します。そのエンドポイントのリスナーは、13行目のsocketListener()メソッドであるということです。20行目で、WebSocket経由で送られてきたメッセージを、27行目の<div>要素の後に追加するだけですが、メッセージの値に応じで、処理を行ったり、JavaScriptを使用して画面遷移をしたりすることも可能です。フロントサイド、バックサイド含めていたって簡単にWebSokectを利用できることがお分かりになると思います。ここでは、詳しくは解説しませんが、JSFの機能を利用してサーバサイド側の処理を行うこともできます(JSFを実務で使用した経験がある人にとっては、説明を聞くまでもないでしょうが)。JSFの機能を利用してサーバサイド側の処理を行うことについては、JSFについてご存知ない方のために、ブログに書く予定です。

4. サンプルWEBアプリケーションの実行

すぐに試せるように、warファイルをダウンロードできるようにしました。動作確認したアプリケーションサーバは、Wildfly(ver 15.0.0.Final)です。 デモの確認手順は、下記のとおりです。
  1. ダウンロードボタンから「jsf_demo.war」ファイルをダウンロードして下さい  warファイルダウンロード
  2. 「jsf_demo.war」ファイルをWildflyサーバにデプロイして、再起動して下さい。
  3. ブラウザで、「http://localhost:8080/jsf_demo/faces/demo.xhtml」のURLを表示して下さい。
  4. 別のブラウザで、「http://localhost:8080/jsf_demo/api/v1/api_demo?message=Hello!」のURLを表示して下さい。
  5. 「Hello!」と画面にメッセージが追加されます。

5. 応用例

今回紹介したWebSocket機能とGoogle Home、IFTTTを連携させて、IFTTT側でAPIを呼び出せば、WEB画面で抽選会を行うことがでます。「抽選を開始して」と声を出して抽選を開始し、WEB画面に当選番号を表示することや、当選した人のブラウザのみに、「Aさん当選おめでとうございます」のメッセージを出すことも可能です。

参考URL
依存性の注入を使用した JAX-RS リソースの実装
JSF 2.3 - The WebSocket Quickstart under Payara Server
JSR 372: JavaServer Faces (JSF 2.3) Specification.
目次表示