Documentation

You are viewing the documentation for the 2.1.5 release in the 2.1.x series of releases. The latest stable release series is 2.4.x.

§初めての Play アプリケーション

Play 2.0 でシンプルな TODO 管理アプリケーションを構築し、クラウドにデプロイしましょう。このサンプルはとても小規模で、数時間でやり通すことができます。

§前提条件

はじめに、 Play のインストールが成功している 事を確かめてください。 Java (バージョン 6 以上) のインストールと、Play のバイナリパッケージの unzip さえすれば始められます。

多くのコマンドを使用するため、 Unix 系 OS を利用する方が効率が良いです。 もし Windows システムを動作させているなら、コマンドプロンプトにいくつかのコマンドを入力する事で、動作させる事も可能です。

もちろん、テキストエディタは必要です。もし Eclipse や IntelliJ のようなフル機能の Java の IDE に慣れているのなら、それらを使うことも可能です。しかし、 Playであれば、編集や開発プロセス自身をフレームワークが管理してくれるため、 Textmate, Emacs もしくは vi のようなシンプルなテキストエディタで楽しみながら作業する事が可能です。

§プロジェクト作成

Play が正しくインストールされているとして、新しくアプリケーションを作成してみましょう。 Play アプリケーションを作成する事はとても簡単であり、 Play コマンドで全て管理されています。全ての Play アプリケーション間で標準のプロジェクト構成になります。

コマンドラインを開き以下のように入力してください:

$ play new todolist

いくつかの質問が表示されます。**simple Java application** を選択しましょう。

play new コマンドが新しいディレクトリ todolist/ を作成し、一連のファイル、ディレクトリを生成します、重要なファイルは以下の通りです:

Play では UTF-8 をエンコーディング形式として採用しており、上記のディレクトリ内に配置された全テキストファイルは本文字セットを使用してエンコードされます。テキストエディタに応じて設定を確認してください。Windows の場合はエディタの文字コード設定は ANSI にする必要があります。

§Play コンソールの使用

一度アプリケーションを作成したら、 Play コンソールを実行できます。新しく作成された todolist/ ディレクトリに行き、以下のコマンドを実行して下さい:

$ play

このコマンドで Play コンソールが起動されます。 Play コンソールから実行できることはいくつかありますが、まずアプリケーションを実行させてみましょう。コンソールプロンプトから、 run とタイプしてください:

[todolist] $ run

development モードで本アプリケーションが実行されています。ブラウザを開き、 http://localhost:9000/ へアクセスしてください:

補足: 詳細は Play 2.0 コンソールを使う を確認してください。

§概要

このアプリケーションがどうやってページを表示しているか確認して行きましょう。

本アプリケーションの主なエントリーポイントは conf/routes ファイルです。このファイルはアプリケーションがアクセス可能な URL の全てを定義しています。生成された routes ファイルを開けば、初期の route を確認できます:

GET /       controllers.Application.index()

上記の記述は web サーバーが / パスへの GET リクエストを受信した時に、 controllers.Application.index() メソッドを呼び出すという事を簡単に説明しています。

どうやって controllers.Application.index メソッドが実行されるのかを確認しましょう。 todolist/app/controllers/Application.java ソースファイルを開いてください:

package controllers;

import play.*;
import play.mvc.*;

import views.html.*;

public class Application extends Controller {
  
  public static Result index() {
    return ok(index.render("Your new application is ready."));
  }
  
}

controllers.Application.index()Result を返す事が確認できます。全てのアクションメソッドは web ブラウザへの HTTP レスポンスを表現する Result を返す必要があります。

補足: アクションについての詳細は、 アクション、コントローラ、レスポンス を確認してください。

ここでは、アクションは HTML コンテントを含む 200 OK のレスポンスを返します。 HTML コンテントはテンプレートによって提供されます。 Play テンプレートは標準 Java メソッド、 views.html.index.render(String message) としてコンパイルされます。

本テンプレートは app/views/index.scala.html ソースファイル上で定義されます。

@(message: String)

@main("Welcome to Play 2.0") {
    
    @play20.welcome(message)
    
}

最初の行は関数の仕様を定義します。ここでは、単一の String 型のパラメータを受け取ります。テンプレートの内容には Scala と HTML (もしくはテキストベースの言語) を一緒に記入しています。 Scala の式は特殊な @ 文字から始まります。

ノート: テンプレートエンジンの式言語として Scala を使用していますが、心配する必要はありません。 Java 開発者にとっては問題にはならず、 Java とほとんど同等の物として使用することができるでしょう。

§開発フロー

さて、新しいアプリケーションにいくつかの変更を加えていきましょう。 Application.java 内でレスポンスの内容を書き換えてみます:

public static Result index() {
  return ok("Hello world");
}

上記の変更によって index アクションはシンプルな text/plainHello world レスポンスを返すようになります。この変更を確かめるために、ブラウザ上でホームページを更新してみましょう:

変更を確認するのにコードを明示的にコンパイルする必要もサーバーを再起動する必要もありません。変更が検出されると、自動的にリロードされます。もし、コードを誤って変更したらどうなるでしょう? やってみましょう:

public static Result index() {
  return ok("Hello world);
}

上記のように変更したら、ブラウザ上でホームページをリロードしてください:

確認された通り、ブラウザ上に直接エラーが表示されます。

§アプリケーションの準備

本 TODO 管理アプリケーションのために、いくつかのアクションと一致する URL が必要になります。 routes ファイルを定義することから始めましょう。

conf/routes ファイルを編集してください。

# Home page
GET     /                       controllers.Application.index()
                                
# Tasks          
GET     /tasks                  controllers.Application.tasks()
POST    /tasks                  controllers.Application.newTask()
POST    /tasks/:id/delete       controllers.Application.deleteTask(id: Long)

全てのタスクを一覧する route 定義を作成し、タスクの作成と削除を処理する2つの定義を作成します。タスク削除を扱うための route には URL パス内に id 変数を定義しています。 id の値は deleteTask アクションメソッドへ渡されます。

ブラウザをリロードすれば、 Play が routes ファイルをコンパイルできないことが確認できます。

これは routes ファイルが参照しているアクションメソッドが存在していないことが原因です。 Application.java ファイルに追記していきましょう。

public class Application extends Controller {
  
  public static Result index() {
    return ok(index.render("Your new application is ready."));
  }
  
  public static Result tasks() {
    return TODO;
  }
  
  public static Result newTask() {
    return TODO;
  }
  
  public static Result deleteTask(Long id) {
    return TODO;
  }
  
}

上記のコードでアクションの暫定的な実装をするために TODO という Result を使用しました。まだアクションの実装を書きたくない場合に、ビルドインの TODO という Result を使用することが可能です。このアクションからは 501 Not Implemented HTTP レスポンスが返るようになっています。

確認するために、 http://localhost:9000/tasks にアクセスできるか試してみましょう。

アクションの実装をはじめる前に修正が必要な最後の項目は index アクションです。タスクの一覧ページに自動リダイレクトするようにします:

public static Result index() {
  return redirect(routes.Application.tasks());
}

見ての通り、 303 See Other の HTTP レスポンスを使用するために ok の代わりに redirect を使用しています。また、tasks アクションの呼び出しに必要な URL を生成するため、リバースルーターを使っています。

補足: 詳細については HTTP ルーティング を参照してください。

§Task モデルの準備

実装を続ける前にアプリケーション内で Task の見え方を定義する必要があります。 classapp/models/Task.java ファイルに作成してください:

package models;

import java.util.*;

public class Task {
    
  public Long id;
  public String label;
  
  public static List<Task> all() {
    return new ArrayList<Task>();
  }
  
  public static void create(Task task) {
  }
  
  public static void delete(Long id) {
  }
    
}

Task の操作を管理するための static メソッドも上記のように作成しました。ここでは各操作のダミー実装を記載しましたが、このチュートリアルの後半、リレーショナルデータベースに関する項目の中でタスクを保存する実装を追加していきます。

§アプリケーションテンプレート

本アプリケーションはタスクリストとタスク作成フォームの両方を持つ単一のウェブページを用います。index.scala.html テンプレートを変更していきましょう:

@(tasks: List[Task], taskForm: Form[Task])

@import helper._

@main("Todo list") {
    
    <h1>@tasks.size() task(s)</h1>
    
    <ul>
        @for(task <- tasks) {
            <li>
                @task.label
                
                @form(routes.Application.deleteTask(task.id)) {
                    <input type="submit" value="Delete">
                }
            </li>
        }
    </ul>
    
    <h2>Add a new task</h2>
    
    @form(routes.Application.newTask()) {
        
        @inputText(taskForm("label")) 
        
        <input type="submit" value="Create">
        
    }
    
}

2つのパラメータを受け取るように以下のテンプレートのシグネチャを変更しました:

フォーム作成用のヘルパー関数を提供する helper._ をインポートしました。これにより、 actionmethod 属性がついた <form> タグ付きの HTML を生成する form 関数や入力用のフォーム HTML を作成する inputText 関数が使用できます。

補足: 詳細については テンプレートエンジンフォームテンプレートヘルパーの利用 を確認してください。

§タスクフォーム

Form オブジェクトはバリデーションを含んだ HTML フォームの定義をカプセル化します。Task クラスのためにフォームを作成しましょう。Application コントローラに以下のコードを追加します。

static Form<Task> taskForm = Form.form(Task.class);

taskForm の型はシンプルな Task を生成するフォームである事を表す Form<Task> 型になります。その他に play.data.*models.* をインポートする必要があります。

JSR-303 のアノテーションを使う事で Task クラスに制約を追加することができます。label フィールドを必須にしてみましょう。

package models;

import java.util.*;

import play.data.validation.Constraints.*;

public class Task {
    
  public Long id;
  
  @Required
  public String label;
  
  ...

補足: 詳細は フォームの定義 を参照してください。

§最初のページをレンダリングする

現在、アプリケーションページを表示するために要求された全ての要素の用意ができました。 tasks アクションを実装しましょう:

public static Result tasks() {
  return ok(
    views.html.index.render(Task.all(), taskForm)
  );
}

本メソッドがタスクリストとタスクフォームを呼出し、 index.scala.html テンプレートによってレンダリングされた HTML を含む 200 OK の結果を返します。

ブラウザ内で http://localhost:9000/tasks にアクセスしてみましょう:

§フォーム投稿処理

現在では、タスク作成フォームを投稿した場合でも、まだ TODO ページが取得されます。 newTask アクションの実装をしていきましょう。

public static Result newTask() {
  Form<Task> filledForm = taskForm.bindFromRequest();
  if(filledForm.hasErrors()) {
    return badRequest(
      views.html.index.render(Task.all(), filledForm)
    );
  } else {
    Task.create(filledForm.get());
    return redirect(routes.Application.tasks());  
  }
}

リクエストデータが入力されている新しいフォームを作成するために bindFromRequest を扱うことができます。もしフォーム内に何らかのエラーがあった場合、エラーを再表示します (ここでは、 200 OK の代わりに 400 Bad Request を使用します) 。もし何のエラーも発生しなければ、タスクを作成し、タスクリストにリダイレクトします。

補足: 詳細は フォーム送信を扱う を参考にしてください。

§データベース内のタスクを永続化する

アプリケーションを使いやすくするため、データベースにタスクの情報を永続化するようにしましょう。本アプリケーション内でデータベースを利用可能にします。 conf/application.conf ファイル内に以下の内容を追記してください:

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"

現在、 H2 というシンプルなインメモリデータベースを使用するようにしています。この定義を有効にするためにサーバーを再起動する必要はありません、ブラウザを更新するだけでデータベースをセットアップします。

これからチュートリアル内でデータベースを検索するために (Play のデフォルト ORM である) Ebean を使用します。使用するためには application.conf ファイルで有効にする必要があります。

ebean.default="models.*"

これで、 default データソースに接続された Ebean サーバーが作成され、models パッケージ以下にある全てのエンティティを管理するようになります。Task クラスを正しい Ebean エンティティに変換しましょう。

package models;

import java.util.*;

import play.db.ebean.*;
import play.data.validation.Constraints.*;

import javax.persistence.*;

@Entity
public class Task extends Model {

  @Id
  public Long id;
  
  @Required
  public String label;
  
  public static Finder<Long,Task> find = new Finder(
    Long.class, Task.class
  );
  
  ...

Task クラスを play.db.ebean.Model スーパークラスから継承するようにしました。これで Play 組み込みの Ebean ヘルパーにアクセスする事ができます。また永続化のためのアノテーションと、クエリを作成するための find ヘルパーを作成しました。

CRUD 操作のメソッドを実装しましょう。

public static List<Task> all() {
  return find.all();
}

public static void create(Task task) {
  task.save();
}

public static void delete(Long id) {
  find.ref(id).delete();
}

本アプリケーションで遊んでみましょう、新しいタスク作成は動作すると考えられます。

補足: 詳細は Ebean を参照してください。

§タスクの削除

タスクを作成することができるようになった後はそれらのタスクを削除する事ができるようにする必要があります。 deleteTask アクションの実装を (とてもシンプルに) 終わらせるだけです。

public static Result deleteTask(Long id) {
  Task.delete(id);
  return redirect(routes.Application.tasks());
}

§Heroku へのデプロイ

全ての機能が完成しました。本アプリケーションを成果物としてデプロイしましょう。 Heroku へデプロイします。はじめに Procfile を Heroku 用に作成する必要があります。 Procfile をアプリケーションの root ディレクトリに作成してください。

web: target/start -Dhttp.port=${PORT} -DapplyEvolutions.default=true -Ddb.default.url=${DATABASE_URL} -Ddb.default.driver=org.postgresql.Driver

補足: Heroku へのデプロイの詳細については Heroku へのデプロイ を参照してください。

Heroku 上で起動する際に、アプリケーションの設定を上書きするためにシステムプロパティを使用します。 Heroku は PostgreSQL データベースを提供しているため、 要求されたドライバーをアプリケーションの依存関係に追加する必要があります。

project/Build.scala ファイルに依存関係を明記してください。

val appDependencies = Seq(
  "postgresql" % "postgresql" % "8.4-702.jdbc4"
)

補足: 依存性の管理については 依存性の管理 を参照して下さい。

Heroku はアプリケーションのデプロイに git を使用します。まずは git リポジトリを初期化しましょう。

$ git init
$ git add .
$ git commit -m "init"

これで Heroku 上にアプリケーションを作ることが出来ます。

$ heroku create --stack cedar

Creating warm-frost-1289... done, stack is cedar
http://warm-1289.herokuapp.com/ | [email protected]:warm-1289.git
Git remote heroku added

さらに git push heroku master を使ってアプリケーションをデプロイします。

$ git push heroku master

Counting objects: 34, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (34/34), 35.45 KiB, done.
Total 34 (delta 0), reused 0 (delta 0)

-----> Heroku receiving push
-----> Scala app detected
-----> Building app with sbt v0.11.0
-----> Running: sbt clean compile stage
       ...
-----> Discovering process types
       Procfile declares types -> web
-----> Compiled slug size is 46.3MB
-----> Launching... done, v5
       http://8044.herokuapp.com deployed to Heroku

To [email protected]:floating-lightning-8044.git
* [new branch]      master -> master

Heroku はアプリケーションを構築し、クラウド上のどこかのノードにデプロイします。アプリケーションのプロセス状態を確認できます。

$ heroku ps

Process       State               Command
------------  ------------------  ----------------------
web.1         up for 10s          target/start

起動したら、ブラウザで開いてみましょう。

あなたの初めてのアプリケーションがアップロードされ、稼働しています!