2014年3月5日水曜日

PlayFrameworkで会員制ギャラリーサイトを作る習作:一般的なフォームの作成

さて一般的なフォームをPlay Frameworkで作っていきます。
入力画面→確認画面→完了画面の表示にします。

まずは事前準備として幾つかヘルパー等の用意をしておきます。

URLバリデータ


Play Frameworkでは基本的なバリデータはほとんど種類がありません。
URLの入力形式をチェックするバリデータを用意します。
正規表現を使って悩むのも面倒なので、org.apache.commons.validator.routines.UrlValidatorを使ってURLのバリデートをします。
https://github.com/YoshiteruIwasaki/PlayFrameworkRecruitConsole/commit/3ed201aea99c0ed525467a69b7bd7f3d1b889753

Bootstrap Helper


PlayにはもともとBootstrapのHelperが用意されていますが、出力されるhtmlタグがあんまり良くなかったりするので、調整したものを用意しました。
エラー時の入力欄の枠の色を変える処理、「必須」ボタンの表示処理などを調整しています。

https://github.com/YoshiteruIwasaki/PlayFrameworkRecruitConsole/blob/a238b208f2009861e28e28d76aa4d8e36d171d5f/modules/base/app/views/base/helper/bootstrapField.scala.html

確認画面用にテキストの表示とhiddenタグを出力するヘルパーを用意します。
https://github.com/YoshiteruIwasaki/PlayFrameworkRecruitConsole/blob/a238b208f2009861e28e28d76aa4d8e36d171d5f/modules/base/app/views/base/helper/bootstrapStaticControlField.scala.html

フォームの作成

https://github.com/YoshiteruIwasaki/PlayFrameworkRecruitConsole/commit/44e08da367faa07d8599216af9387c4e08fa6e76
でコミットをしています。

SiteFormController.java

がControllerになります


  • 入力画面:register()
  • 確認画面:confirm()
  • 登録:submit()
  • 完了画面:success()


のようになっています。
登録処理と完了画面表示処理を分けているのは、ブラウザのリロードにより2重投稿されるのを防ぐためです。

リダイレクトは
redirect(controllers.site.routes.SiteFormController.success());
のように書きます。

また、FormにセットするModelはEBeanのEntityを拡張したXXXBeanをセットするようにしてみました。


register.scala.html

入力画面のテンプレートになります。
bootstrapFieldを使ってhtmlを生成しています。
各入力欄にエラー表示をする処理をしつつ、画面上部にエラーを表示させる処理を行っています。
action指定は

controllers.site.routes.SiteFormController.confirm()
のようにして指定します。




confirm.scala.html

確認画面のテンプレートになります。
bootstrapStaticControlFieldを使って入力画面で入力したテキストの表示・hiddenタグへのデータ渡しを行っています。
Helperを使うとこんなに短く書くことが出来ます。




success.scala.html


確認画面のテンプレートになります。



messages

ヘルパーを使う関係で用意しました。がイマイチなんでこんなに短い定義でテキストが割り当てられるのかよくわかりません。。。


routes

URLとコントローラをひも付けています。とりあえずこのようなエンドポイントに設定しています。。。ちなみにリダイレクトのURLやFormのPOST先のURLをcontrollers・・・にしておくことで、実際のURLを変更した時にroutesだけの変更で抑えることが出来ます。



Site.java

EBeanのモデルです。
バリデートルールを追加しました。
@Column(nullable = false, unique = true, columnDefinition = "varchar(191)")
でデータベースの定義をします。他のアノテーションはバリデートルールです。
MaxLengthにエラーメッセージを定義する場合には以下のように書きます。

@MaxLength(value=191, message="URLは191文字以下でご入力ください。")

ちなみに@Lobにすると、一覧で取得するときにそのカラムはバイナリデータででかいから取ってこない、という判断をするケースもあるっぽいので注意が必要です。



SiteBean.java

save()メソッドはイケてないので目をつむって下さい。
validate()メソッドですが、正式な書き方はこのようになります。
今回は同じURLの2重登録を防ぐために自前validate()しています。
DBカラムをキーにエラーメッセージの配列をセットすると、入力項目ごとにエラーメッセージを関連付けることが出来ます。

ここで何か全体的なエラー(例えばアプリケーション内での権限的にデータの登録ができない処理とかで入力項目に関係なくエラーを出す場合にはreturnでエラーメッセージのテキストだけを返すようにしておけばOKです。)



SiteService.java


URL重複登録防止用のメソッドを追加しました。

今回のケースではあえて一般的な入力フォームの流れを作成しました。
URLを入力したら自動的でtitleタグを取ってきたかったりするのでそこはまた次回実装します。





2014年3月1日土曜日

PlayFrameworkで会員制ギャラリーサイトを作る習作:Play2.2.xで@NotNullアノテーションについて調べたこと

Play Framework 2.2.1がリリースされましたね。

さて、PlayFramework 2.1で使えていた@NotNullアノテーションが2.2で開発をした時にエラーを吐くようになりました。
その解決方法についていろいろ調べて詰まったので、備忘録として控えておきます。

まず結論から言うと、
Play! 2.1 アプリを Play! 2.2 に移行した作業の覚え書き

@NotNullアノテーション がなくなった
の節にある以下の様な書き換えで対応するのが良いようです。

2.1
import com.avaje.ebean.validation.NotNull;
2.2
import javax.validation.constraints.NotNull;
ここに至るまでに試行錯誤した結果を書いておきます。

2.1で使えていた@NotNullアノテーションをそのまま移植

そのまま使おうとすると、ビルドの際にエラーが出るようになりました。

build.sbtにavaje-ebeanorm-apiを追記してみる

調べてみると、どうやら
avaje-ebeanorm-api is not in the list of SBT dependencies
ということだそうで、EBeanの依存関係のバグでMaven Repositoryで自動取得してくれないようなので、build.sbtに以下を追記するようなので追記してみることにしました。

  "org.avaje.ebeanorm" % "avaje-ebeanorm-api" % "3.1.1"

https://groups.google.com/forum/#!topic/play-framework/aEglzIVCnH8
https://groups.google.com/forum/#!msg/play-framework/azlPQ14XJ2I/tdOKUkYVAxAJ

build.sbtの追記をやっぱり辞める

再度ビルドすると今度は新たなエラーが

Exception in thread "main" java.lang.NoSuchMethodError: com.avaje.ebean.config.AutofetchConfig.isGarbageCollectionOnShutdown()Z

http://stackoverflow.com/questions/20520456/java-lang-nosuchmethoderror-is-chasing-me-at-cloudbees 
を見ると、
isGarbageCollectionOnShutdown
メソッドはEBean の2.6.0系には存在しないメソッドで、3.2.2で存在しているメソッドだそうです。
また、

Looks like conflicting version of same jar in classpath
とあるように、そもそもPlay Framework 2.2系で使用しているEBeanのバージョンと
avaje-ebeanorm-apiのバージョンが混在しているのがいけないっぽい。

改めて
http://cs.hatenablog.jp/entry/2013/12/15/234618
を見てみると、

2.2ではEBeanが3.2.2になっています。
とあるので、できればavaje-ebeanorm-apiも3.2.2系にできればいいんだが、
http://mvnrepository.com/artifact/org.avaje.ebeanorm/avaje-ebeanorm-api
だと、3.1.1しかリリースされてない。。。

さらにGithubを見ると、
https://github.com/ebean-orm
のリポジトリ、
deprecated-avaje-ebeanorm-api
になってる・・・。

ということで、
2.2系では

import javax.validation.constraints.NotNull;
にするという結論になりました。以上。