アメリカではほとんどデフェクトスタンダードとなっている「」の覚書きです。Spring は簡単に言うと、IoC (制御の反転)、またの名を DI (依存性注入) という仕組みを取り入れた軽量コンテナです。

Springは MVCフレームワークを提供しています。Springのフレームワークは、すべてインターフェースベースになっているので、単一継承の JAVA にとっては非常にありがたいものです。Spring MVC の View には、JSP の他、Velocity、XSLT、JSFなどといったさまざまな技術が使えます。

Validation 機能は、Web システムにとって非常に重要なものとなっています。Springでは、 Validation は Web パッケージと切り離されているので、単体テストも簡単に出来るようになっています。

Springの詳細については、ほかにもっとよいサイト(Springフレームワークの紹介)があるので、そちらを参考にしてください。ここでは、Springを使っていて、ハマった点や気になった点などをメモしていこうと思います。随時更新していくつもりです。間違っている可能性が高いので、気になる点があればコメントをお願いします。

参考

Spring Pad - Wiki

JavaWorld 7月号 2004年

Spring MVC フレームワーク

Spring MVC フレームワークとは

Spring MVCは、IoC コンテナをベースにした、WebアプリケーションのためのMVCアーキテクチャです。IoCコンテナをベースにしているので、設定は定義ファイルに書くことになります。

Spring MVC が使用する定義ファイルは、WEB-INFフォルダの直下に 「《サーブレット名》-servlet.xml」という名前で作成します。《サーブレット名》は web.xml で設定した名前となります。(今後は、便宜的に 「Web アプリケーション定義ファイル」と呼びます。)

Spring MVC の基本的な処理の流れは以下のようになります。

リクエストを受け取る (コントローラーサーブレット)
      ↓
転送先のコントローラを決定する (ハンドラマッピング)
      ↓
ビジネスロジックを呼び出す (コントローラ)
      ↓
ビジネスロジックを呼び出して「モデル」に結果をセットする (ビジネスロジック)
      ↓
モデルと、それを表示するビュー名のセット (モデル&ビュー)
      ↓
ビュー名からビューを解決する (ビューリゾルバ)
      ↓
モデルの結果を表示する (ビュー)

Spring MVC のアーキテクチャは非常に柔軟で、プラグイン形式でワークフローを制御したり、Validation を追加したりすることが出来ます。Web アプリケーション定義ファイルに定義された ID を使って Bean を指定することでプラグインします。

Spring MVC で使われる主なクラス / インターフェース

Spring MVC を利用する場合に使われる主なクラスやインターフェースです。

org.springframework.web.servlet.DispatcherServlet

コントローラサーブレットの基本クラスです。アダプタクラス設定することで、さまざまなワークフローを行うことが出来ます。デフォルトの設定クラスは以下のようになっています。

HandlerMapping

リクエストとコントローラのマッピングを保持します。デフォルトの設定は BeanNameUrlHandlerMappingです。このクラスは「/」で始まるBean名とURLをマッピングします。多くの場合、SimpleUrlHandlerMapping クラスを変わりに使います。

HandlerAdapter

ワークフローを制御するために設定されるもの(たぶん)です。デフォルトは SimpleControllerHandlerAdapter です。

HandlerExceptionResolver

例外からエラーページビューを解決するためのクラスです。デフォルトは設定されていません(none)。

ViewResolver

ビューと名前をマッピングさせるものです。 例えば、 prefix=”/WEB-INF/jsp” suffix=”.jsp” viewname=”test” の場合、/WEB-INF/jsp/test.jsp というビューを参照することになります。

JSPファイルは、WEB-INF 以下のフォルダに置くことをおすすめします。こうすることで、外部から直接アクセスが出来なくなります。コントローラを経由しなければファイルが読めないので、セキュリティ的にも非常に効果的です。

デフォルトは InternalResourceViewResolver を使います。このクラスは、実際にビューの在る無しに関わらず、名前からビューを解決することが出来ます。

MultipartResolver

マルチパートのリクエストを処理するものです。「multipartResolver」という名前でBean定義を設定します。デフォルトは設定されていません(none)。

LocaleResolver

Webベースロケール(?)を受け付けるかどうかを設定します。デフォルトは AcceptHeaderLocaleResolver クラスです。このクラスは、セッション、クッキーなどを受け付けます。おそらく、ワークフローを処理する条件か何かになると思います。「localeResolver」という名前でBean定義を設定します。

ThemeResolver

テーマを受け付けるかどうかを設定します。おそらく、ワークフローを処理する条件か何かだと思います。 「themeResolver」という名前でBean定義を設定します。デフォルトは FixedThemeResolver クラスです。

org.springframework.web.servlet.mvc.Controller

リクエストとレスポンスを引数にとるコントローラの基本インターフェースです。サーブレットとほとんど同じで、Struts の Action クラスのようなものです。このクラスは、複数のHTTPリクエストで処理できるように、スレッドセーフでなければなりません。

リクエストを受け取ったあと、ロケールやテーマを元にワークフローが決定されます。そして、適切なコントローラが見つかると、handleRequest メソッドが呼び出されます。Webアプリケーションのために、標準的な機能を持つコントローラが用意されています。

org.springframework.web.servlet.mvc.AbstractController
Template Method パターンを利用した、便利なコントローラ抽象クラスです。

【特徴的な機能】

Generation of Caching Headers

世代別キャッシュヘッダーを備えています。指定秒内の同じリクエストに対してはキャッシュされた結果を返します。

GET/POST のサポート切り替え

GET/POST のサポートを切り替えます。POST メソッドは処理するのに、GET メソッドはエラーにするといったことが出来ます。

【設定可能な項目(Web アプリケーション定義ファイルに書く)】

supportedMethods

サポートするメソッド(GET, POST, PUT)。カンマ(,)で区切って指定する(例: GET,POST)。デフォルトは『GET,POST』

requireSession

セッションの存在をチェックするかどうか(true, false)。この設定を true にしておけば、セッション切れをチェックできます。セッションが切れていたときには ServletException がスローされます。デフォルトは『false』

cacheSeconds

キャッシュヘッダーを利用する秒数(数値)。設定した秒内の同じリクエストに対しては、キャッシュされた結果を返します。デフォルトは『-1 (キャッシュを利用しない)』

【ワークフロー】

  1. メソッドがサポートされているかのチェック
  2. セッションが要求されているかどうかのチェック
  3. キャッシュヘッダーのチェック
  4. コントローラ処理の呼び出し
org.springframework.web.servlet.mvc.AbstractCommandController

リクエストからコマンドオブジェクトを作成して、リクエストパラメータをセットするコントローラです。リクエストパラメータを Bean クラスに設定するために利用できます。その際、Validation を使ってパラメータの妥当性チェックを行うことが出来ます。Validation の結果は Errors オブジェクトに格納します。

リクエストパラメータが 「firstName」であった場合、コマンドオブジェクトの「setFirstName」メソッドが呼び出されます。ネスとしたパラメータ、「address.city」といった形も受け入れられます(getAddress().setCity())。

パラメータを独自型や特殊型に変換することも出来ます。その際は、PropertyEditor クラスを利用します。

[参考]

Spring Pad - PropertyEditorだよ

【設定可能な項目】

commandName

リクエストとコマンドオブジェクトを結びつけるときに使う名前(文字列)。デフォルトは『command』。

commandClass

コマンドとして使われる完全クラス名(文字列)。デフォルトは『null』。

validator

妥当性チェックで使われる名前(Bean 参照)。リストも受け取れます。複数のバリデーションクラスを指定する場合は 「validators」を使います。設定する値は、「<ref bean="ValidatorID"/>」のように書きます。デフォルトは『null』です。

validateOnBinding

リクエストと結び付けられたバリデータを有効にするかどうか(true, false)。デフォルトは『true』。

通常は、このクラス使わずに AbstractFormController を代わりに使います。

org.springframework.web.servlet.mvc.AbstractFormController

リクエストパラメータを自動的に フォームオブジェクトに設定するコントローラです。 Struts の Action とほとんど同じものだと思います。フォームオブジェクトは、 Struts の ActionForm と同じくただの JavaBean です。リクエスト毎に新しいフォームオブジェクトを作成するか、毎回同じフォームオブジェクトを使いまわすかを決められるようです。フォームが送信されたかどうかは 「isFormSubmission(HttpServletRequest)」メソッドの戻り値で判断されます。デフォルトは POST で呼び出された場合に、送信とみなされます。オーバーライドして独自にカスタマイズも可能です(コマンド名が送信されたらフォーム送信とみなすとか)。

サブクラスに、 SimpleFormController があり、Bean定義 を使って処理後のページを設定できるようです。AbstractFormController を直接使う場合は、処理後のページはプログラマティックに設定しなければなりません。

【設定可能な項目】

bindOnNewForm

新しいフォームオブジェクトを作成した場合に、リクエストと結びつけるかを決めます(true, false)。結び付けなかった場合は、ただのリクエストパラメータはただのパラメータとして処理されます。デフォルトは『false』。

sessionForm

セッションで共有するかどうかの設定(true, false)。デフォルトは『false』

AbstractCommandControllerで設定できる項目

AbstractCommandController で設定できる項目が設定できます。

org.springframework.web.servlet.mvc.multiaction.MultiActionController

メソッド名で複数のリクエストを処理することが出来るクラスです。アクション名をメソッドと結びつけることで、コントローラクラスが膨張するのを防げます。

定義するメソッドシグネチャ

ModelAndView 《メソッド名》(HttpServletRequest request, HttpServletResponse response);
ModelAndView 《メソッド名》(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception);

メソッド名とアクション名のマッピングは MethodNameResolver を使います。「methodNameResolver」というプロパティ名に設定します。

MethodNameResolver に使える主なクラス

ParameterMethodNameResolver

リクエストパラメータを元にメソッド名を決定します。例えば 「http://hamasyou.com/index.view?action=insert」 の場合、 「ModelAndView insert(HttpServletRequest, HttpServletResponse)」 というメソッドが呼ばれます。「action」というパラメータ名をメソッドと結びつけるという設定を行っておく必要があります。

InternalPathMethodNameResolver

パス名がそのままメソッド名と結び付けられるクラスです。「http://hamasyou.com/insert.view」 というリクエストパスがあった場合に 「ModelAndView insert(HttpServletRequest, HttpServletResponse)」 が呼ばれることになります。

PropertiesMethodNameResolver

マッピングをプロパティファイルに持つクラスです。「/action/insert.view=insert」というマッピング情報をプロパティファイルに書いておくことで、「/action/insert.view」 という名前が含まれるパスが呼ばれると 「ModelAndView insert(HttpServletRequest, HttpServletResponse)」 が呼ばれることになります。

org.springframework.web.servlet.ModelAndView

ビューに対するモデルを保持する単なるホルダーとして機能します。コントローラから返された ModelAndView インスタンスからビューに遷移し、ビューからモデルを使用できるようにします。

ビューには、View を継承したオブジェクトか、 ViewResolver によって解決されるビュー名を指定します。 モデルには、キーとなる文字列と、オブジェクトを設定します。内部では Mapで保持するようです。

ビューにおいてモデルは、EL式を用いて表現することが出来ます。JSPでは、request の attribute にモデルが設定されてるはずです。

org.springframework.web.servlet.ViewResolver

ビュー名とビューのマッピングを行うクラスです。ResourceBundleViewResolver クラスは、マッピング情報を設定ファイルに指定できます。InternalResourceViewResolver はマッピングを MVCアプリケーション定義ファイルにしていします。

Spring で言う 「ビュー」とは、レスポンスを返すクラスのことです。例えば、JSTL と JSP を使ってレスポンスを返す場合には、org.springframework.web.servlet.view.JstlView を使用します。Velocity などのテンプレートエンジンや JSF などを使用する場合には、別のビュークラスを指定します(参考)

org.springframework.web.servlet.HandlerInterceptor

ワークフローに処理を付け加えるためのインターフェースです。「インターセプター」という名前の通り、処理を横取りします。例えば、入力パラメータのエンコードに使えます。

コントローラ・サーブレットの設定 (web.xml)

コントローラ・サーブレットは web.xml に設定します。サーブレット読み込み時にIoC コンテナのところで書いた Bean定義ファイル を読み込むには、 org.springframework.web.context.ContextLoaderListener を使用します。

[参考]

Spring Pad- Servlet 環境への導入

サーブレットの例

<?xml version="1.0" ?> 
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
"http://java.sun.com/dtd/web-app_2_3.dtd"> 
<web-app>    
   
<listener> 
    <listener-class> 
    org.springframework.web.context.ContextLoaderListener 
    </listener-class> 
</listener> 
   
  <!-- Bean定義ファイルの設定 --> 
  <context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>BeanContext.xml</param-value> 
  </context-param>   
   
  <!-- 通常のコントローラ・サーブレット --> 
  <servlet> 
    <servlet-name>dispatcher</servlet-name> 
    <servlet-class> 
      org.springframework.web.servlet.DispatcherServlet 
    </servlet-class> 
    <load-on-startup>1</load-on-startup> 
  </servlet> 
   
  <servlet-mapping> 
    <servlet-name>dispatcher</servlet-name>     
    <url-pattern>*.do</url-pattern> 
  </servlet-mapping> 
   
</web-app> 

ModelAndView のサンプルコード

ModelAndView を使ったビュー表示の例です。

public class WelcomeForm extends SimpleFormController {
  /**
   * 読み取り専用で処理すること!
   * スレッドセーフでないから、書き込みすると危ない。
   * 本来なら、clone を返すか、ラップするべし。
   */
  private Person[] defaultPersons;
 
  public WelcomeForm() {
    super();
  }
 
  public Person[] getDefaultPersons() {
    return defaultPersons;
  }
 
  public void setDefaultPersons(Person[] defaultPersons) {
    this.defaultPersons = defaultPersons;
  }
 
  protected ModelAndView 
     processFormSubmission(HttpServletRequest request,
                           HttpServletResponse response, 
                           Object command, 
                           BindException errors)
      throws Exception {
    Map map = new HashMap();
    map.put("title", "WelcomeFormTitle");
    map.put("persons", getDefaultPersons());        
    return new ModelAndView("/WEB-INF/jsp/form_list.jsp", "model", map);
  }
}

Webアプリケーション定義ファイルの設定例です。今回は、コントローラ(WelcomeForm)が SimpleFormController を継承しているので、「commandClass」 を設定しなければなりません。 jp.dip.xlegend.spring.web.cmd.WelcomeCommand は、ただの JavaBeanです。Struts で言うところの、 ActionForm だと思えばいいと思います。

Web アプリケーション定義ファイルの設定例

<!-- 中略 --> 
<bean id="WelcomeForm" 
      class="jp.dip.xlegend.spring.web.WelcomeForm"> 
  <property name="commandClass"> 
    <value>jp.dip.xlegend.spring.web.cmd.WelcomeCommand</value> 
  </property> 
  <property name="validator"> 
    <ref bean="welcomeValidator"/> 
  </property> 
  <property name="defaultPersons"> 
    <list> 
      <ref bean="person1"/> 
      <ref bean="person2"/> 
      <ref bean="person3"/> 
    </list> 
  </property> 
</bean> 
 
<bean id="person1"  
      class="jp.dip.xlegend.spring.Person"> 
  <property name="name"><value>山田 太郎</value></property> 
</bean> 
<bean id="person2"  
      class="jp.dip.xlegend.spring.Person"> 
  <property name="name"><value>山田 次郎</value></property> 
</bean> 
<bean id="person3"  
      class="jp.dip.xlegend.spring.Person"> 
  <property name="name"><value>山田 三郎</value></property> 
</bean> 
<!-- 中略 -->

ModelAndView で設定された JSP ファイルの例です。JSTLを使って表示していますが、スクリプトレットを使って表示することも出来ます。

JSPファイルの例

<%@ page contentType="text/html; charset=Shift_JIS" %>
<%@ page import="java.util.*" %>
<%@ page import="jp.dip.xlegend.spring.Person" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>  
 
<html>
<head>
<title>form_list.jsp</title>
</head>
<body bgcolor="#FFFFFF">
<form action="welcome.do" method="post">
  EL式を利用した表示 <br>
  <h4><c:out value="${model.title}"/></h4>
  <c:forEach items="${model.persons}" var="person">
    <c:out value="${person.name}"/>
  </c:forEach>  
 
  こうしても同じ結果が取得できる。
  <%
      Map map = (Map)request.getAttribute("model");
  %>
 
  <h4><%= map.get("title") %></h4>
  
  <%
      Person[] persons = (Person[])map.get("persons");
      for (int i = 0; i < persons.length; i++) {      
  %>  
  <%= persons[i].getName() %>
  <% } %>
 
  <input type="submit" value="送信">  
</form>
</body>
</html>

最後に、結果画面です。

結果画面

ViewResolverの例

ViewResolver はビュー名とビューとをマッピングするものです。レスポンスを返すものを「ビュー」と、Springでは呼んでいます。ビューの例としては「JSP」、「JSF」、「Velocity」、「Tiles」、「Excel」、「PDF」などがあります。

ViewResolver を指定する場合には、MVCアプリケーション定義ファイルに「viewResolver」という名前で設定します。

ViewResolverの設定例

<!-- 中略 -->
<bean id="viewResolver" 
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass">
    <value>org.springframework.web.servlet.view.JstlView</value>
  </property>
  <property name="prefix">
    <value>/WEB-INF/jsp/</value>
  </property>
  <property name="suffix">
    <value>.jsp</value>
  </property>
</bean>
<!-- 中略 -->

Validateを使った妥当性チェックの方法

データ検証について、『実践J2EE』から、少し抜粋します。(P.532)

データ検証 (Validation) は、「構文」の検証と「セマンティクス」の検証とに分類されます。構文検証には、データが存在するか、データの長さが許容範囲にあるか、データが有効なフォーマット(数字など)であるかといった、単純な操作が含まれます。通常、これはビジネスロジックではありません。セマンティクス検証はこれより手が込んだもので、ビジネスロジックやデータアクセスまでが含まれます。

Struts では、構文検証もセマンティクス検証も、アクションフォームの validate メソッドで行っています。しかし、Spring ではWeb 層にとらわれない方法でValidation 処理を行うことができます。Validator インターフェースを実装したクラスがそれに当たります。

ただし、Validator インターフェースでは、サポートするクラスを明示的に指定しなければなりません(supports メソッド)。これだと、フォームごとにアクションフォームのようなクラスをたくさん作った場合に、Validator クラスも作らなければなりません。

そこで、「構文」の検証には、BaseCommandController クラスの 「onBindAndValidate」メソッドをオーバーライドして、「セマンティクス」の検証にだけ、Validator インターフェースを継承したクラスを作成するのがいいと思います。

Bind を使ったエラーメッセージの表示方法

Bind というのは、コマンドオブジェクトのフィールドと、入力パラメータとを結びつける機構です。JSP の入力項目で idと password という入力項目があったとすると、コマンドオブジェクトの setId()、setPassword() というメソッドが自動的に呼ばれるということです。

もちろん、妥当性チェック(Validation) に失敗した場合にエラーメッセージを表示させることもできます。Struts のタグリブを使った動作とほとんど同じ感じです。

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> 
<%@ taglib prefix="spring" uri="/spring" %> 
<html> 
<body> 
<form action="entry.do" method="post"> 
  <table> 
    <tr> 
   <spring:bind path="person.id"> 
      <td> 
      ID: 
      </td> 
      <td> 
      <input type="text" name="id" value="<c:out value=""> 
      <td>  
      <font color="red"><c:out value="${status.errorMessage}"/></font> 
      </td> 
     </spring:bind> 
    </tr> 
    <tr> 
      <spring:bind path="person.password"> 
      <td> 
      Password: 
      </td> 
      <td> 
      <input type="text" name="password" value="<c:out value=""> 
      <td>  
      <font color="red"><c:out value="${status.errorMessage}"/></font> 
      </td> 
      </spring:bind> 
    </tr> 
<!-- 中略 -->

<spring:bind path="person.id">」の部分が Bind している部分です。person という名前で定義されたコマンドオブジェクトの id フィールドと、入力フィールドの id を結び付けています。 「{status.value} 」というのは Bind された値を表示する場合に使うものです。入力値を Bind して、妥当性チェックでエラーがあった場合に、元の画面で入力値を再表示させるときに使えます。

{status.errorMessage}」は妥当性チェック等で、Errors オブジェクトにエラーが設定された場合に表示されます。 Validation クラスのエラーチェック時に、 「errors.rejectValue(“id”, 《エラーコード》, “Default Message.”) メソッド」を呼び出してエラーを設定すると、画面に表示されるようになります。ちなみに「{status.expression}」はバインドするプロパティ名が取得できます。フィールドの name 属性にセットするという使い方が出来ます。

Validation で エラーメッセージを追加する方法

public void validate(Object command, Errors errors) { 
  Person person = (Person)command; 
  if (person.getPassword() == null) { 
    errors.rejectValue("password", "M001",  
                       new String[] { "Password" },  
                       "必須入力です。"); 
  } 
} 

Bind するときに使った「person」を定義する場所は、Web アプリケーション定義ファイルです。他にも、コントローラのコンストラクタで setCommandName を呼び出してコマンド名を設定しているサンプルもありました。

Web アプリケーション定義ファイルでコマンドオブジェクトを指定する

<bean id="EntryFormController" 
      class="jp.dip.xlegend.spring.web.EntryFormController"> 
  <property name="commandName"> 
    <value>person</value> 
  </property> 
  <property name="commandClass"> 
    <value>jp.dip.xlegend.spring.Person</value> 
  </property> 
<!-- 中略 -->

commandName」 に Bind するときに使ったコマンド名を指定します。「commandClass」 はコマンドのクラス名を書きます。Spring では、入力値をそのままドメインのオブジェクトにマッピングすることが出来ます。Struts では ActionForm を使わなければならず、コントローラで値の詰め替えが必要でしたが、Spring ではその必要はありません。ただ、凝った画面表示をしようとした場合には、画面用のコマンドを用意して処理を呼び出すなどの方法も必要かもしれません。

Bindの結果

型変換時のエラーメッセージを独自のメッセージにする方法

Bind 時に型変換でエラーが出ると次のようなエラーが出力されます。

Failed to convert property value of type [java.lang.String] to required type [{型名}] for property '{プロパティ名}'; nested exception is ...

このエラーは、開発時はまだ許せるとして、リリースした後は、ユーザにはまったく意味不明のメッセージになっています。

このメッセージは、MessageResource を使うことで、独自のメッセージにすることが出来ます。メッセージファイルに 「typeMismatch.{プロパティ名}」 というキーでメッセージを定義しておくと、そのメッセージが使えます。そして、置換文字の 0番目「{0}」にプロパティ名が埋め込まれるようになっています。(typeMismatch だけだと、すべての型変換エラーに対するメッセージが定義できる。typeMismatch.{コマンド名}.{プロパティ名} だと、コマンド名で指定されたものにマッチするようになる。さらに、typeMismatch.{型名} だと、型名にマッチするものに対してメッセージを指定できる。)

errorMessage.properties

# 日本語は native2ascii をかけておく
typeMismatch={0} は入力形式が無効です。
typeMismatch.java.sql.Timestamp={0} は日付型で入力してください。
typeMismatch.int={0} は整数値で入力してください。
typeMismatch.dateFiled={0} は yyyy/mm/dd 。
typeMismatch.command.dateField={0} は yyyy/mm/dd の形で入力してください。 

詳細に設定するほど優先的に使われるようです。上記のように定義した場合、command.dateFiled プロパティのエラーメッセージは「{0} はyyyy/mm/dd の形で入力してください。」 が使われます。それ以外の型エラーに関しては、「{0} は入力形式が無効です。」が使われます。

[参考]

Spring Framework API - DefaultMessageCodesResolver

独自の型変換を使う方法

MVC フレームワークでは、CustomeEditor の設定の仕方がちょっと違ったのでメモ。MVC フレームワーク中で CustomeEditor を設定するには、BaseCommandController クラスのメソッド 「initBind(HttpServletRequest request, ServletRequestDataBinder binder)」メソッドをオーバーライドして、その中で、binder.registerCustomEditor(Class, PropertyEditor) を呼び出します。SimpleFormController は BaseCommandController を継承しています。

protected void initBinder(HttpServletRequest request, 
                          ServletRequestDataBinder binder)
    throws ServletException {        
  CustomDateEditor de =  new CustomDateEditor(
            new SimpleDateFormat("yyyy/MM/dd"), true);        
  binder.registerCustomEditor(java.util.Date.class, de);
}

Command コントローラ一覧

Spring MVC フレームワークで使われるコントローラの中で、基本的なコントローラである Command Controller をまとめます。

[参考]

Spring Framework リファレンス - 12.3.4. CommandControllers

Command Controller 一覧
クラス名 説明
AbstractCommandController 任意のデータオブジェクトにリクエストをマッピングできる コマンドコントローラ を定義するために使います。フォーム機能は提供しませんが妥当性チェック(Validation)機能は提供されます。。明示的にリクエストパラメータをデータオブジェクトせ設定できるので、分かりやすいコントローラです。
AbstractFormController フォーム送信機能を提供します。データオブジェクトにバインドされたフォームを表示し、妥当性エラーが発生したときに画面を再表示できます。サポートされる機能は、不正入力送信チェック、妥当性チェック、フォームのワークフローです。このコントローラは、ビューの指定を明示することができません。
SimpleFormController 指定したデータオブジェクトとのマッピングを行うフォームコントローラの具象クラスです。コマンドオブジェクトと、成功時や失敗時に表示するビュー名を指定することができます。
AbstractWizardFormController ウィザード形式のフォームを作るときに指定します。validatePage, processFinish, processCancel メソッドを実装します。この3つのメソッドを適切に実装して、ワークフローを定義します。

コントローラマッピング

コントローラサーブレットは、リクエストを処理するコントローラを選択します。どのような条件でコントローラが選択されるかは、Bean 定義で設定されている HandlerMapping インターフェースの実装クラスに任されます。

BeanNameUrlHandlerMapping

Struts と同じようなマッピング方法で、スラッシュ("/")で始まるURLと Bean の名前をマッピングするクラス。DispatcherServlet がデフォルトで使う実装です。

SimpleUrlHandlerMapping

URL からリクエストハンドラBean へのマッピングを提供します。「urlMap」プロパティにマッピンを定義します。この定義は Bean 定義ファイルに書きます。

ハマった点

Bind 時に例外が発生する

Bind 時に次のような例外がでます。

javax.servlet.ServletException: Neither Errors instance nor plain target object for bean name 《コマンド名》 available as request attribute

これは、Bind するコマンドオブジェクトがリクエストに保存されていないのが原因です。コントローラに SimpleFormController を使っている場合、processFormSubmission() メソッドで、super.onSumit(request, response, command, errors) を呼び出すと、例外は発生しなくなりました。参考までに。

更新系画面の初期表示はどうするのか?

FormController 系のコントローラを使うと、フォーム送信をデータオブジェクトに自動でバインドしてくれて楽チンです。ですが、初期表示(フォームに何も入力していない状態の画面)を行いたい場合に、どうすればいいのか分かりませんでした。

SimpleFormController の 「formView」プロパティは、初期表示する画面を設定するプロパティだったということに、やっと気づきました。Struts とかだと、初期表示用のアクションを用意していたので Spring でもそうするのかと思ってました。ハマった・・・ (T T;)

それでもって、初期表示に使いたいデータは 「protected Map referenceData(HttpServletRequest) throws Exception」メソッドをオーバーライドして Map につめて返せばいいわけでした。

Spring MVC フレームワークに出てくる用語

Spring MVCフレームワークに出てくる用語をまとめておきます。

コントローラサーブレット

フレームワークを使用するためのエントリポイントとなるサーブレット。コントローラのコントローラであり、アプリケーション固有のリクエストコントローラを呼び出す役割を担います。DispatcherServlet はコントローラサーブレットです。

コントローラ(リクエストコントローラ)

リクエストの処理を受け持つサーブレットです。通常、コントローラサーブレットによってリクエストの処理を委譲されます。コントローラはマルチスレッドコンポーネントであり、スレッドセーフでなければなりません。したがって、フィールドやプロパティはリードオンリであることが推奨されます。org.springframework.web.servlet.mvc.Controller インターフェースを実装する必要があります。実装クラスには BaseCommandController, AbstractFormController, SimpleFormController, MultiActionController などがあります。

ハンドラマッピング

リクエストをリクエストコントローラに結びつける役割を担います。コントローラサーブレットは、ハンドラマッピングを元にリクエストを委譲するリクエストコントローラを判断します。org.springframework.web.servlet.HandlerMapping インターフェースを実装する必要があります。実装クラスには BeanNameUrlHandlerMapping, SimpleUrlHandlerMapping などがあります。

Handler mappings

ModelAndView

MVC アーキテクチャにおける モデルとビューのホルダーです。ビュー名にモデルをバインドして、リクエストコントローラから返されます。

ビュー

モデルをレンダリングするオブジェクトです。ビューオブジェクトはレスポンスにモデルデータをレンダリングするのが仕事です。org.springframework.web.servlet.View インターフェースを実装します。実装クラスには JstlView, TilesView, VelocityView などがあります。

ビューリゾルバ

ModelAndView のビュー名から、ビューオブジェクトを解決するクラスです。実装クラスには UrlBasedViewResolver などがあります。

View and resolving them

ワークフロー

コントローラにおける処理の流れのことです。ウィザード形式のフォームコントローラを使用する場合など、画面間における必須項目のチェックなどを行えます。

ハンドラインターセプター

コントローラを呼ぶ前や、コントローラの処理が終了した後などに、呼び出されるコールバックオブジェクト。インターセプターと名前がつくことから、コントローラの処理を横取りして、処理をなかったことにしたり、装飾を加えたリクエストをコントローラに渡したりできる。HandlerInterceptor インターフェースを実装する必要がある。通常、HandlerInterceptorAdapter クラスを継承して、任意のインターセプトポイントに関するメソッドのみをオーバーライドすればよい。

妥当性チェック (Validation)

入力値が処理可能なものかを検査すること。一般に「構文」の検証と「セマンティクス」の検証とがある。構文検証は、データが存在するか、データの長さが許容範囲に日あっているか、データが有効なフォーマットかどうかを調べるものです。セマンティクス検証は、ビジネスロジックやデータアクセスまでが含まれる、手の込んだ検証になります。

参考

  • Spring の ロッドジョンソンが贈る、J2EE技術者のためのバイブル
  • Spring のロッドジョンソンによる Spring ユーザのための本 (洋書)
  • SpringでWebアプリケーションを作りながら、Springの全体像がわかりやすく解説されています。