是非ためしてもらいたいフルスタックなWebフレームワーク Play

Play framework とは

RoR風のフルスタックフレームワークです。Java5以上。ダウンロードは以下から。
http://www.playframework.org/

今回は play-1.0.1.zip をダウンロード。解凍したディレクトリ内で play を起動してみる。Usageが表示される。

play-1.0.1> play
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.0.1, http://www.playframework.org
~
~ Usage: play cmd [app_path] [--options]
~
~ with,  new      Create a new application
~        run      Run the application in the current shell
~        help     Show play help
~

新しいアプリケーションの作成

以下のコマンドで新しいアプリケーションを作成。

play-1.0.1> play new myApp

myApp というディレクトリが作成され、アプリケーションの準備が整う。

run コマンドで作成したアプリケーションの実行。

play-1.0.1>play run myApp

ブラウザから9000ポートでアクセス可能。
http://localhost:9000

終了時はコマンドプロンプトで Ctrl+C

eclipseからの編集

以下のコマンドにてeclipseプロジェクトに変換。

> play eclipsify myApp

eclipseからインポート。

URLマッピング

Playでは conf/routes ファイルでURLとコントローラクラスとのマッピングを定義。作成直後のroutesファイルは以下の定義。

GET     /                        Application.index
GET     /public/                 staticDir:public
*       /{controller}/{action}   {controller}.{action}

/へのGETアクセスは Application クラスのindexメソッド(アクションメソッド)にマッピングされている。Application クラスは以下。

import play.mvc.*;

public class Application extends Controller {
    public static void index() {
        render();
    }
}

viewテンプレート

Application の index アクションメソッドにより /app/views/Application/index.html が View テンプレートとして呼ばれる。

#{extends 'main.html' /}
#{set title:'Home' /}

#{welcome /}

Playタグにより非常にシンプルな構造。#{extends /} タグにて別のテンプレート(ここではmain.html)を拡張する。index.html テンプレートの親テンプレートとなるのが /app/views/main.html で以下。

<!DOCTYPE html>

<html>
  <head>
    <title>#{get 'title' /}</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}">
    #{get 'moreStyles' /}
    <link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}">
    <script src="@{'/public/javascripts/jquery-1.4.min.js'}" type="text/javascript" charset="utf-8"></script>
    #{get 'moreScripts' /}
  </head>
  <body>
    #{doLayout /}
  </body>
</html>

上記 #{doLayout /} タグにて index.html の内容が body 内に埋め込まれる。

Hello Worldの作成

/app/views/Application/index.html テンプレートを以下のように編集

#{extends 'main.html' /}
#{set title:'Home' /}

<form action="@{Application.sayHello()}" method="GET">
  <input type="text" name="myName" /> 
  <input type="submit" value="Say hello!" />
</form> 

@{...} ノーテーションにて Application.sayHello() アクションメソッドと紐付け。
Application クラスに sayHello アクションメソッドを追加。

public class Application extends Controller {
    ・・・
    public static void sayHello(String myName) {
        render(myName);
    }
}

sayHelloに対応するsayHelloテンプレートを作成 /app/views/Application/sayHello.html

#{extends 'main.html' /}
#{set title:'Home' /}
 
<h1>Hello ${myName ?: 'guest'}!</h1>
 
<a href="@{Application.index()}">Back to form</a>


以下のコマンドにて動作確認

play-1.0.1>play run myApp

レイアウトのカスタマイズ

/app/views/main.html の body タグを以下に変更。

  <body>
    The Hello world app.
    <hr/>
    
    #{doLayout /}
  </body>

共通的にレイアウトが適用される。

validation の追加

sayHello アクションメソッドを以下に変更。

public static void sayHello(@Required String myName) {
    if(validation.hasErrors()) {
        flash.error("Oops, please enter your name!");
        index();
    }
    render(myName);
}

@Required アノテーションにより必須定義。

/app/views/Application/index.html のformタグの上にエラーメッセージの表示を追加。

#{if flash.error}
  <p style="color:#c00">
    ${flash.error}
  </p>
#{/if}

テストスイートの作成

アプリケーションをテストモードで起動。

play test myApp

http://localhost:9000/@tests でアクセス

select allを選択し、Start!で表示されているテストが実行される。unitテストと機能テストとSeleniumテストが行われる。

BasicTestはデフォルトでは以下の実装。必要なテストに変更する。

public class BasicTest extends UnitTest {
    @Test
    public void aVeryImportantThingToTest() {
        assertEquals(2, 1 + 1);
    }
}


同じように ApplicationTest は以下の実装となっている。Playが提供するテスト系にユーティリティにてテストの記述が簡素に可能。

public class ApplicationTest extends FunctionalTest {
    @Test
    public void testThatIndexPageWorks() {
        Response response = GET("/");
        assertIsOk(response);
        assertContentType("text/html", response);
        assertCharset("utf-8", response);
    }
}

selenium テスト

/test/Application.test.html にてデフォルト実装がある。

*{ You can use plain selenium command using the selenium tag }*

#{selenium}
    // Open the home page, and check that no error occured
    open('/')
    waitForPageToLoad(1000)
    assertNotTitle('Application error')
#{/selenium}


以下に変更してValidation処理の検証を行う。

#{selenium}
    // Open the home page, and check that no error occurred
    open('/')
    assertNotTitle('Application error')
    
    // Check that it is the form
    assertTextPresent('The Hello world app.')
    
    // Submit the form
    clickAndWait('css=input[type=submit]')
    
    // Check the error
    assertTextPresent('Oops, please enter your name!')
    
    // Type the name and submit
    type('css=input[type=text]', 'bob')
    clickAndWait('css=input[type=submit]')
    
    // Check the result
    assertTextPresent('Hello bob!')
    assertTextPresent('The Hello world app.')
    
    // Check the back link
    clickAndWait('link=Back to form')
    
    // Home page ?
    assertTextNotPresent('Hello bob!')
#{/selenium}

再びテスト実施にて上記のSeleniumテストが実施される。