02.基本概念:Spring MVCにおける設計のルール
概要
ここでは、Spring MVCのルールや思想のようなものに触れてみようと思います。
この記事の前に、01.基本概念:全体的な処理フローを読まれておくことをお勧めします。
ちなみに、かなり自由に設計できるので、それほど制限のようなものはありません。
画面と画面処理のマッピングの設計
Spring MVCでも他のWEBフレームワークと同様に、リクエストとJavaの処理メソッドをマッピングします。
わかりやすいところでは、あるURLがリクエストされたときに、「Aクラスのa()メソッドを呼び出す」といった具合です。
Spring MVCでは処理メソッドを決めるときに、URLだけでなく、header、クッキー、メソッド(GET/POSTなど)、パラメタなど、様々な値を利用できます。
可能なマッピングについて、いくつかを図にすると以下の感じになるかと思います。
考えられるマッピングのサンプル
<複数の画面に1つのControllerを結びつけるパターン>
複数画面に対して、画面処理(Controller)を1つに対応させることができます。
<1つの画面に1つのContollerで、複数submitボタンから呼び出しするパターン>
画面1つに、submitボタン毎にメソッドを対応させることができます。
このパターンを実現するにもいくつか方法があります。
例えば、ボタン毎に、パラメタの値を変える、URLを変えるなどです。
<画面とControllerを1対1にするパターン>
1画面に対して、画面処理(Controller)を1つ対応させることができます。
<画面とJSPを1対1にするパターン>
1画面に対して、Controllerを作成せずに直接1つのJSPに対応させることができます
これを実現するには、Spring設定ファイル(DIコンテナ)で、mvc:view-controllerタグと、
Springが用意したUrlFilenameViewControllerクラスをbeanとして設定します(参考: mvc:view-controller)
(このパターンは、内部ではSpringが用意したControllerが処理しています。)
<その他>
その他にもさまざまなパターンが考えられますが、書ききれないくらい柔軟性が高いです。
SpringMVCの画面処理マッピングの設計思想
StrutsなどのWEBフレームワークでは、URLとリクエストパラメタからどの画面を表示するかを決めていました。
しかし、SpringMVCでは、URL、リクエストパラメタだけでなく、ヘッダ、クッキーなど、ブラウザから送られてくる情報ほぼすべてを、
画面を決める条件にできます。
それは単純に扱える情報量を増やしたのではなく、RESTなどに対応するという世の中の要請に応えたものだと思われます。
RESTとは、URLがリソースを表し、メソッド(POST、GET、DELETEなど)がその処理方法を表すというルールを決めているものです。
今後主流になっていくと言われています。
Spring MVCは今後も、新しいものでも、世の中の主流になりそうなものはきっと取り入れて進化していくのではと、個人的には期待しています。
その他のルール等
Resolverなどの設定ルール
前回の記事で見ましたように、SpringMVCではいくつかの機能を持っています。
機能1つにつき、1つのクラスが対応しているので大変わかりやすく、拡張しやすいです。
その設定方法も簡単で、基本的にはSpringの設定ファイル(DIコンテナ)にbeanとして設定するだけです。
Interceptorは設定用のタグが用意されていますが、そのほかのResolverはbeanとして記述すればDispatcherServletが自動的に検索してくれます。
また基本的には、同じ種類のResolverを複数設定することができ、優先順位も設定できます。
Controllerの設計ルール
SpringMVCの2.5以前のバージョンでは、Controllerインターフェースをimplementsするようになっていました。
しかし、3.0からはアノテーションで@Controllerをクラスにつけることを推奨するようになっています。
おそらく、Controllerも使用できるかとは思いますが、アノテーションを使用する設計にしましょう。
ただし、SimpleFormControllerはDepreated(廃止勧告)されているので、使用しないようにしてください。
Controllerの処理メソッドの引数のルール
処理メソッドの引数にはUserなどのモデルを指定できます。
Springのドキュメントを読むと、「指定するとリクエストパラメタをUserにバインドして引数に渡す」くらいにしか記述していません。
しかし、実際使ってみるともう一つ機能が隠れていることが分かります。
処理メソッドの引数にして初めてModel にaddされるのです。
つまり、以下のコードは"user-Edit-Input"という文字列を返す処理だけでなく、
model.addAttribute("user", user) も実行されていることになります。
public String input2(User user) {
return "user-Edit-Input";
}
ですので引数にしなかった場合は、@ModelAttributeアノテーションをメソッドに指定してモデル前処理でModelにaddするか、
Modelクラスを処理メソッドの引数にして、明示的にaddしなければなりません。
そうしなければ、Model に"user"というモデルが存在しないことになります。
【明示的にaddする例】
public String input(Model model){
model.addAttribute("user", new User());
return "input";
}
【明示的にaddしなかった場合】
JSPの中で以下のようなタグを指定すると、おそらくnull 例外が発生すると思います。
<form:input path="user.id" />
Formの設計 (リクエストパラメタの受け取り方)
リクエストパラメタを受け取るモデルについて考えてみます。
WEB上で紹介されているSpring MVCのサンプルでは、業務モデルをそのまま受け取りのモデルに使っているのものがほとんどです。
しかし実際には、WEBの画面上にしか存在しない値(パラメタ)などが存在します。
当然ながら業務モデルにそのようなパラメタを入れるわけにはいきません。
ですので、別途Formクラスのようなものを作成して、そのプロパティ(setter/getter)に業務モデルや画面用パラメタを
設定するのがよいかと思います。
この辺りはSpringMVCのドキュメントに書いてあるわけではないので、1つの設計案として読んでいただければと思います。
コマンドオブジェクトという概念について
Spring MVCのドキュメントやフォーラムなどを読むと、「コマンドオブジェクト」「コマンド」という言葉がときどき出てきます。
これは、リクエストパラメタの値を設定されたモデルを指しているようです。
【補足】
どうも、GoFのデザインパターンのコマンドパターンのイメージからきているようです。
しかし実際のところ、コマンドパターンのように実行できるわけではないので、コマンドパターンではないように見えます。
もしかしたら、コマンドが次々に登録されるようにモデルが生成され、Springに登録されることから来たのかもしれません。
このあたりのいきさつを明確に記述した文書が見つけられなかったので単なる推測です。
でも、コマンドオブジェクトがパラメタから変換されたモデルということを覚えておくだけで、
ドキュメントを読むときの理解が早くなることがありますので覚えておいた方がよいかなと思います。
セキュリティ
リクエストパラメタをモデルに展開するときに、悪意のあるパラメタを無視する機能があります。
この辺りは以下の記事を参考にしていただければと思います。
Created Date: 2012/04/07