サーバサイドはいつものようにGlassfish 4.0。まずは寺田さんのブログを見つつメッセージ送信用のページで入れたメッセージが表示されるようにするとこまで持っていく。(元のブログのようにツイッターを見に行きはしないで、index.htmlで入れたものが表示されるようにする。)
サーバ用のエンドポイント(ws://localhost:8080/first/hello/)
package jp.co.epea.first; import java.util.Collections; import java.util.HashSet; import java.util.Set; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/hello/") public class HelloWorld { static Set<Session> sessions = Collections .synchronizedSet(new HashSet<Session>()); @OnMessage public void onMessage(String message) { System.out.println("message[" + message + "]"); for (Session s : sessions) { s.getAsyncRemote().sendText(message); } } @OnOpen public void open(Session sess) { System.out.println("開始します:" + sess.getId()); sessions.add(sess); } @OnClose public void close(Session sess) { System.out.println("終了します:" + sess.getId()); sessions.remove(sess); } @OnError public void error(Session sess,Throwable t) { System.out.println("エラーです:" + sess.getId()); t.printStackTrace(); } }
メッセージ送信用のページ(http://localhost:8080/first/index.html)
<!DOCTYPE html> <html> <head> <title>WebSocketテスト</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script> <script type="text/javascript"> var socket; $(document).ready(function(){ var host="ws://localhost:8080/first/hello/"; socket = new WebSocket(host); socket.onmessage = function(message){ $('#log').append(message.data + "<br/>"); } $('#send').click(function(){ var text = $('#msg').val(); socket.send(text); $('#msg').val(''); }) }); </script> </head> <body> <h1>WebSocketテスト</h1> <div id="log"> </div> <input id="msg" type="text"/> <button id="send">送信</button> </body> </html>
クライアントサイドの作成の流れは
(手順1と3は省略)
2.足りない依存関係を追加
tyrus-clientとtyrus-container-grizzlyはこちらのブログを参考にしたときに「Grizzly 関連の jar」の今版として使えそうなので試したところいけたっぽいので持ってきた。(ユーザガイド)
<dependencies> <dependency> <groupId>com.oracle</groupId> <artifactId>javafx</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>C:\dev\pleiades43\java\7\lib/jfxrt.jar</systemPath> </dependency> <dependency> <groupId>org.glassfish.tyrus</groupId> <artifactId>tyrus-client</artifactId> <version>1.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.glassfish.tyrus</groupId> <artifactId>tyrus-container-grizzly</artifactId> <version>1.1</version> <scope>compile</scope> </dependency> </dependencies>
4.とりあえず動くようになるために最低限の修正を加える
TwitterClientのアノテーションを@ClientEndpoint、@OnOpen、@OnMessage、@OnCloseに変更。
SampleController.javaのURLを修正。
ClientEndpointConfigurationの行をコメントアウト。
URI clientURI = new URI("ws://localhost:8080/first/hello/"); //ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();
動作確認
サーバを起動する。
JavaFXを起動する。
start timelineボタンをクリックしてサーバと接続
(コンソールメッセージ) Connection had opened.
index.htmlからメッセージを送信
JavaFX側に表示される
一応これで動作しているようなのでこいつを基点に触っていくことにする。
(JavaFX側をXボタンで閉じたときにOncloseが呼ばれてないっぽいけど、実装的にそういう動きになるのか環境がおかしいのか。。。。。)
2013/11/03追記
子の実装ではJavaFXのTableViewを使用することで、WebSocket側のスレッドによる変更がJavaFXのスレッドに通知されている。(オブザーバ)
桜庭さんに伺ったところ、「(GUIはそっちのスレッドから動かすのが基本なので)きちんと動かないことあるかもよ」とのことでした。
他の日記ではLabelで同期しようとした場合にPlatform.runLaterでJavaFXのスレッドに処理を戻しているけど、そちらの方法が基本とのことでした。