連載
» 2012年08月23日 00時00分 公開

Java開発者がScalaでPlay frameworkのビューを作るにはJavaの常識を変えるPlay framework入門(3)(2/3 ページ)

[木村重昭, 多田丈晃,株式会社ビーブレイクシステムズ]

サンプルアプリのテンプレートを読んでみよう

図2 ビューファイルのありか 図2 ビューファイルのありか

 サンプルプロジェクトでは始めから2つのビューを定義したファイルが作成されます。ビューファイルはapp/viewsの中に置きます。ファイル名は「.scala.html」で終わる拡張子の名称を付けます。


 サンプルプロジェクトのテンプレートの機能は簡単に説明すると以下の通りです。

  • index.scala.html
    「http://localhost:9000/」のリクエストの結果を表示するためのテンプレート
  • main.scala.html
    index.scala.htmlから呼び出されるテンプレート

 なお前回の連載で書き直したものは、これらのテンプレートを使用していません。テンプレートを使用するためにはApplicationクラスのindexメソッドの戻り値に気を付ける必要があります。前回修正したときは戻り値に直接表示したい文字列を設定しました。

return ok(msg.toString());

 この方法ですと、テンプレートを使用せず単純に文字列を出力するだけです。テンプレートを使用するためにはサンプルプロジェクトを作ったときの戻り値の返し方に戻す必要があります。

return ok(index.render("Your new application is ready."));

 returnの後から順に説明していきます。まず、「ok」はhttpプロトコルで正常な結果を返す意味のメソッドです。ok以外にもnotFoundなどの異常な結果を返すようなものも存在しますが、ok以外の結果については次回に説明したいと思います。

 次に「index」ですが、こちらは作成したテンプレートファイルに応じて作られるクラスです。indexはテンプレートファイルのindex.scala.htmlに対応しています。テンプレートを作った時点では作成されないクラスなので、Eclipseなどでプロジェクトを管理している場合はクラスが見つからずにコンパイルエラーとなり、赤字で表示されます。

 テンプレートファイルに応じて作られるクラスは、実行時もしくは「play compile」コマンドを実行した時点で生成されます。ですので、新しいテンプレートを作ったらまず、一度実行するか「play compile」コマンドでクラスを生成させると良いでしょう。

 このテンプレートファイルに応じたクラスにあるrenderメソッドを呼び出すことで、テンプレートに書かれた内容に応じた結果が表示されます。ここではrenderメソッドに文字列を渡しているので、これを何らかの形で表示するように見えます。では、表示されるテンプレートファイルに目を向けてみましょう。

サンプルプロジェクトのテンプレートの内容

 まずは、index.scala.htmlを開いてみましょう。

@(message: String)
@main("Welcome to Play 2.0") {
    @play20.welcome(message, style = "Java")
}

 テンプレートファイルの最初の1行目はテンプレートの引数定義です。テンプレートでの引数定義は「引数名: 型名」と書きます。このテンプレートは文字列を受け取り、テンプレート内でそれをmessageという変数名で扱います。よって、Application.javaから呼び出すときに渡していた「Your new application is ready」が、ここのmessageに代入され、このテンプレートで使われます。

 2行目は他のテンプレートを呼び出しています。呼び出すテンプレートはmainで、引数に「Welcome to Play 2.0」という文字列を渡しています。テンプレートのmainとはテンプレートファイルのmain.scala.htmlを指しています。main.scala.htmlも引数に文字列を受け取るようにできています。

 3行目は2行目で呼び出しているmain.scala.htmlにもう1つの引数を渡しています。渡しているのは標準で組み込み済みのテンプレートです。このテンプレートに関しては初めてサンプルプロジェクトを表示したときの内容を生成するものです。

 どのようにページを生成しているかについては、本題から外れますので詳しくは解説しません。詳しく知りたい方はGitHubにあるソースコードを直接ご覧ください。

 次にindex.scala.htmlから値を受け取ったmain.scala.htmlを開いてみましょう。

@(title: String)(content: Html)
<!DOCTYPE html>
<html>
    <head>
        <title>@title</title>
        <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>
        @content
    </body>
</html>

 1行目はテンプレートの引数を表しています。先ほどindex.scala.htmlのソースについて説明しましたが、その際にmain.scala.htmlを呼び出す際に2つの引数を渡すと説明しました。ここではその引数を受け取るための定義を書いています。ここでは、「カリー化」された2つの引数を受け取れるように定義されています。

コラム 関数型言語よく使われる「カリー化」とは

関数型言語でよく使われる考え方。複数の引数のある関数を呼び出す際に引数を分解して、1つの引数を使用する関数のチェーンにすることを指します。それにより、各引数の役割とそれに関する処理を明確に分けられます。

カリー化の詳細は連載「のんびりHaskell」の第2回「関数の話をしよう」の2ページ目で解説されているので、そちらもあわせて参考にすると良いでしょう。


 なお、カリー化した書き方のお話をしましたが、Javaのように引数を列挙するような書き方も可能です。サンプルプロジェクトのテンプレートを書き換えた場合の例をお見せします。まずは、index.scala.htmlでmain.scala.htmlを呼び出しているところは以下のように書けます。

@main("Welcome to Play 2.0", play20.welcome(message, style = "Java"))

 呼び出される側のmain.scala.htmlの引数定義の部分は以下のように書けます。

@(title: String, content: Html)

 カリー化して書くのがScalaらしくはありますが、慣れた書き方も可能ではあります。

 次は1行目の引数定義から少し飛んで5行目を見てください。これは見て何となく想像できると思いますが、引数で与えられた「title」をHTMLの<title>タグの中身として設定しています。

図3 サンプルプロジェクトのpublicディレクトリ 図3 サンプルプロジェクトのpublicディレクトリ

 今まで「@」は他のテンプレートを参照したり、引数定義したりするために使っていましたが、本来は「ここからコードブロックが始まりますよ」という意味を持っています。少し先走りますが、11行目のcontentも同様で、第2引数のcontentを表示します。

 6〜8行目はJavaScriptやCSSといった静的リソースの参照です。「@routes.Assets.at」とすることでpublic以下のリソースにアクセスするためのパスに変換したテキストをテンプレート内に埋め込めます。どこのディレクトリを静的リソースの置き場とするかは別途定義できますが、ビューのお話から外れるので、次回に回します。

テンプレートで使える基本構文

 ここまでで、一通りサンプルプロジェクトのテンプレートの説明が終わりました。テンプレートへの値の渡し方やテンプレートからテンプレートを参照する方法などを学びました。しかし、実際に使うためにはもう少しテンプレートの基本構文を知っておく必要があります。

  構文 使用例
if文 @if(条件式) {
【出力内容】
} else {
【出力内容】
}
@if(hoge.isEmpty()) {
<div>空です</div>
} else {
<div>@hoge.name</div>
}
for文 @for(ブロック内要素名 <- リスト名) {
【繰り返し中の出力内容】
}
@for(item <- itemList) {
<div>@item.price 円</div>
}
テンプレート内関数 <関数定義>
@関数名(引数定義) =@{
【出力内容】
}
<関数呼び出し>
テンプレートの呼び出しと同様
<関数定義>
@showItem(item : models.Item) =@{
item.name は item.price 円
}
<関数呼び出し>
@showItem(item)
変数定義
(ブロック内のみ有効)
@defining(変数にする値の算出式) { 変数名 =>
【出力内容】
}
@defining( item.price + “円”) { dispPrice =>
<div>@dispPrice</div>
}
インポート文 @import インポートするパッケージ 例:itemクラスのみをインポート
@import models.Item
例:utilsパッケージ以下をインポート
@import utils._
コメント @* コメントの内容 *@ @***********************
*******コメントです******
************************@
htmlタグのエスケープ @Html(エスケープする内容) @Html(item.caption)

 なお、プロジェクト内で共通的に使うようなクラスをプロジェクト全体でインポートしておきたい場合は、「/project/Build.scala」の「val main」の中のコメント「// Add your own project settings here」のところに以下のように記述してください。

templatesImport += "jp.co.bbreak.model._"

 この例では「jp.co.bbreak.model」というパッケージ以下のクラスをすべてのテンプレートで暗黙的にインポートするという意味です。

 次ページでは、前回表示した実行結果をテンプレートで表示するように修正しましょう。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。