Play frameworkことはじめ

# Play Framework
世の中には多様なウェブシステムのためのフレームワークがありますが、今回はPlayに注目して話します。Javaには伝統的にJavaEEというものがあり、最近はやりのkotlinでのコーディングが可能なSpringもかなり使いやすくなっていますが、scalaなどの親和性も考慮するとPlayが一番よさそうなため。アーキテクチャもモダンなので管理がしやすい印象です。

## Playのインストール
以前はactivatorというツールがあったようですが、今は提供されていないようです。[公式ドキュメント](https://www.playframework.com/download#starters)によると現在はGitHubから[スターターコード](https://github.com/playframework/play-scala-starter-example/tree/2.6.x)をダウンロードするか、sbtのgilter8テンプレートを使うというのが推奨されている始め方のようです。gilter8を使う場合は以下のようにします。


```
 sbt new playframework/play-scala-seed.g8
```

該当フォルダに移動して、sbt runとすると[http://localhost:9000](http://localhost:9000)にサンプルアプリが立ち上がります。まずはこれで準備は完了です。ちなみにこの状態でも、scalaに特有のauto-reload機能が有効なので、ソースコードを修正すると即座に再コンパイルされ、再スタートされます。便利ですね。ちなみにこれはtrigger executionという機能で、~をsbtコマンド前にいれると、どのコマンドでも実行できます。（~ compile, ~ run, ~ test, etc...)

## IDEのセットアップ
上記のauto-reload機能があれば、特にIDEはいらないともいえますが、生産性を高めるために、EclipseやIntellij IDEAとの連携も考慮されています。ここではIntellij IDEAを使ってセットアップします。事前にIntellijの[Scala Plugin](https://www.jetbrains.com/help/idea/run-debug-and-test-scala.html)のインストールをしておきます。

sbtプロジェクトはIntellij IDEAで直接インポートすることができますので、先ほど作ったプロジェクトを読み込みます。新たなRun Configurationを作って、SBT Taskのrunを実行させるようにすれば、上記と同じ環境を再現できます。

Intellijで便利なのは、play.editorコンフィグレーションを使うことで、エラーページからのソースコードへのダイレクトリンクを実現できることです。IntellijではリモートファイルREST APIのための組み込みウェブサーバがポート63342で動いています。これに繋ぐ設定を、conf/application.confに記載します。

``` application.conf
play.editor="http://localhost:63342/api/file/?file=%s&line=%s"
```

加えて、build.sbtに以下の記述を追記します。

``` build.sbt
fork := true // required for "sbt run" to pick up javaOptions

javaOptions += "-Dplay.editor=http://localhost:63342/api/file/?file=%s&line=%s"
```

この他にもPLAY_EDITOR環境変数を定義することで実現することもできます。

```
PLAY_EDITOR="http://localhost:63342/api/file/?file=%s&line=%s"
```

## ルーティングことはじめ
サンプルアプリケーションを起動すると、Playのチュートリアルが確認できます。
PlayはMVCのフレームワークに沿って構成されています。まず最初に理解すべきは、コントローラにウェブのリクエストをルーティングするルールの記載方法です。conf/routesという静的なファイルにルールを記載します。これはアプリケーションで記載するよりもわかりやすいと感じます。例えば以下のように記載します。

``` conf/routes
GET   /                    controllers.HomeController.index
GET   /clients/:id         controllers.Clients.show(id: Long)
GET   /files/*name          controllers.Application.download(name)
```

1番目の設定は[http://localhost:9000](http://localhost:9000)直下のリクエストを、HomeControllerに定義されている関数であるindexにルーティングする設定です。２番目の設定は、Clientsに定義されている関数であるshowにルーティングするとともに、関数の引数にidを割り当てます。最後の設定はワイルドカードを使ったパターンで、立てばファイル名などimages/log.pngなどにもマッチします。他にも正規表現を使った柔軟なマッチングが可能です。この辺は[公式ドキュメント](https://www.playframework.com/documentation/2.6.x/JavaRouting)が詳しいです。

## コントローラ
ルーティングで定義されたコントローラはControllerを拡張したクラスになります。app/controllers以下に設置します。ControllerはAbstractControllerを拡張したクラスで、前の@Injectアノテーションも必須です。Play2.6以降に仕様が変わったようです。Action型を返す関数を定義する必要がありますが、testの中のOkという関数は実際にはplay.api.mvc.Resultを返します。Okはシンタックスシュガーなので、Resultをnewして返り値とすることも可能です。

```app/controllers/TestControllers.scala
package controllers
import play.api._
import play.api.mvc._

class TestContoller @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
    def test(String name) = Action {
        Ok("Hello " + name + "!");
    }
}
```

同じく、conf.routesに以下を追記します。[localhost:9000/test/bob](http://localhost:9000/test/bob)などとすると、ブラウザにHello bob!と表示されます。

```conf/routes
GET   /test/:name         controllers.TestContoller.test(name:String)
```

## Viewの定義
Playでは[Twirl](https://github.com/playframework/twirl)というASP.NETのRazorにインスパイアされたテンプレートエンジンを使うのが一般的のようです。ファイルはapp/views以下に配置されます。@マークを使って、ダイナミックに値を埋め込む記法をとります。公式ドキュメントは[こちら](https://www.playframework.com/documentation/2.6.x/ScalaTemplates)。


先ほどのTestControllerを少し変えて、テンプレートエンジンを使うようにしてみます。


```app/controllers/TestControllers.scala
package controllers
import play.api._
import play.api.mvc._

class TestContoller @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
    def test(String name) = Action {
        Ok(views.html.test("Hello " + name + "!");
    }
}
```
app以下にtest.scala.htmlというファイルを用意します。ここに上記から呼び出されるViewsを定義しています。結果は先ほどとまったく同じですが、複数の引数を取って、scalaの構文でlist要素を列挙するといったことは簡単にできます。

```app/test.scala.html
@(message: String)

<!DOCTYPE html>
<html lang="ja">
    <head>
        <title>Test</title>
    </head>
    <body>
        @message
    </body>
</html>
```

## おわりに
SpringやJavaEEなどに比べるとPlayが簡易で柔軟なフレームワークであることは、よく理解できます。まだまだ枯れておらず、仕様が細かいところで結構変わっているようなので、最新の公式ドキュメントを追わないといけないのが、ハードルが高くなっている気もしますが、一度覚えてしまえばよっぽど容易かなと感じる次第。次は[Lagom](https://www.lagomframework.com/)にも挑戦してみます。