ステップバイステップ
以下の記述は、Play1.2.2RC2+scala-0.9.1によるもの(2011/6/25時点)
※play-scala-0.9とはコントローラの記述方法が大幅に異なるので注意。
基本操作
スケルトンの作成と実行
上述の環境でplay new ... -with scalaとしてアプリケーションを作成する。 さらにIntelliJで編集できるように、play idealize ...などとする(このときエラーが発生するがとりあえず無視)。 play runとして実行する。通常通りのデモ画面が表示される。
ちなみに、現時点ではplay run --%prodとするとエラーが発生してしまう。
ルーティングの確認
conf/routesを確認すると、
GET / Application.index
という記述がある。 これは、ルートにアクセスされた場合には、controllersパッケージのApplicationオブジェクトのindexメソッドを呼び出すという意味。 ここで記述する、オブジェクト名はcontrollersパッケージに存在することを前提としている。これはJavaの命名規約に背くものであるが、このアプリ内だけで使うものなので問題ないだろう、と考えたものと思われる。 controllers以外のパッケージのものを使う場合は、パッケージ名を明示する必要がある。
routesの記述はJava版と同じと考えられる。 routes ファイルの構文
コントローラの確認
app/controllers.scalaを見てみると、
package controllers import play._ import play.mvc._ object Application extends Controller { import views.Application._ def index = { html.index("Your Scala application is ready!") } }
などとなっている。この「html.index("Your Scala application is ready!")」という部分は、play-scala専用のテンプレートエンジンによって生成される関数の呼び出しなのだが、これはとりあえず無視する。
とりあえず、テンプレートは使わずに自力でhtmlを作成して返すことを考える。
自力HTMLの返し方
次のように記述を変更する。
object Application extends ScalaController { def index = { Html("<html><body><h1>hello, wold</h1></body></html>") } }
まず、「extends Controller」は「extends ScalaController」に変更する。前者のままだとIntelliJが混乱してしまうようなので。
さらに、indexの本文にはhtmlらしきものを引数としてHtml()というメソッドを呼び出してみる。もちろんScalaでは直接XMLが記述できるので、二重引用符はなくてもよい。
この状態でIntelliJの「Goto Declaration」機能を使えば、ScalaControllerやHtmlの宣言部分にジャンプすることができる(見たいものを右クリックして表示されるメニューで「Goto」「Declaration」)。
このような「アクションメソッドの返り値」には、ほかにも次のようなものがある。
http://www.playframework.org/modules/scala-0.9.1/controllers#Actionmethodsreturnvalues。
パラメータの受け取り方
アクションメソッドの引数として、パラメータ(の内容を受け取る引数)を指定できる。例えば、
def index(name: String, address: String) = { Html(<html><body><h1>{name + " --- " + address}</h1></body></html>) }
とすると、
http://localhost:9000/?name=sugimura&address=tokyo
というURLの呼び出しで
sugimura --- tokyo
と表示される。しかしこのやり方では、「プログラム上でパラメータ名を生成する」ことができなくなる。この場合には、以下のように記述する。
def index() = { val name = params.get("name") val address = params.get("address") Html(<html><body><h1>{name + " --- " + address}</h1></body></html>) }
このあたりもJava,Scalaで共通の模様。 http://playdocja.appspot.com/documentation/1.2/controllers#params
Scala版特有のパラメータハンドリング
おそらくJava版には無い、Scala版特有のものとして便利な処理方法がある。例えば以下のように記述できる。
def index(name: Option[String], address: String = "Japan") = { Html(<html><body><h1>{name.getOrElse("gonbei") + " --- " + address}</h1></body></html>) }
あるいは、次のような書き方もある。
case class User(name: String, address: String) def index(user: User) = { Html(<html><body><h1>{user.toString()}</h1></body></html>) }
が、パラメータはuser.nameなどとする必要がある。
http://localhost:9000/?user.name=sugimura&user.address=tokyo
参考はhttp://www.playframework.org/modules/scala-0.9.1/dataBinding
URLの取得
データバリデーションなどは自力でもできる(自力でやった方が効率が良い場合も多い)のでとりあえず省略。 他のリソースを参照する、つまりURLを取得するにはどうするか。
routesを以下にする。
GET / Application.index GET /login Application.login
Applicationオブジェクトを次のように書く。
object Application extends ScalaController { def index() = { Html( "<html><body><a href='" + Router.reverse("Application.login").url + "'>to login page</a></body></html>" ) } def login() = { Html(<html><body>enter id and password...</body></html>) } }
つまり、Router.reverse(アクション名)とすることにより、そのURLが取得できる。
テンプレート
とりあえずは、前述した知識があればplay-scala上のwebアプリケーションを作成することができると思われるが、 しかし、大規模なウェブアプリをテンプレートエンジン無しに行うのは面倒である。特に生成するhtmlの中に静的部分が大量に含まれる場合や、デザイナさんと共同作業する場合は。
もちろん、他のテンプレートエンジン(freemarkerやvelocity)を使うこともできるはずだが、ここでは新しく開発されたというscala templatesを試してみる。
scala templates
scala-0.9.1より、playの従来のテンプレートエンジンとは異なる、scala templatesというものが導入された。 従来のものはテンプレート上の言語がなぜかgroovyであり、テンプレートの入れ子指定も妙な構文だったが、それらは一新され、htmlとscalaのみで記述できるようになっている(ようだ)。
scala templatesの基本的な考え方は以下(と思われる)。
- scalaとhtmlをまぜこぜにしたファイル(テンプレート)を作成する。
- これが実行時に自動的にscala関数に変換される。
- コントローラ(Application.indexメソッドなど)からはこれを関数として呼び出す。
- もちろん、テンプレートにはscalaの式が記述できるので、テンプレート内から別のテンプレートを呼び出すこともできる。
微妙な点としては
- テンプレート「関数」は実行時に作成されるので、IDE上では常に「そんな関数はねえ」というエラーを見続けることになる。
- (そんな人はいないだろうけれども)play-scala環境以外では動作しない。
※もしかしたら、テンプレートをコンパイルしてscalaソースを生成してくれる仕組みがあるかもしれない。