Play Framework 2.0 ‥‥絶望的?複数チェックボックスの値を送信する

最初に。余裕のある人は、Play Framework 2.1 を使うことをおすすめしますよ~‥‥

ということで、Java + Play! 2.0 で、複数チェックボックスの値を送信する方法です。
調べた限りでは、どうやら Java + Play! 2.0 の環境では、
multiple checkbox の binding 処理にバグがあるみたい‥‥。
(参考:こことか。)
もちろん、select ボックスの複数選択も同じくできないようですね。

で、この内容、Play! 2.1 では修正されているみたいなんです。(参考:こことか。)
なので、それでもあえて Java + Play! 2.0 で複数チェックボックスを扱わなきゃいけない!
という人以外には、下記の方法はおすすめしないかもしれません。

さて、では本題です。
バグがある。正攻法じゃダメ。じゃあどうするか‥‥ javascript に頼るしかないですねえ。
値を区切り文字を挟んで連結して、hidden 項目に入れて送信しちゃいましょう。
やや面倒ですが、ほかに思いつく楽な方法がありませんから‥‥しょうがないです。

手順はこんな感じ。
1. フォームの submit イベントを拾う。
2. チェックボックスの値を区切り文字を挟みながら連結する。
3. 連結した値は hidden 項目に格納。
4. フォームを送信。
5. 受け取った内容を区切り文字で分割。

ソースを見ていきましょう。
まず html から

チェックボックスは submit 時に値を付ける必要がありませんので、name を宣言していません。

javascirpt はこんな感じです。

今回はカンマ区切りで連結してみました。
hidden フォームに格納してしまえば、あとは普通のフォームの値と同様に扱えます。

半分以上がおまけの機能=全てチェックするためのボタンのための処理です。
「全てチェック」は、よくチェックボックスで機能を用意してある場合がありますが、
動作の整合性を取るための機能の実装に混乱をきたしがちです。
だったらいっそのことボタンにしちゃったほうが楽でしょ?

次にコントローラー側では、受け取ったフォームの値を区切り文字で分割してあげないといけません。

受け取った値は、ここには書いていない TestFormData クラスで受け取ることとします。
また、DB から取得した内容は、これまたここには書いていない PREF_TBL クラスで受け取ることとします。
java.util.regex.Pattern.split で分割した値を java.util.Arrays.asList で配列に保存しています。
あとは org.apache.commons.lang3.StringUtils.join で
区切り文字を入れながら再度連結なんてこともしています。

routes については書いてませんが、一般的な Form の POST 処理で OK ですので、
悩ましいところはないはずです。

いかがでしたでしょうか。
複数チェックボックスの値を扱えない‥‥というところがコマッタさんでしたが、
javascript を使えば難なくクリアできちゃいますよというお話でした。

Play Framework 2.0 で jQuery の ajax メソッドを使って非同期通信

Play 2.1 + Scala だと、非同期通信に関する強化やアップデートがいろいろあるようだけど‥‥
参考:こことか
でも、Play 2.0 + Java でも非同期通信したいっ!というのが今回のハナシ。

非同期通信を使って、何をどんなふうに実現したいかというところをまずまとめておきます。
うーんと、こんなふうかな。
1) ビュー上で、ユーザーが画面フォーム上の Select 要素の選択肢を変更
2) jQuery.ajax メソッドを使って、Select 要素の選択肢を非同期で送信
3) コントローラーでは、非同期で受信した内容を条件に、DBから関連データを抽出
4) 抽出したデータを JSON 形式に変換して、ビューへ返す
5) ビュー上で、受け取った JSON 形式のデータをもとに、新たな Select 要素を生成する

非同期通信を使わなくても実現可能な内容ではあるけれど、
いまどき非同期のほうがスマートかな?というのが個人的な印象です。

これらの内容、いろいろ冗長かもですが、せっかくなので細かくまとめておくことにします。

さて、じゃあまず 1) の画面フォームの準備から。
いつものようにフォームヘルパーなどの機能は使わずに書いてます。

よくある感じにまとめてみました。
都道府県を選んだら、選んだ内容に合わせて市区町村の選択肢を切り替える、
ということをやってみたいと。

次は 2) jQuery.ajax メソッドを使って非同期通信を行う部分です。
都道府県が変更されたときに、非同期通信を行うように jQuery で記述します。

こんな感じです。
都道府県の change イベントに処理をバインドします。
type は post 、url には routes の定義を記載します。
データには、都道府県の選択肢をバインドします。
select ボックスで選択した内容は、$(‘#pref_list option:selected’).val() という風に取得できます。
ここでのポイントは cache を false としておくことです。
ブラウザやユーザーの環境によっては、戻り値の json データがキャッシュされてしまうのを防ぐためです。

success 時の処理は 5) 受け取った JSON 形式のデータをもとに、新たな Select 要素を生成する処理です。
select ボックスへの option の追加処理は、
以前の記事のようにie6対応の書き方にしています。
ie6を意識しないのであれば、もっとスマートに書けるんですけどね。

続いて、3) コントローラーで受信した内容を条件に、DBから関連データを抽出します。
ビューからの非同期 Request をコントローラーのアクションにバインドするために、
routes には次の定義を行っています。

コントローラーの Test クラスの changePref メソッドをコールします。
changePref メソッドはこんな感じ。

ちょっと冗長かも・・・。
フォームの値をフォーム用のクラスにバインドしています。
このあたりはなくてもいいんじゃない?という意見もあるかもですね。
取得したフォームの値をもとに、DBから値を取得します。
T02_PREF_LOCAL は、DBのテーブル用のクラスです。
フォームの値のための FormPref 、DBのテーブルのための T02_PREF_LOCAL はそれぞれこんな感じ。

DBにはクラスの定義と同じ名称・形のテーブルを準備しておきます。

続いて、4) 抽出したデータを JSON 形式に変換して、ビューへ返します。

Play! では、Scala に JSON 用のライブラリが用意されています。
これらのライブラリ、Java からも利用はできるようなのですが、
今回はいろいろの事情であえて jsonic を使うことにしました。
(検証用の時間が足りなかったりっだとか‥‥いろいろです)
JSON へのエンコードだけだと、上記のように非常に簡単な記述で済みます。
JSON への変換が済んだ文字列をそのまま戻り値とします。

戻り値を受け取ったあとの 5) の処理は 1) の箇所に記載済みです。

受け取った戻り値 data を $.parseJSON() でパースします。
パースした値は、$.each(value, function(id){…}) で、データごとの値を取得します。
パースしたデータの値は、テーブル用のクラスの変数名をキーにして格納されていますので、
市区町村名は childList[idx].local といった感じで取得できます。

こんな感じで、非同期通信でのやり取りが書けちゃいます。
Java で割と簡単に書けちゃうというところがポイントでしょうか。

Play Framework 2.0 で送信したフォームの中身をコントローラー上で HttpRequest レベルで確認する

今回は、Play Framework 2.0.4 で、ビューで送信したフォームの中身を
コントローラー側で生のまま確認したいなーということで、その方法を探ってみました。

Play! には、便利なフォームテンプレートやヘルパーの機能がいろいろあるらしいですけど、
まずはベーシックに使ってみましょうということで、私自身は今のところ使用してません。

今利用しているのは単純な Form で Submit された内容を
コントローラーで Form クラスに bindFromRequest で格納する方法です。
こんな感じ。

[ ビュー : Form(Values) ] → [ コントローラー : Form(Values) → UserForm(Values) ]

UserForm クラスは受け取ったフォームの値を格納するクラスです。
あらかじめ、こんな風に作ってあります。

ビューで送信したフォームの内容は、コントローラー上でこんな風に書けば簡単に取得できます。

@Required アノテーションのおかげで、year や month に値が入っていないと
エラーとしてはじいてくれます。

さて、この手順で作ってった場合、
ビューで送信したフォームの内容を生のままで確認したいときなどは、ちょっと困ってしまいます。
bindFromRequest メソッドで form に値を格納した段階で、中で処理されちゃっているからです。
本当に form の値がコントローラーに渡っているのかどうか疑わしいときなどです。

そんな時は、デバッグ中にでもこの値をチェックしましょう

currentに入っているのは現在のHttp通信のContextの中身そのもの。
HttpRequestの中身、つまりリクエストの内容がほしい場合は、

に入ってます。

HttpRequestのヘッダなども取得できるので、送信元IPなんかも取れちゃいますねー。
いろんな処理に応用できそうです。