Play framework(8) - モデルバインディング

今回はPlay frameworkでビューとコントローラの間でデータの受け渡しにモデルを使う方法についてです。
ASP.NET MVC におけるモデルバインディングと同様の動きとなります。

まずは画面と仕様です。
この画面はユーザー情報を更新するための画面で、
画面の初期表示時にはテキストボックスに表示する値をモデルで受け取ります。
「Update」ボタン押下時には、テキストボックスの入力値をモデルに入れてコントローラに渡します。
f:id:UnderSourceCode:20111120214244j:plain


では、ソースです。

◆モデル


package models;

import java.util.*;
import javax.persistence.*;

import play.db.jpa.*;
import play.data.validation.*;

@Entity
public class User extends Model {

@Required(message = "ユーザー名を入力して下さい。")
public String name = "";

@Required(message = "パスワードを入力して下さい。")
@CheckWith(PasswordCheck.class)
public String password = "";

@Email(message = "Emailの形式で入力して下さい。")
@Required(message = "Emailを入力して下さい。")
public String email = "";

@Required
public boolean isAdmin = false;

public User(String name, String password, String email, boolean isAdmin) {
this.name = name;
this.password = password;
this.email = email;
this.isAdmin = isAdmin;
}

public void update(User user){
this.name = user.name;
this.password = user.password;
this.email = user.email;
this.isAdmin = user.isAdmin;
save();
}
(中略)
}


前回と同じ、Userモデルです。

◆コントローラ


package controllers;

import play.*;
import play.mvc.*;
import play.Play.*;
import play.data.validation.*;

import java.util.*;

import models.*;

@With(Secure.class)
public class UserController extends Controller {
public static void update(long id, User user){
setUpdateRenderArgs(id);
render(user);
}

public static void dbUpdate(long id, @Valid User user){
if(validation.hasErrors()){
setUpdateRenderArgs(id);
render("UserController/update.html", user);
}else{
User updateUser = User.findById(id);
updateUser.update(user);
index();
}

}

private static void setUpdateRenderArgs(long id){
renderArgs.put("pageTitle", "Update");
renderArgs.put("id", id);
}

}


update()は画面を初期表示するためのアクションです。
render(user)で、Userモデルをそのままビューに渡しています。

dbUpdate()は「Update」ボタンを押下すると呼び出されるアクションです。
引数に更新対象するUserモデルのid、画面の入力値を格納したUserモデルを受け取ります。

update()、dbUpdte()の双方で、setUpdateRenderArgs()メソッドを呼び出し
renderArgs.put("id", id); で、ビューのhidden項目であるidに、Userモデルのidをセットしています。

◆ビュー
ビューはupdate.htmlと、タグであるuser.htmlに分かれています。
まずはupdate.htmlです。

update.html


#{extends 'main.html' /}
#{set title:'Home' /}

#{form @UserController.dbUpdate()}
#{user user:user /}
<p>
<input type="submit" value="Update" />
</p>
<input type="hidden" name="id" id="id" value="${id}" />
#{/form}


#{form @UserController.dbUpdate()}で、Post時にUserControllerクラスのdbUpdate()アクションを
呼び出すことを指定しています。
またhidden項目で、表示するユーザーのidを保持しています。

user.html


<p>
<label for="name">name: </label>
<input type="text" name="user.name" id="name" value="${_user?.name}" />
</p>
<p>
<label for="password">password: </label>
<input type="password" name="user.password" id="password" value="${_user?.password}" />
</p>
<p>
<label for="email">email: </label>
<input type="text" name="user.email" id="email" value="${_user?.email}" />
</p>
<p>
<label for="isAdmin">isAdmin: </label>
<input type="checkbox" name="user.isAdmin" id="isAdmin" #{if _user?.isAdmin}checked="true"#{/if}/>
</p>

テキストボックスのvalueプロパティにUserモデルのプロパティを、それぞれ指定してます。
これにより、画面の表示値・入力値と、モデルのプロパティの値を同機することができます。

nameテキストボックスの value="${_user?.name}" を例に挙げてみると
userの前の_(アンダーバー)がモデルの参照を表し、userの後ろの?がnull以外を表します。

isAdminチェックボックスの #{if _user?.isAdmin}checked="true"#{/if} では
Grovyの構文を使い、isAdminプロパティがtrueの場合はチェック状態としています。

null以外を考慮しているのは、実は前回のCreate画面でもこのタグを使用しているので
Userが未登録=nullの場合でも動くようにするためです。