はじめてのPlay Frameworkで詰まった事のメモ

scalaなんて知らない。
Javaでplay frameworkをゴリゴリ書いていきたい。
いろいろハマったので書いておく。

# インストール（Mac/要brew）
* ```brew install play``` play 2.2までしか入らない。2.3以降使いたい場合は下記参照。
* ```brew install typesafe-activator``` play 2.3よりactivator使う様になったらしい。

# アップデート（Mac/要brew）

```brew upgrade typesafe-activator``` で　```Error: typesafe-activator 1.3.2 already installed```とエラーが出る場合。
```brew update```をかけて、アップデートしたのち、```brew upgrade typesafe-activator```を行う。

# コマンドについて(2.2からの違い）
``` $play run``` とかやってたけど、 ```$activator run``` とかやればいい。
様は、```play``` を ```activator```にしてやれば上手く行く。
対応が無いコマンドとかはよく知らない。調べてない。ざっと使った感じ問題なさそう。

# 外部ライブラリを追加する（SBT）
build.sbt に追記していくっぽい。
libraryDependencies ++= Seq( ) の中にいろいろと書いていく。

```scala:build.sbt
name := "YourFirstApp"

version := "1.0-SNAPSHOT"

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  filters, //追加
  "org.jongo" % "jongo" % "1.0", // 追加
  "org.mongodb" % "mongo-java-driver" % "2.11.4" // 追加
)     

play.Project.playJavaSettings

```

※ 2.3になってちょっとかわったけど```libraryDependencies```に追加していくのはかわらないので、体勢に影響は無い。

#### SBT（Scala Build Tool?）の形式ってよくわからない。
* [http://mvnrepository.com/](http://mvnrepository.com/)に
のサイトで検索して、SBTのタブがあるので便利
* Googleで「XXXXX maven」（XXXXはライブラリ名）と検索して、[http://mvnrepository.com/](http://mvnrepository.com/)サイトのSBTのタブを見ればOK。

※ SBTあたりはもうちょいリサーチしたい。

# Eclipseプロジェクト周りでハマること

### ```v2.4```からは```eclipse```コマンドが使えない

eclipse はデフォルトでは使えない･･･

**解決策**
1. eclipseを諦めて、IntelliJ IDEAにscala pluginを入れる。（[参照](http://plugins.jetbrains.com/plugin/?idea&id=1347)）
2. eclipseで動かすには、sbteclipse を入れる。（[参照](https://www.playframework.com/documentation/2.4.x/IDE)）

eclipse淘汰が始まってる･･･。

1. IntelliJ IDEAの場合は、scala pluginを入れた後、playのアプリプロジェクトフォルダをimport先に指定すれば動く。
2. eclipseは今まで通り。

### ```eclipse with-source=true```の後のプロジェクトのインポート時
1. 「プロジェクトをワークスペースにコピー」のチェックボックスを外すことは絶対忘れない。

※ 以前、```eclipsify```だったけどどっかのバージョンで```eclipse```に変わったらしい。

### build.sbtを更新したとき（ライブラリ追加した際）
1. ```update```
1. ```eclipse with-source=true```
1. プロジェクトをリフレッシュ（F5更新）

※コンパイルエラーがある場合は、compile通る様にしておくこと。```eclipse with-source=true```のコンパイルでこけて、更新されない。
※　```update```を打ってもSBTの更新が反映されない時。```reload```コマンドを打った後、```update```を打つと解決することがあった。（2014/11/29現在）

# Play Frameworkの書き方とか

### RESTfulなAPIを作りたくてハマったこと
たぶん、いろいろやり方はあるんだろうけども、とりあえず、これで動いたという事で。

#### js側コード

```js:get.js
$.ajax({
  url: '/hogehoge/',
  data : typeof data == "string"?data:JSON.stringify(data || {}),
  cache : false,
  type: type,
  dataType: 'json',
  success: function(data){ console.log(data)},
  error : function(){ console.log('error!')},
  contentType : "application/json; charset=utf-8"
});
```


#### play側コード（Controller）

```:routes
GET  /hogehoge/ controllers.Application.getHoge()
```

```java:Application.java

// 略
public static Result getHoge(){
    JsonNode json = request().body().asJson();

    // だめだった場合の返し方。正しいのか不明だけども。
    if(hasError()){ //hasErrorは適当です。
      return badRequest(Json.toJson("ng"));
    }
    // Json.toJson メソッドを用いて、オブジェクトでもMapでもなんでも返せるので便利。
    return ok(Json.toJson("ok"));
}
// 略
```

### Formの使い方っぽいこと？
※ play.data.Form<T>　のこと
HTMLからの入力をJsonで受け取るとして、パラメータから受け取ったりしてばらしたりとか、validationとか色々面倒。
そこで、Formを用いれば楽になるっぽい。
[JavaForm（Official）](http://www.playframework.com/documentation/2.2.x/JavaForms)


```java:SampleForm.java

package hoge;
import play.data.validation.Constraints.Pattern;
import play.data.validation.Constraints.Required;

public class SampleForm {
    
    @Required(message="必須入力です") //エラー時のメッセージも入力できる
    public String sample1;
    
    @Required
    @Pattern(value="\\d{4}/\\d{2}/\\d{2}", message="形式に合わせて入力してね！") // YYYY/MM/dd の形式にマッチさせる
    public String startDate;
   
    @Required
    @Pattern(value="\\d{4}/\\d{2}/\\d{2}") // YYYY/MM/dd の形式にマッチさせる
    public String endDate;

    public String validate(){
      
      Date startDate_ = convertString2Date(startDate);
      Date endDate_    = convertString2Date(endDate);
      if(startDate_.compareTo(endDate_)>0){
          return "終了日より開始日が前になっています。";
      }else{
          return null; // 正常時はnullを返す仕様らしい
      }
    }
}

```


```java:Application.java

// 略
public static Result getHoge(){
    JsonNode json = request().body().asJson();
    Form<SampleForm> form = Form.form(SampleForm.class).bind(json);
    
    if(form.hasErrors()){ // SampleFormクラスのvalidate()メソッドも同時に呼ばれるみたい。ソースコードは読んでない。
      return badRequest(form.errorsAsJson());
    }else{
       SampleForm sampleForm = form.get();
　　   Logger.debug(sampleForm.sample1);
       return ok(Json.toJson("ok"));
    }

}
// 略
```

#### 他のValidator
* Constraints.Email - メールアドレス
* Constraints.Max - 最大値
* Constraints.MaxLength - 最大サイズ
* Constraints.Min - 最小値
* Constraints.MinLength - 最少サイズ
* Constraints.Pattern - 正規表現
* Constraints.Required - 必須
* Constraints.ValidateWith - 他との組み合わせ？（使ったことない）、[参考になりそうなStackOverFlowのリンク](http://stackoverflow.com/questions/18794842/play-custom-ebean-constraints)

### xxxx.scala.html　について
controllerからviewにアサインする時に、名前解決ができなくてコンパイルエラーになる場合がある。その場合、フルパス（例：input.form.SomethingForm）で書くとエラーが解消される。```@import input_```だとエラーのままだった。

```:xxxx.scala.html
@(aaaa : Form[input.form.SomethingForm])
```

### CSRF対策について

CSRF対策のトークンを入れるまで（[ソース](http://www.playframework.com/documentation/2.2.x/JavaCsrf)）

* build.sbt の依存関係に```filters``` を追加する。
* CSRF filter用のクラスを作成する

```java:Global.java
import play.GlobalSettings;
import play.api.mvc.EssentialFilter;
import play.filters.csrf.CSRFFilter;

public class Global extends GlobalSettings {
    @Override
    public <T extends EssentialFilter> Class<T>[] filters() {
        return new Class[]{CSRFFilter.class};
    }
}
```

* ControllerにCSRF用追加する箇所と検証する箇所にアノテーションを入れる

```java:HogeController.java

@play.filters.csrf.AddCSRFToke
public static Result get(){
  //.. something
}

@play.filters.csrf.RequireCSRFCheck
public static Result save() {
    //.. something
}
```

* Viewの ```@Form``` 内に書き込む

```scala:some.scala.html
@form(routes.HogeController.save()) {
    @CSRF.formField
    ...
}
```
or

```scala:some.scala.html
@import helper._

@form(CSRF(routes.HogeController.save())) {
    ...
}
```