#注意
これは自分用のメモです。未熟な雑魚Springユーザーが書いたものなので、きっと間違いもあります。ご容赦ください
#Spring MVC
MVCパターンはwebアプリケーションの開発に使われるパターンで、初めてreilsでポートフォリオを作ろうとしたときに僕は初めて知りました。ただ、SpringMVCは厳密にはフロントコントローラーパターンと呼ばれるアーキテクチャパターンで、僕も十分に理解できていないが、全てのリクエストを一旦受け取るフロントコントローラーとと呼ばれるコントローラーを実装したパターンらしい。
一方、SpringMVCの特徴は以下の通りです。
1. POJOで実装されてる
POJOってのはシンプルなJAVAのオブジェクトって意味。フレームワーク独自のインターフェースを実装する必要がない!
2. アノテーションを使って開発
リクエストマッピング(ここにアクセスしたらこのメソッドを実行するとか)などをアノテーションを使って記述するのでスッキリ簡単にかける。
3. メソッドシグネチャの定義を柔軟にできる
Controllerクラスのメソッドの引数には様々な型を指定できる。引数に関しても多くの型に対応している。
4. ServletAPIの抽象化
ServletAPIが抽象化できると、Controllerクラスの実装からServletAPIを使うコードを排除できるとのこと。これがどのくらいいいことなのかわかってはいないが、とりあえずコードの記述量が減るっぽい。
5. viewの実装技術の抽象化
viewの実装技術を意識しなくても、view名さえ指定してあげればviewを返却できる。
6. SpringのDIコンテナとの連携
SpringのDIやAOPを活用することができる。
SpringMVCではフロントコントローラーパターンと言うアーキテクチャパターンを持っていて、全てのリクエストを一旦フロントコントローラーが受け取り、その後適切なControllerを探しまっせ。と言う感じらしい。
さらにフロントコントローラーの中身を見てきましょ。
フロントコントローラーには以下の5つの部品が存在してます!
- DispatcherServlet
- HandlerMapping
- HandlerAdapter
- ViewResolver
- view
以下それぞれの説明さ!
DispatcherServlet
フロントコントローラーのエンドポイントとなるサーブレットクラス。司令塔的な役割を持つ。
図以外のインターフェイスを使用して他にも機能があるが、そこはひとまず割愛。
HandlerMapping
リクエストに対するcontrollerを選択する役割を持つ!
@RequestMapping
アノテーションのついている元に、適切なcontrollerを探すよ。
今時は@GetMapping
とかを使うかもだけど、どっちでも見つけてくれるよ!
HandlerAdapter
controllerのメソッドを呼び出す役割を持つ。
さらにメソッドの引数に値を渡す処理とかも実装されている。
さらにさらに、リクエストをjavaオブジェクトにする処理や、バリデーションとかもやっていくれる。
手広く処理してくれる頼れるやつ。
ViewResolver
controllerから返されたview名から、どのviewインターフェースの実装クラスを使うのかを決めてくれる。
view
Viewインターフェースはクライアントに返すデータを完成させるよ。
###リクエストを受けてからレスポンスを返すまでの流れ
例として、リクエストがあってからレスポンスを返すまでを図で見ていくよ!
DispatcherServlet:「あ、リクエスト来た!HandlerMapping君、コントローラーをおくれ!」
HandlerMapping:「仕方ねーな。お前がそう言うなら。必殺!getHandlerメソッド!」
HandlerMapping:「そのリクエストに対するControllerだよ。どうぞ。」
DispatcherServlet:「あんがと」
DispatcherServlet:「次はcontrollerのメソッドを実行したいから、、、HandlerMapping君!!!」
HandlerMapping:「おけ。必殺!handleメソッド!」
HandlerMapping:「実行したらview名帰ってきたから、渡しとくね」
DispatcherServlet:「あざまる」
DispatcherServlet:「このview名のviewが欲しいのだが、知ってる?ViewResolver君」
ViewResolver:「知っとるよ。このviewでしょ。はい。」
DispatcherServlet:「ありがとー。じゃあこいつをレンダリングしてもらって良いですかな?Viewインターフェース君」
View:「任してくれよな。動けレンダリングエンジン!!これでレンダリングできたよ〜」
DispatcherServlet:「ありがと〜。じゃあこいつをレスポンスとして渡す〜。はいよ。」
クライアント:「ありがとね〜」
###FormオブジェクトとかEntityオブジェクトとの連携!
EntityとかFormオブジェクトがどうやってviewに反映されてるんだい!って思うのでそれをこの図で紹介。フロントコントーラーが作るModelってのが。一時的な倉庫の役割をやってくれていて、そこにControllerがFormやEntityをぶち込むことによってviewはその倉庫から必要な材料を取り出しているって感じ。
###DIコンテナとの繋がり
上記の例ではDispatcherServletが他の部品と連携していたけど、その部品たちは全部DIコンテナに入っておるとのこと。SpringMVCでは以下の2つのDIコンテナ(アプリケーションコンテキストとも言う)を使う。
- WEBアプリケーション用DIコンテナ:WEBアプリに対して1つだけ作る
- DispatchServlet用のDIコンテナ:DispatchServletに対して1つ作る
DispatchServletクラスを複数持つことってあるの?って思ったけど『API用』と『UI用(webページ用)』とかのように分けて実装することがあるとのこと。なるほどなるほど。
DispatcherServletはDispatcherServlet用のDIコンテナと繋がっておるんですな。
ちな、それぞれのDIコンテナを作るためにはConfigファイルの作成とweb.xmlに設定をする必要がある。
###サーブレットコンテナとservlet、DIコンテナの繋がり
##SpringMVCを始める前のセットアップ
SpringMVCを始めるにも、まずは準備から。やらなければいけないセットアップは以下の5つ。
- ライブラリのセットアップ
- ContextLoaderListenerのセットアップ
- DispatcherServletのセットアップ
- CharacterEncodingFilterのセットアップ
- ViewResolverのセットアップ
###ライブラリのセットアップ
Marvenは以下のように。
<dependency>
<groundId>org.springframework</groundId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groundId>hibernate</groundId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groundId>org.slf4j</groundId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groundId>ch.qos.logback</groundId>
<artifactId>logback-classic</artifactId>
</dependency>
gradleならこっちで。
dependencies {
compile group: 'org.springframework', name: 'spring-webmvc'
compile group: 'hibernate', name: 'hibernate-validator<'
compile group: 'org.slf4j', name: 'jcl-over-slf4j'
compile group: 'ch.qos.logback', name 'logback-classic'
}
###ContextLoaderListenerのセットアップ(DIコンテナを作る)
アプリケーションコンテキストを生成するためにContextLoaderListener
クラスをサーブレットコンテナに登録する必要があるとのこと。アプリケーションコンテキストとはDIコンテナのことだと思っておけば良さそうです・
また、サーブレットコンテナとはjavaのプログラムを動かすためにクライアントからの命令を中継してjavaプログラムを動かしてくれるやつってイメージ。
ContextLoaderListenerクラスをサーブレットコンテナに登録するにはまず、アプリケーションコンテキストにBeanを登録するためのBean定義が必要になる。Bean定義を行うためにはConfigクラス(設定用のクラスみたいな)を作ろう。
@Configration
public JavaConfig {
}
このConfigクラスを使ってアプリケーションコンテキストを作るように設定します。
その設定にはweb.xml
という設定ファイルを作って書いていく必要があるとのこと。
web.xmlについてはこちらがわかりやすかった。
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener ・・・①
</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationConfig ・・・②
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>example.config.JavaConfig</param-value> ・・・③
</context-param>
①:サーブレットコンテナのリスナクラスとしてContextLoaderListenerを指定
②:サーブレットコンテナのcontext-paramというパラメータにAnnotationConfigWebApplicationConfigというクラスを指定する。
③:どのConfigクラスを使ってDIコンテナを作るのかをここで指定する。
###DispatcherServletのセットアップ
SpringMVCのフロントコントローラーパターン(MVCの弱点を改善したアーキテクチャパターン)を利用するために、DispatcherServletクラスというものをサーブレットコンテナに登録する必要があるとのこと。それにはwebアプリケーションコンテキストとは別にDispatcherServlet用のアプリケーションコンテキストを作成しなければならないらしい。
DispatcherServlet用のアプリケーションコンテキストが必要ということはそれ用のConfigクラスを作る必要があるということ。というわけでDispatcherServlet用のConfigクラスを作ります!
@Configration
@EnableWebMvc ・・・①
@ComponentScan("example.app")
public class WebMvcConfig extends WebMvcConfigureAdapter { ・・・②
}
①:@EnableWebMvc
を指定することでSpringMVCが提供するコンフィギュレーションクラスがインポートされ、SpringMVCを利用するのに必要となるコンポーネントのBean定義が自動で行われる。
②:WebMvcConfigureAdapterクラスを継承することで、デフォルトで提供されるBean定義を簡単にカスタマイズできるようになる。
続いて、DispatcherServletクラスをサーブレットコンテナに登録します。その際に、先ほど作成したDispatcherServlet用のConfigクラスを使ってアプリケーションコンテキスト(DIコンテナ)を生成するように定義します。
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet ・・・①
</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationCofigWebApplicationContect ・・・②
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>example.config.WebConfig</param-value> ・・・③
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern> ・・・④
</servlet-mapping>
①:フロントコントローラー(全部の処理を一旦受け取るコントローラー)を設定するタブの<servlet-class>
にDispatcherServlet
クラスを登録する。こいつはspringが提供してくれているクラスで、とりあえずこいつを使っておけばいいらしい。このクラスに好きな名前をつけるのだが、今回はapp
にしよう(上の<servlet-name>
に名前を入力)。
②:contextClassパラメータにAnnotationCofigWebApplicationContect
を指定。こいつは何か調べてみると、@Configration
アノテーションのついたConfigクラスをアプリケーションコンテナを作る時に利用します!っていう設定とのこと。参考
③:ハンドリングするURLのパターンを指定し、ハンドリングしたリクエストをどのサーブレットクラスで捌いてもらうかを<servlet-name>
タグで指定。ここではwebアプリに対する全てのリクエストをapp
と言う名前のクラスで捌くように指示している。app
の名前がついているのは①のDispatcherServlet
なので、こいつに渡すことになる。
###ViewResolverのセットアップ
SpringMVCではビュー名を解決して使用するViewを判別するためにViewResolver
を使うらしい。
ここではviewにJSPを使うものとしてViewResolverの実装手順を書いていく。
@Configuration
@EnableWebMvc
@ComponentScan("example.app")
public class WebConfig extends WebMvcConfigAdapter {
@Override
public void configureViewResolvers(viewResolverRegistry registry) { ・・・①
registry.jsp(); ・・・②
}
}
①:configureViewResolversのメソッドをオーバーライド
②:viewResolverRegistryクラスのjspメソッドを呼び出しJSP用のviewResolverをセットアップする。
これでセットアップは終わりです!お疲れ様です!
##用語集
- メソッドシグネチャ:「メソッド名」「パラメータ数と順序、パラメータの型」「戻り値の型」をまとめた名称
- サーブレット:webサーバーで働くjavaのアプリケーションのこと。ここがわかりやすい。
- プレゼンテーションロジック:ユーザーが向き合う画面のロジック
- ビジネスロジック:データ処理を行うところ
- WARファイル:http://e-words.jp/w/WAR%E5%BD%A2%E5%BC%8F.html
- Handler:controllerのこと。