LoginSignup
14
14

More than 5 years have passed since last update.

Playframework付属のサンプル'websocket-chat'を見てみる(1/4)

Last updated at Posted at 2014-08-06

WebSocketを使ったこんなチャットのサンプルアプリがついてたので動かしてみた。2つのブラウザ間でほぼ同時にサクサクとチャットを表示してくれる。ローカルホストとはいえスゴイ。WebSocketという技術が個人的に気になりまくりんぐなので楽しみである。
2014-08-06_1846.png

appフォルダは以下のようになっている。
2014-08-06_1608_001.png

Application.java

Application.java
package controllers;

import play.mvc.*;

import com.fasterxml.jackson.databind.JsonNode; 
import views.html.*;

import models.*;

public class Application extends Controller {

    /**
     * Display the home page.
     */
    public static Result index() {
        return ok(index.render());
    }

    /**
     * Display the chat room.
     */
    public static Result chatRoom(String username) {
        if(username == null || username.trim().equals("")) {
            flash("error", "Please choose a valid username.");
            return redirect(routes.Application.index());
        }
        return ok(chatRoom.render(username));
    }

    public static Result chatRoomJs(String username) {
        return ok(views.js.chatRoom.render(username));
    }

    /**
     * Handle the chat websocket.
     */
    public static WebSocket<JsonNode> chat(final String username) {
        return new WebSocket<JsonNode>() {

            // Called when the Websocket Handshake is done.
            public void onReady(WebSocket.In<JsonNode> in, WebSocket.Out<JsonNode> out){

                // Join the chat room.
                try { 
                    ChatRoom.join(username, in, out);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
    }

}
  • index
  • chatRoom
  • chatRoomJs
  • chat

の4つのアクションが定義してある。chatRoomとchatRoomJsがチャットルームの表示、chatがWebSocketのオブジェクトを返してくれているっぽいのがわかる。routesでルーティングを確認してみよう。

routes

conf/routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                                controllers.Application.index()
GET     /room                            controllers.Application.chatRoom(username: String ?= null)
GET     /room/chat                       controllers.Application.chat(username)
GET     /assets/javascripts/chatroom.js  controllers.Application.chatRoomJs(username)

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file                    controllers.Assets.at(path="/public", file)

まず/にアクセスすると、indexが呼び出される。indexではindex.scala.htmlの内容をResultとして返す。

index.scala.html

index.scala.html

@main(null) {

    @if(flash.containsKey("error")) {

        <div class="alert-message error">
            <p>
                <strong>Oops!</strong> @flash.get("error")
            </p>
        </div>

    }

    <div class="alert-message block-message info">
        <p>
            <strong>This is the Play Websocket sample application!</strong> 
            To start, choose a username and sign in using the top right form.
        </p>
    </div>
}

index.scala.htmlは、まずmain.scala.htmlを呼び出し、その中身として自分自身を表示しようとする。ベースとなるmain.scala.htmlにはめ込むイメージである。main.scala.htmlは2つの引数を受け取る(@(connected: String)(content: Html))が、一つ目の(connected: String)にあたるものが@main(null)の'null'、(content: Html)にあたるものが@main(null) {...}で囲まれた部分となる。

ここにはサーバへのアクセス処理は含まれていない模様。特筆するとすれば、flashというオブジェクトを使って一度きりのメッセージを表示している点。これはController側で

flash("error", "Please choose a valid username.");

と定義しておくことでView側で使用できるようになる。
2014-08-06_1712.png

main.scala.html

main.scala.html
@(connected: String)(content: Html)

<!DOCTYPE html>

<html>
    <head>
        <title>Websocket Chat-Room</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/bootstrap.css")">
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
        <script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
    </head>
    <body>

        <div class="topbar">
            <div class="fill">
                <div class="container">
                    <a class="brand" href="@routes.Application.index()">Websocket Chat-Room</a>

                    @if(connected != null) {
                        <p class="pull-right">
                            Logged in as @connected 
                            <a href="@routes.Application.index()">Disconnect</a>
                        </p>
                    } else {
                        <form action="@routes.Application.chatRoom()" class="pull-right">
                            <input id="username" name="username" class="input-small" type="text" placeholder="Username">
                            <button class="btn" type="submit">Sign in</button>
                        </form>
                    }

                </div>
            </div>
        </div>

        <div class="container">

            <div class="content">
                @content
            </div>

            <footer>
                <p>
                    <a href="http://www.playframework.com">www.playframework.com</a>
                </p>
            </footer>

        </div>

    </body>
</html>

main.scala.htmlのハイライトは

main.scala.html
@if(connected != null) {
    <p class="pull-right">
        Logged in as @connected 
        <a href="@routes.Application.index()">Disconnect</a>
    </p>
} else {
    <form action="@routes.Application.chatRoom()" class="pull-right">
        <input id="username" name="username" class="input-small" 
            type="text" placeholder="Username">
        <button class="btn" type="submit">Sign in</button>
    </form>
}

の部分である。

ログインしているかどうか(connectedに文字列が入っているかどうか)で条件分岐し、ログインしていない場合はログイン用のフォーム(methodはGET)を作成、飛び先が@routes.Application.chatRoom()となっている。routesファイルを見ると、

GET    /room    controllers.Application.chatRoom(username: String ?= null)

となっており、今回QueryStringで送信するusername(String型)をchatRoomアクションで受け取るよう定義してあることがわかる。?= nullの部分は送信された値がなかった場合のデフォルト値を指定している模様(ScalaRouting)。

Application.java
public static Result chatRoom(String username) {
    if(username == null || username.trim().equals("")) {
        flash("error", "Please choose a valid username.");
        return redirect(routes.Application.index());
    }
    return ok(chatRoom.render(username));
}

chatRoomアクションの飛び先では、ユーザ名が入力されているかをチェックし、OKならchatRoom.scala.htmlの内容をResultとして返している。これでチャットルームへの入室が完了となる。
2014-08-06_1742.png

今日はここまで。→続き


Playframework付属のサンプル'websocket-chat'を見てみる(2/4)
Playframework付属のサンプル'websocket-chat'を見てみる(3/4)
Playframework付属のサンプル'websocket-chat'を見てみる(4/4)

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14