04.基本概念:Controllerの処理フロー

概要

ここでは、Spring MVCでの最重要なControllerの動作について見ていきます。
具体的・実践的なサンプルは次の記事で触れますので、ここでは処理の概要を把握することが目的です。

まずControllerの骨組みだけで作ったソースコードを提示して、それから動作を1つ1つ見ていきます。
バインドも重要な内容ですので、前回の記事をまずお読みいただき、ご理解の上、読んでいただけると助かります。
 
  【この記事で把握したいこと】
   この記事で書きたかったのは、以下のことです。
    ・InitBinder(バインダーの初期化)が呼ばれるタイミング
    ・標準的なControllerでの処理とその順番
 
 
  【先だって覚えておいてほしいこと】
   Modelオブジェクト: Springが用意するMapオブジェクトで、Viewに渡すオブジェクトを設定します。
   @Xxxx      : アノテーションを表します。指定したメソッドをSpringが呼び出します。
 
 
 
 
 

 

Controllerクラスの骨組み

  【Controllerクラスのサンプル】

//変更したユーザ情報の入力を受け取って、DBの値を変更する画面のコントローラです。

 

@Controller
public class SampleController {

 @Autowired

 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クラス】

public class 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メソッドの処理の流れ

   【再掲:実際のコード】

@ModelAttribute("user")  //②モデルの前処理
public User newRequest( 
    @RequestParam(required=false, value="id") String id,
) {
  if(id== null) return null;
  return this.accountService.get(id);
}

 
  【図の説明】
   ①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メソッドの処理の流れ

 
   【再掲:実際のコード】

@InitBinder("user")
public void initBinder(WebDataBinder binder) {
  binder.setAllowedFields("id", "name");
}

@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