概要ここでは、Spring MVCでの最重要なControllerの動作について見ていきます。 具体的・実践的なサンプルは次の記事で触れますので、ここでは処理の概要を把握することが目的です。 まずControllerの骨組みだけで作ったソースコードを提示して、それから動作を1つ1つ見ていきます。 バインドも重要な内容ですので、前回の記事をまずお読みいただき、ご理解の上、読んでいただけると助かります。 【この記事で把握したいこと】 この記事で書きたかったのは、以下のことです。 ・InitBinder(バインダーの初期化)が呼ばれるタイミング ・標準的なControllerでの処理とその順番 【先だって覚えておいてほしいこと】 Modelオブジェクト: Springが用意するMapオブジェクトで、Viewに渡すオブジェクトを設定します。 @Xxxx : アノテーションを表します。指定したメソッドをSpringが呼び出します。
Controllerクラスの骨組み 【Controllerクラスのサンプル】
private AccountService accountService;
@InitBinder("user") public void initBinder(WebDataBinder binder) { binder.setAllowedFields("id", "name"); } //(1) @ModelAttribute("user") public User newRequest( @RequestParam(required=false, value="id") String id, ) { if(id== null) return null; return this.accountService.get(id); } //(2) @RequestMapping(value="/accountEdit", method=RequestMethod.POST) public String form(@Valid @ModelAttribute("user") User user, BindingResult result) { if(result.hasErrors()){ return "account-edit-input"; } this.accountService.updateUser(user); return "account-edit-complete"; } } 【Userクラス】
private String id; private String name; private Integer feeId; //getter/setterは省略します。 } 後で少し詳しくSpringMVCにおけるController処理を見ていきます。 細かな内容はともかく、以下のことだけ覚えておいていただければと思います。 【通常のControllerの処理の流れ】 (1).@ModelAttributeの呼び出し : 事前準備として、DBからPOJOを取得して、Model に登録します。 (2).@RequestMappingの呼び出し: Model からPOJOを取り出して、画面処理をします。 【Controller処理のイメージ図】 ※@InitBinder は、引数にモデルが存在するときに、モデルにバインドするたびに呼ばれます。 つまり、引数のモデルの数だけ呼ばれます。 以下で、上記の(1)、(2)をそれぞれもう少し細かく説明していきます。 Controllerの処理の流れ(1)@ModelAttributeメソッドの処理の流れ 【再掲:実際のコード】
【図の説明】 ①Springでの処理 通常、initBinderメソッドを呼び出して初期化し、リクエストパラメタ("id")を、@ModelAttributeのメソッドの引数(id)にバインドします。 このサンプルでは、@InitBinder("id")が付けられたメソッドがないので、 initBinderのメソッドは何も呼ばれず、デフォルトのBinderでバインドします。 それにより、型変換された値が引数に渡されます。 ②モデルの前処理 リクエストパラメタのうちUserオブジェクトのキーになるidを受け取り、DBから指定のidのオブジェクトを取得します。 ③Springでの処理 @ModelAttributeのメソッドの返り値をModelオブジェクトにaddします。 【補足】 ModelAttributeメソッドは、リクエストのたびに、RequestMappingメソッドの前に呼ばれます。 ModelAttributeメソッドは無くても動作する任意のメソッドです。 しかし使用した方がController処理がすっきりし、DB処理も簡単に記述できるようになります。 以下の(2)で見ることになりますが、たいていの場合、DBの更新をするときは、DBから取得したモデル(POJO)にこの画面で更新したいフィールドのみを 上書きし、Daoに渡すことになるからです。 (ModelAttributeメソッドでDBからPOJOを取得し、RequestMappingメソッドを呼び出すときにSpringが自動的に画面の値で必要なPOJOフィールドを更新する) (2)@RequestMappingメソッドの処理の流れ 【再掲:実際のコード】
@RequestMapping(value="/accountEdit", method=RequestMethod.POST ) //②コントロール処理 public String form(@Valid @ModelAttribute("user") User user, BindingResult result) { if(result.hasErrors()){ return "account-edit-input"; } this.accountService.updateUser(user); return "account-edit-complete"; } 【図の説明】 ①Springでの処理 @ModelAttributeで指定された"user"がModelから取り出されます。 もしModelに"user"がない場合、新たにUserをnewして、Modelに設定します。 今回のサンプルの場合、(1)のモデル前処理で既にModel に"user"が設定されているので、(1)のオブジェクトが取り出されます。 また、このサンプルでは、ModelAttribute("user")に対応する@InitBinder("user")があるので、 それが付けられたメソッドが呼ばれ、Binderが初期化されます。 取り出したUserオブジェクトに、Binderを介してリクエストパラメタを設定します。nameが"次郎"で上書きされ、user.feeIdは無視されます。 initBinderメソッドで、パラメタ "user.feeId" を許可していないからです(DBのfeeIdの値を変更したくないので無視するように設定しました)。 最後にUserオブジェクトは②のメソッドの引数に引き渡されます。 ②コントロール処理 自作したコントロール処理をします。 引数で渡ってきたuserは、Model 内のuserとインスタンスが同じため、userを操作するとModel 内のuserの値も変更されます。 ここではreturnとして、View名をStringで返しています。(実際にはreturnで返却できるクラスはString(View名)だけでなく、他にもあります。) ③Springでの処理 Modelと、②のメソッドが返したView名をまとめて、ModelAndViewを作成して、次の処理に渡します。 まとめ ちょっとこまかかったでしょうか? すみません。 把握してほしかったのは、InitBinderが呼ばれるタイミング、スタンダードなControllerでの処理とその順番です。 大まかに理解できていれば嬉しいです。 結局、DBからデータを取得し、リクエストの内容でDBを更新する、という流れです。 Springの場合、この一連の流れが、きれいに1つずつメソッドになっているので、分かりやすく、処理も簡潔に書けます。 付け加えておくと、(1)のモデル前処理は必須ではありませんので、必要に応じて使用することになります。 インターネットを検索するとSpring MVCのサンプルは数多く出てきます。 しかし、たいていのサンプルでは(1)の処理について省略しています。が、実践では必須になってくると思います。 なぜなら、リクエストパラメタ全てをそのままバインドすると、セキュリティホールになってしまうからです。 Created Date: 2012/04/07 |