Spring MVC

Spring MVCとは

Spring MVCは、現在よく使われている開発パターンの一つであるMVCパターンをもとにした仕組みである。

MVCは、画面に表示するView、データ処理を管理するModel、ViewとModelをつなぐControllerの頭文字を取ったものである。

Spring Frameworkは、MVCパターンで開発しやすいように機能を提供している。 一般的にはModel、View、Controllerの形で構成するが、最近はスケーリングや運用の都合からフロントエンドとバックエンドのサーバーを分離する構成も多い。

Spring MVCの構造と処理の流れ

Spring MVC

  • DispatcherServlet
    • アプリケーションに入ってくるすべてのrequestを受け取る入口である。
    • requestを実際に処理するcontrollerへ渡し、その結果を受け取ってviewに渡せるように全体の流れを制御する。
  • HandlerMapping
    • 各Request URLをどのControllerが処理するかを探す役割を持つ。
  • Controller
    • Requestを直接処理し、その結果をDispatcherServletへ返す。
  • ModelAndView
    • Controllerが処理した結果と、その結果を表示するViewの情報を保持するオブジェクトである。
  • ViewResolver
    • View関連情報をもとに実際のViewを探す。
  • View
    • Controllerが処理した結果を表示するViewを生成する。

SpringにおけるFilter、Interceptor、AOPの違い

Filter

  • リクエストとレスポンスを通過させる前後で整える役割を持つ。
  • Servlet FilterはDispatcherServletより前に実行され、指定されたリソースの前段でリクエスト内容の変更や各種チェックを行える。
  • Springコンテキストの外側に存在し、Springとは独立したリソースに対して動作する。
  • Springの領域には含まれない。

Interceptor

  • リクエスト処理の前後に割り込むものと考えるとよい。
  • SpringのDispatcherServletがコントローラーを呼び出す前後に介入するため、Springコンテキスト内部でControllerに関するリクエストとレスポンスを処理する。

AOP

  • Aspect Oriented Programming、つまりアスペクト指向プログラミングである。
  • OOPを補完する概念であり、OOPを置き換えるものではない。
  • オブジェクト指向プログラムで重複を減らしにくい部分を、横断的な観点から扱って整理する。
  • 主にロギング、トランザクション、エラー処理など、ビジネス層のメソッドをより細かく調整したい場合に使う。
  • メソッド実行の前後などに柔軟に設定できる。

3つの違い

  • 処理順序は一般に Filter > DispatcherServlet > Interceptor > AOP である。
  • InterceptorとFilterは主にアドレスを基準に対象を絞り込むが、AOPはアドレス、パラメーター、アノテーション、メソッドなど、より多様な方法で対象を指定できる。

Spring設定ファイル、web.xmlの作成

Spring設定ファイル、Bean定義ファイルの指定

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  id="WebApp_ID" version="3.1">
 <display-name>springMVC</display-name>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
 <servlet>
   <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value></param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
   <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>
  • まず org.springframework.web.context.ContextLoaderListener クラスをリスナーとして登録する。
  • これが登録されているため、Spring設定ファイル /WEB-INF/applicationContext.xml が読み込まれる。
  • このパスとファイル名は contextConfigLocation で変更できる。

Spring設定ファイル名の変更

 <context-param>
   <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/app.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  • Spring設定ファイルが /WEB-INF/spring/app.xml に変更される。

ServletにSpring設定ファイルを適用する

 <servlet>
   <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/mvc-servlet.xml</param-value>
    </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>
  • Spring設定ファイルはServletごとに設定できる。
  • 設定する場合は、init-paramcontextConfigLocation に指定する。
  • Spring設定ファイルを /WEB-INF/spring/mvc-servlet.xml に指定している。

org.springframework.web.servlet.DispatcherServletについて

通常のWebアプリケーションではServletを作成するが、Spring Web MVCではSpringが提供するため、別途作成せずに org.springframework.web.servlet.DispatcherServlet を使用する。

DispatcherServletはクライアントからのリクエストを受け取り、@Controller が付いたコントローラークラスに割り当て、コントローラーの戻り値からJSPなどのViewを解決してクライアントへ返す。 Spring MVC全体を制御し、web.xml に設定される。

そのため、Spring MVCでWebアプリケーションを開発するときには普段あまり意識しないが、裏側でさまざまな処理を行っている。

CharacterEncodingFilter

  • 前の例では省略したが、CharacterEncodingFilter も指定する必要がある。
  • クライアントから送信されたデータを、指定した文字コードで強制的にエンコードする。
  • 内部では HttpServletRequest#setCharacterEncoding を実行する。
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
      <param-name>encoding</param-name>
     <param-value>utf-8</param-value>
    </init-param>
   <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
   </init-param>
 </filter>
 <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

Bean定義ファイル

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-4.2.xsd
    http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">

 <context:component-scan base-package="spring.test" />

 <mvc:annotation-driven />

 <bean
   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/" />
    <property name="suffix" value=".jsp" />
 </bean>
</beans>

最初の component-scan 要素は、指定したパッケージ配下にあるアノテーション付きクラスを自動的に読み込む。 読み込まれるアノテーションには、@Controller@Service@Component@Repository などがある。

次の annotation-driven 要素は、Spring Web MVCに必要な設定を自動的に有効化する。 対象となるアノテーションには、@RequestMapping@ModelAttribute@SessionAttribute@RequestParam などがある。

最後に org.springframework.web.servlet.view.InternalResourceViewResolver を宣言している。 これはJSPファイルの場所を指定する。 prefixsuffix を宣言し、コントローラーの戻り値文字列と組み合わせてJSPファイルを解決する。

prefix文字列 + コントローラーの戻り値文字列 + suffix文字列

例えば、コントローラーが test を返した場合は次のようになる。

"/WEB-INF/" + test + ".jsp" > "/WEB-INF/test.jsp"

CSVダウンロードやExcelダウンロードなどのViewを扱う場合は、org.springframework.web.servlet.view.XmlViewResolver を指定する。 これは別の機会に説明する。

<mvc:resources> 要素

画像、CSS、JavaScriptなどの静的リソースへアクセスする場合、次のようにアクセス先ディレクトリを宣言する。

<mvc:resources mapping="/image/**" location="/WEB-INF/image/" />

上記のディレクトリにある画像を表示するJSPは、次のように記述する。

<img src="./image/test.png"/>

JSPでBeanを使用する

JSPでSpring Java Beanを便利に使うには、次のように呼び出す。

まず、Spring設定ファイルで InternalResourceViewResolver を設定するときに、exposeContextBeansAsAttributes 属性を true にする。

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="exposeContextBeansAsAttributes" value="true" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

次のようにJava Beanファイルを作成する。 名前が foo のシングルトンオブジェクトが生成される。

@Component
public class Foo  {
    private String name;

    public String getName() {
        return name;
    }
}

JSPでSpring Java Beanである foo をJSP ELから呼び出す。

<%@page language="java" contentType="text/html; charset=UTF-8"%>
<div class="foo-name">
    <c:out value="${foo.name}"/>
</div>