playframework 2.0 javaと websocketでつくる リアルタイムmvc webアプリケーション

91
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション 原 一浩 @kara_d

Upload: kazuhiro-hara

Post on 24-May-2015

17.390 views

Category:

Technology


4 download

DESCRIPTION

JavaOne Tokyoの時の資料です。http://www.oracle.co.jp/javaone/2012/timetable/index.html Blogにて補足説明があったりします。 http://blog.greative.jp/

TRANSCRIPT

Page 1: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

PlayFramework 2.0 JavaとWebSocketでつくるリアルタイムMVC

Webアプリケーション

原 一浩 @kara_d

Page 2: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

原 一浩 @kara_d NetBeans / SublimeText 2

Page 3: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

デザイントレンド、統計、システム

何してる人?

Greative is Great Creative

Page 4: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

本日のセッション内容

4

Page 5: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

本日のセッション内容

5

サンプルダウンロードURL

Page 6: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

目次➡ PlayFrameworkとWebSocketの概要➡ WebSocketアプリ制作の概要• Play 1.2.x

• Play 2.0

➡ サンプル:Reversiの実装とデモ➡ まとめ

6

Page 7: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play Frameworkとは

7

Page 8: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFrameworkとは➡ オープンソース(zenexity製)➡ non Servlet、non XML ➡ ステートレス➡ MVCフレームワーク➡ ホットデプロイ➡ ノンブロッキング IO➡ HTTPマッピング➡ テスト環境➡ シェルサポート

8

Page 9: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFramework 1.2.xまで➡ テンプレートはGroovy➡ フルスタック➡ JPA拡張によるORM➡ Javaベース➡ Pythonによるシェル➡ Scalaモジュール

9

Page 10: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFramework 2.0➡ テンプレートはScala➡ モジュール型➡ 一部ORM選択可能• JavaはEBean

• ScalaはAnormやScalaQuery

➡ Scalaベース➡ SBTによるビルドシステム• 従来のplayコマンドに相当

➡ Akkaによる非同期処理➡ Java/Scalaサポート

10

Page 11: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFramework 2.0 more...➡ ドキュメントが整備➡ サンプルが豊富➡ CoffeeScriptサポート➡ LESSサポート➡ Google Clojure Compilerサポート➡ ヘルパー機能

11

Page 12: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

どちらを使うべきか?➡ 安心の1.2.x• 大量のサードパーティモジュール

• バグフィックスが進んでいる

• 業務で使用実績

➡ 挑戦の2.0• モジュールは、あまりない

• 出たばかりで、まだバグ多い

• 業務実績などもこれから

12

アプリの互換性は、ほぼありません

Page 13: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ニュース➡ 最近本家のMLがごたごたしてた➡ 今後1.2系はメンテナンスモードに• つまり1.3は出ない

• 1.2.5は月末に出るっぽい

➡ 2.0は、JavaとScala両方を今後サポートしていく➡ 1.2系をforkする人も?➡ 1.2系と2.0ではサイトを分ける➡ 今後はプロジェクトのテンプレートはgiter8で

13

Page 14: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play 2.0 Overview

14

Page 15: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play 2.0フォルダ➡ app• controllers

• models

• views

➡ conf• application.conf

• routes

➡ logs➡ project➡ public• images

• javascripts

• stylesheets

➡ target• IDEを使う人には大事

15

Page 16: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play2.0のサイト構築、基本の流れ(Java)➡ モデルの構築• テスト:Unit Test

➡ コントローラーの構築• テスト:Functional Test

➡ ビューの構築• テスト:Selenuimベースのfluentlenium

16

Page 17: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデル➡ ORMとしてEBeanを採用➡ findやバリデーション(Constraints.*)に対応

17

@Entitypublic  class  User  extends  Model{        @Id        public  Long  id;                @Constraints.Required        public  String  name;}

Page 18: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

コントローラ➡ 基本、Resultを返す

18

public  class  Application  extends  Controller  {    public  static  Result  index()  {        return  ok(index.render());    }}

Page 19: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

レイアウト➡ レイアウトとビューの区別はない➡ 呼び出しによる入れ子構造

19

@(title:  Html,  nav:  String  =  "")(content:  Html)<!DOCTYPE  html><html>    <head><title>@title</title></head>    <body>        <h1>@title</h1>                @content    </body></html>

main.scala.html

Page 20: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビューテンプレート➡ main.scala.htmlを呼び出す➡ 引数と内容(content)

20

@main(Html("Samples"))  {    <p>Hello!</p>}

index.scala.html

Page 21: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

リアルタイム通信サーバのこれまで

21

Page 22: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Flashでのリアルタイム通信➡ Adobe Flash Communication Server➡ Adobe Flash Media Server

Real Time Messaging Protocol(RTMP)➡ Red5• http://www.red5.org/

• Javaで作られている

• オープンソース

22

Page 23: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketとは

23

Page 24: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketは、W3CとIETFが策定➡ 元々はHTML5の一部➡ 双方向の通信技術➡ AjaxやCommetよりも自然に双方向通信➡ コネクション後、専用のプロトコルで通信• ハンドシェイク

• ws:もしくはwss:※

➡ 最終仕様は、RFC6455。対応は下記• IE 10 Platform Preview 5※

• Firefox 11

• Google Chrome 16

• Safari 最新※

24

Page 25: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket未対応ブラウザへ

25

Page 26: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

web-socket-js➡ https://github.com/gimite/web-socket-js• Google Chrome 4 or later, Firefox 6 or later

• Firefox 3 to 5, Internet Explorer 8, 9 + Flash Player 10 or later

26

Page 27: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFrameworkでの利用➡ ダウンロードしたら、• public/javascripts/ に「swfobject.js」「web_socket.js」

• public/swfs/ に「WebSocketMain.swf」

• 配置し、JavaScript側で呼び出せるようにしたら終わり

27

Page 28: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

JavaScriptでのWebSocketの接続方法

➡ Flashを介している点が異なる➡ こうすることで未対応ブラウザでも動作可能

28

WEB_SOCKET_SWF_LOCATION  =  "SWFを配置したパス";

WEB_SOCKET_DEBUG  =  false;

var  socket;socket  =  new  WebSocket('@routes.Application.game().webSocketURL(request)')

Page 29: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

JavaScriptのWebSocketのAPI➡ socket = WebSocket(url, protocols)➡ socket.send()➡ socket.close()

イベントハンドラ➡ socket.onmessage➡ socket.onopen➡ socket.onerror➡ socket.onclose

29

Page 30: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket通信の確認にはChromeが便利

30

Page 31: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFrameworkとWebSocket

31

Page 32: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play1.2.3➡ hybi-00• Chrome 14までサポート

Play1.2.4➡ hybi-10• バージョン8

• Chrome 16までサポート

パッチ(Lighthouse 1240 patch)➡ RFC6455• 最新版に対応

32

Page 33: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

パッチ(Lighthouse 1240 patch)の当て方➡ 該当のパッチを当てる• https://github.com/playframework/play/pull/438 を参照

• framework/src/play/server/PlayHandler.java を修正

➡ 修正後、antタスクを実行

33

$  ~/play-­‐1.2.4/framework$  ant  Buildfile:  /Users/harakazuhiro/play-­‐1.2.4/framework/build.xml.....BUILD  SUCCESSFULTotal  time:  22  seconds

Page 34: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

パッチが当たったリビルド版➡ バージョン表記が「play! 1.2.x-localbuild」に

34

$  play  run                                                                                                          ~                _                        _  ~    _  __  |  |  __  _  _    _|  |~  |  '_  \|  |/  _'  |  ||  |_|~  |    __/|_|\____|\__  (_)~  |_|                        |__/      ~~  play!  1.2.x-­‐localbuild,  http://www.playframework.org

Page 35: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play以外の対応、ご参考まで

35

Page 36: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketをフレームワークに載せる意味➡ Webアプリケーションとのシームレスな統合➡ WebSocketをコントローラーにして設計が容易に➡ 認証系、データ管理系の実装が楽になる

WebSocketアプリケーションとポート➡ 基本的には、Playが動いているポートになる➡ Apacheのmod_proxyを経由させている場合は注意

36

Page 37: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play 1.2.4のWebSocket

37

Page 38: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketController➡ Staticによるアクション➡ ルーティングが可能➡ InboundとOutboundの2チャンネル➡ request、params、validation、session➡ disconnect()で通信の切断➡ awaitメソッドで処理の待機➡ ビューで、wsプロトコルのURLに• Routesでプロトコルの指定が必要

38

Page 39: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

InboundとOutbound➡ Inbound• WebSocketの受信

• WebSocketのソケットオープン中、 inbound.isOpen()がtrue

• inbound.nextEvent()にて、イベントを取得

➡ Outbound• WebSocketの送信

• outbound.send(String string)にて送信

• sendメソッドには、opcodeを指定可能- outbound.send(byte opcode, byte[] data);

39

Page 40: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Outboundあれこれ➡ テキストフレームは、通常下記みたいな利用をするが、• outbound.send("quit:ok");

➡ JSONでも送信が可能。sendJsonを使用する• outbound.sendJson(Object);

➡ 生データ• send(

byte opcode, byte[] data)

40

Page 41: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

テキストフレームのやりとり➡ 受信• play.mvc.Http.WebSocketEvent.TextFrameから

Matcherを使ってtextDataを取り出す

➡ 送信• outbound.send(String string)を使って送信

41

for(String  textData:  TextFrame.match(e._1))  {

       ...処理...

}

Page 42: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

PlayFramework 1.2.4でのサンプル

42

Page 43: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket:サーバーとクライアント

43

WebSocketController

DB PlayFramework

Webサイト

WebSocketハンドシェイク

WebSocketソケット通信

WebSocketEvent

ModelEvent

TextFrame

SocketClose

BinaryFrame

Join

Message

Leave

アプリごとにイベントデザインが必要

Outbound

Inbound

1

2

34

5

Page 44: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

全体構成➡ クライアント• プロパティを「:」でつないだメッセージ

• コマンド : ユーザー : メッセージ

• message : name : text

➡ サーバー• WebSocketControllerクラスを継承したChatRoomSocket

• ChatRoomSocketには、joinメソッドのみがある

• ChatRoomモデル内でチャットのイベントを設定

• inbound.isOpen()の限りループ- Either<WebSocketEvent,ChatRoom.Event> eが評価されない限りは停止

44

Page 45: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

• 各種イベントにマッチするものがあれば、各処理を実行- WebSocketのイベントが、TextFrameかつTextFrameがquit- WebSocketのイベントが、TextFrame- Chatroom内のイベントが、ChatRoom.Joinクラス- Chatroom内のイベントが、ChatRoom.Messageクラス- Chatroom内のイベントが、ChatRoom.Leaveクラス- WebSocketのイベントが、SocketClosed

45

public  static  void  join(String  user)  {        while(inbound.isOpen())  {                Either<WebSocketEvent,ChatRoom.Event>  e  =                          await(Promise.waitEither(                                inbound.nextEvent(),                                  roomMessagesStream.nextEvent()));

               ...各種処理...

       }}

ここで停止

Page 46: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ChatModelは、イベント管理モデル➡ 内部にEventクラスというabstractなクラスを用意➡ Eventクラスを継承した各種イベントクラス• Joinクラス

• Leaveクラス

• Messageクラス

ChatRoomSocketでのイベント判定➡ ChatRoom.Eventクラスをパターンマッチで分岐• ClassOf(ChatRoom.Join.class).match(e._2)

• ClassOf(ChatRoom.Message.class).match(e._2)

• ClassOf(ChatRoom.Leave.class).match(e._2)

46

Page 47: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Play 2.0のWebSocket

47

Page 48: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket:サーバーとクライアント

48

Model(In)

WebSocket.out

DB PlayFramework

Webサイト

WebSocketハンドシェイク

WebSocketソケット通信

WebSocket.in

Event

onMessage

onClose

Join

Message

Quit

アプリごとにイベントデザインが必要

Out

onReady

AkkaonReceive

1

In

2

3

4

Page 49: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket用コントローラ➡ Staticによるアクション➡ ルーティングが可能➡ WebSocketオブジェクトの入出力• InとOutの2チャンネル

➡ ほとんどの処理はモデルに移動➡ onReady()イベントを定義

49

Page 50: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket対応のコントローラー

50

public  static  WebSocket<JsonNode>  game(        final  String  username        )  {        return  new  WebSocket<JsonNode>()  {                public  void  onReady(WebSocket.In<JsonNode>  in,  WebSocket.Out<JsonNode>  out){                        try  {                                  Reversi.join(username,  in,  out);                        }  catch  (Exception  ex)  {                                ex.printStackTrace();                        }                }        };}

Page 51: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket用モデル➡ 専用のクラス• UntypedActor

➡ Akkaベースの非同期プログラミング➡ 同期処理は、Awaitメソッド➡ In.onMessageと、In.onClose➡ onReceive()イベントを定義➡ Out.write()で送信➡ メンバーとチャンネル

51

Page 52: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket対応のモデルの一部

52

public  void  onReceive(Object  message)          throws  Exception  {        if  (message  instanceof  Join)  {                //  Received  a  Join  message        }  else  if  (message  instanceof  Message)  {                Message  talk  =  (Message)  message;                notifyAll(                        "talk",  talk.username,  talk.text,                          talk.x,  talk.y,  talk.uuid);        }  else  if  (message  instanceof  Quit)  {                //  Received  a  Quit  message        }}

Page 53: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

AkkaとWebSocketの関係➡ WebSocket.In• メッセージ受け取り時

• onMessage(Callback<A> callback)- event

➡ Akkaのアクター• イベントの監視、非同期処理

• onReceive(Object message)

➡ WebSocket.Out• 通信の書き出し

• write(A frame)

53

WebSocket.In

ActorRef

WebSocket.Out

tell

write

Page 54: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

サンプル:Reversi

54

Page 56: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Reversi作成の手順➡ Playアプリケーションの作成➡ メッセージフォーマットの設計➡ イベントモデルの設計➡ コントローラ、モデルの作成➡ ルーティングの作成➡ ビューの作成

56

Event SchemeRestful Make Format Model and Controller Routing Front

【参考】作業ステップをつけています

Page 57: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Playアプリケーションの作成(1)➡ システム企画• ユーザーは2人(BlackとWhite)の選択

• 盤面をロールオーバーすると相手にも伝わる

• 盤面をクリックすると自分の色に変わる

• 駒はどこでも配置可能

57

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeMake Format Model and Controller Routing Front

WSLogin Game

ゲーム画面トップページ

画面遷移 WebSocket

Page 58: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Playアプリケーションの作成(2)➡ トップページ• http://URL/

➡ ゲーム画面• http://URL/reversi/

➡ WebSocket• ws://URL/reversi/game?username=hoge

58

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeMake Format Model and Controller Routing Front

WS

Login

Game

Page 59: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

Playアプリケーションの作成(3)➡ コントローラ• app/controllers/Application.java- HTTPリクエストを受けるところ

➡ モデル• app/models/Reversi.java- WebSocket周りのイベント処理を記述

➡ ビュー• app/views/index.scala.html

• app/views/main.scala.html

• app/views/reversi.scala.html

59

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeMake Format Model and Controller Routing Front

Page 60: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

メッセージのフォーマット(JSON)を決める➡ kind• join、talk、quitの各種フラグ

➡ user• ユーザー名(black or white)

➡ x、y➡ uuid• 各升目のユニークid

➡ message• thinkOver、thinkOut、black、whiteの各メッセージ

60

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Model and Controller Routing Front

Page 61: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

イベントの種類を決める➡ 各イベントごとにクラスを作成➡ public static class

Join(username、channel) … 参加➡ public static class

Message(username、text、x、y、uuid) … 送信➡ public static class

Quit(username) … 終了

61

Event SchemeRestful Make Format Model and Controller Routing FrontRestful Make Format Model and Controller Routing Front

Page 62: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

コントローラの作成(1):Application.java➡ 各種メソッドを実装➡ public static Result

index() … トップページ• index.scala.html を表示

➡ public static Result

reversi(username) … ゲーム画面• ゲーム画面用アクション

• ユーザー名を取得し、ゲーム画面 reversi.scala.html を表示

62

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 63: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

コントローラの作成(2):Application.java➡ public static WebSocket<JsonNode>

game(final String username) … WebSocket• WebSocket用アクション

• 初接続時は、ユーザー名をメンバーとしてJoinメソッドを呼び出し

• 2回目以降は、JsonFrameをInboundとして処理

63

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 64: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(1):Reversi.javaの構成➡ static ActorRefgame … アクター

➡ Map<String, WebSocket.Out<JsonNode>>members … メンバー一覧

➡ public static voidjoin(username, in, out) … 参加メソッド

➡ public void

onReceive(message) … 受信➡ public void

notifyAll(kind, user, text, x, y, uuid) … 全員に通知

64

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 65: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(2)➡ イベント用のインナークラス用意• Join

• Message

• Quit

65

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

public  static  class  Join  {        final  String  username;        final  WebSocket.Out<JsonNode>  channel;        public  Join(                String  username,                  WebSocket.Out<JsonNode>  channel        )  {                this.username  =  username;                this.channel  =  channel;        }}

Page 66: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(3)➡ static ActorRefgame … アクター

➡ Map<String, WebSocket.Out<JsonNode>>members … メンバー一覧

66

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

static  ActorRef  game  =      Akka.system().actorOf(new  Props(Reversi.class));

Map<String,  WebSocket.Out<JsonNode>>  members  =      new  HashMap<String,  WebSocket.Out<JsonNode>>();

Page 67: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(4)➡ public static voidjoin(username, in, out) … 参加メソッド• 接続を行う最初のみ呼び出される

• ユーザー名と、Inbound、Outboundを引数

• Joinクラスのインスタンスをメッセージとしてgameに送信

• InboundのonMessageハンドラを設定- Messageクラスのインスタンスを送信

• InboundのonCloseハンドラ時を設定- Quitクラスのインスタンスを送信

67

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 68: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(5)➡ public void

onReceive(message) … 受信• 送信されてきたメッセージのクラスによって処理を振分け

• Joinクラスだった場合- メンバーに追加

• Messageクラスだった場合- Outboundにメッセージを送信

• Quitクラスだった場合- メンバーからusernameを削除- 退出のメッセージ

68

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 69: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

onReceiveメソッドの抜粋

69

public  void  onReceive(Object  message)          throws  Exception  {        if  (message  instanceof  Join)  {                //  Received  a  Join  message        }  else  if  (message  instanceof  Message)  {                Message  talk  =  (Message)  message;                notifyAll(                        "talk",  talk.username,  talk.text,                          talk.x,  talk.y,  talk.uuid);        }  else  if  (message  instanceof  Quit)  {                //  Received  a  Quit  message        }}

Page 70: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

モデルの作成(6)➡ public void

notifyAll(kind, user, text, x, y, uuid) … 全員に通知• 各プロパティをJSON形式で格納

• JSONをメンバー全員に送信

70

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Routing Front

Page 71: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ルーティングの設定➡ ルーティングは、conf/routesファイルを編集

71

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Front

GET          /                            controllers.Application.index()GET          /reversi              controllers.Application.reversi(username:  String  ?=  null)GET          /reversi/game    controllers.Application.game(username)

Page 72: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(1):ビューですること➡ レイアウトの用意➡ ログイン画面を用意➡ ゲーム画面を用意➡ ゲーム用のクラスを用意➡ 通信用のJavaScriptを用意➡ マウスイベント用のJavaScriptを用意

72

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

Page 73: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(2)➡ レイアウトの用意

73

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

Page 74: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(3)➡ ログイン画面を用意

74

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

Page 75: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(4)➡ ゲーム画面を用意

75

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

Page 76: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(5)➡ ゲーム用のクラスを用意

76

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

.white .black .thinkOut .thinkOver

Page 77: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(6)➡ 通信用のJavaScriptを用意• WebSocketに接続

• メッセージを受信したら、内容に応じて処理

• kindがtalkなら、駒の配置もしくはロールオーバーの表示

77

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

var  chatSocket  =  new  WS("WEBSOCKET")var  receiveEvent  =  function(event)  {    var  data  =  JSON.parse(event.data);

   //  各種処理}chatSocket.onmessage  =  receiveEvent;

Page 78: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ビュー周りの設定(7)➡ マウスイベント用のJavaScriptを用意• mouseover時- textに"thinkOver"- x座標、y座標、uuidに $(this).attr('id')

• mouseout時- textに"thinkOut"、その他は同じ

• click時- textに"ユーザー名"、その他は同じ

➡ WebSocketとして送信• chatSocket.send(JSON.stringify(オブジェクト));

78

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

Page 79: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocket通信中のJSON➡ コマンドラインにて確認可能

79

Event SchemeRestful Make Format Model and Controller Routing FrontEvent SchemeRestful Make Format Model and Controller Routing

org.codehaus.jackson.node.ObjectNode@8bfaf9f[    _children={kind="talk",  user="black",  x=5,  y=4,  uuid="4_5",  message="thinkOut",  members=["black"]}    _nodeFactory=org.codehaus.jackson.node.JsonNodeFactory@fbf00a9];

Page 80: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

F.javaの話

80

Page 81: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

F.java:Play 1.2.x➡ WebSocket周りを見ていくと、必ず当たる壁➡ Javaで関数言語的な使い方をサポートするライブラリ• Either- E2、E3、E4、E5まである- Haskel由来?

• ArchivedEventStream- イベントのキューとして扱う仕組み

• Matcher- パターンマッチ用

• Promise- 非同期処理

81

Page 82: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

パターンマッチFor文:Play 1.2.x

82

for(String  a:  TextFrame.match(e._1))  {

       ...処理...

}

for(String  a:  TextFrame.and(Equals("quit")).match(e._1))  {

       ...処理...

}

明示的なキャストが存在しないので、すべてがタイプセーフであり、コンパイラによって型チェックが行われます。

Page 83: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

F.javaのMatcher周り:Play 1.2.x➡ String• 文字列でマッチ

➡ ClassOf• クラスでマッチ

➡ StartsWith• プレフィックスでマッチ

➡ Re• 正規表現パターンでマッチ

➡ Equals• 等価な文字列でマッチ

83

Page 84: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketEvent周りのMatcher➡ SocketClosed.match()• WebSocketCloseかどうかでマッチ

➡ TextFrame.match()• WebSocketフレームがバイナリでなく、なおかつtextDataでマッチ

➡ BinaryFrame.match()• WebSocketフレームがバイナリで、binaryDataでマッチ

84

Page 85: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

F.java:Play 2.0➡ Javaで関数言語的な使い方をサポートするライブラリ• Either- E2相当のみになった

• Callback- Callback0、Callback1、Callback2、Callback3まである- コールバックを実現する

• ArchivedEventStream- Akkaが肩代わり

• Matcher- なくなった

• Promise- 独自実装、Akkaとの連携もあり

85

Page 86: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

F.javaの利用について➡ F.javaはバージョンごとに変化が激しい➡ 現状は読むのみに➡ WebSocket周りでは必須

86

Page 87: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

まとめ

87

Page 88: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketアプリの設計・構築手順➡ Playアプリケーションの作成➡ メッセージフォーマットの設計➡ イベントモデルの設計➡ コントローラ、モデルの作成➡ ルーティングの作成➡ ビューの作成

88

Event Scheme

Restful

Make Format

Model and Controller

Routing

Front

クラスベースハンドラのイベント駆動プログラム関数型風味

WebSocketは、チャットを作るための機能ではない

Page 89: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

WebSocketはどこで役に立つのか?➡ ログイン以降は、ユーザーによる細かな操作が続く➡ Ajaxで行ってきた部分の上位バージョンとして➡ ブラウザで閲覧中にリアルタイム通信が必要なとき➡ 業務アプリなど、利用人数が限られたサイトでのレスポンスの向上

➡ Pushstate(Pjax)と組み合わせてみよう

89

PjawPushstate JavaScript with WebSocket

Page 90: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

今後の研究課題➡ 既存の通信手段とのパフォーマンス比較➡ 認証がからむケースのセキュアなWebSocket➡ WebSocketのデータを保存のベストプラクティス➡ イベントの登録管理をもっとスマートに➡ PlayにおけるWebSocketの負荷の調査➡ サーバー構成の研究➡ ネームスペースの実装(Socket.IO)

90

Page 91: PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション

https://github.com/karad/PlayWebSocketReversi

ありがとうございました

91

PlayFramework + WebSocket の勉強会 もよろしくhttp://www.facebook.com/groups/313802075344855/

詳しくは @kara_d まで