Spring-MVC/ステップ・バイ・ステップ

2008/04/14からのアクセス回数 25482

mvc-conventionのサンプルプログラムは、とてもシンプルで素晴らしいのですが、 規約をどのように使用したかを解説していないので、ソースを見ただけでは理解 しにくいので、ここで説明します。

設定ファイルの説明

サンプルの設定ファイルは、

  • web.xml
  • applicationContext.xml
  • coverc-servlet.xml

最後のcoverc-servlet.xmlは、「サーブレット名-servlet.xml」がサーブレット関連Bean定義ファイルの デフォルトファイル名です。DsipatcherServletの初期化で使用されます。

web.xmlの設定

web.xmlでSpring-MVC特有の定義は、

    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>coverc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>coverc</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
  • ContextLoaderListenerは、WebアプリケーションのContextをロードするためのサーブレット・リスナー です
  • サーブレットの定義では、DispatcherServletを指定します
  • サーブレット・マッピングは、xxxx.htmという要求をcovercというサーブレットにマッピングしています

サーブレット名称は、Servlet関連Bean定義ファイルを読み込むために使用されますので、適宜変更してください。

サーブレット関連のBean定義ファイルを細分して定義する場合には、web.xmlの contextConfigLocationに以下のように定義ファイルを列記します。

    <servlet>
        <servlet-name>cart</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
	     <param-name>contextConfigLocation</param-name>
	     <param-value>/WEB-INF/servlet-def.xml,/WEB-INF/servlet-stub.xml</param-value>
	</init-param>
    </servlet>

applicationContext.xml

applicationContext.xmlの定義は至って簡単です。

webアプリケーションで共通に利用されるrecipeManagerの定義をしています。

<bean id="recipeManager" class="org.springframework.showcase.coverc.service.StubRecipeManager"/>

coverc-servlet.xml

coverc-servlet.xmlでは、

  • ControllerClassNameHandlerMappingの定義
  • SwitchBoardControllerの定義
  • EditRecipeControllerの定義
  • viewNameTranslatorの定義
  • viewResolverの定義

をしています。

ControllerClassNameHandlerMappingは、コントローラのクラス名でHTTP要求を振り分けるHandlerMapppingです。

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

DefaultRequestToViewNameTranslatorは、ModelAndViewオブジェクトにビューの名前が定義 されていない場合に、デフォルトのview名称を返してくれるクラスです。 詳しくは、Spring-MVC/ステップ・バイ・ステップ/Convention over configurationを参照してください。

    <bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>

InternalResourceViewResolverは、論理ビュー名称から、実際のビューファイル名にマッピングしています。

ここでは、xxxという論理ビュー名に対するビューファイルとして、/WEB-INF/jsp/xxx.jspを返すように

  • prefixに/WEB-INF/jspを指定
  • suffixに.jspを指定

しています。

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

Spring2.0からBean定義ファイルで継承が使えるようになりました。

baseRecipeControllerは、SwitchBoardController、EditRecipeControllerの親Bean定義で この定義で、共通に使用する属性recipeManagerの定義をしています。 親Bean定義では、クラスを指定する必要がなく、abstract="true"とすることで、 必要な属性のみを定義することができます。

    <bean id="baseRecipeController" abstract="true">
        <property name="recipeManager" ref="recipeManager"/>
    </bean>

SwitchBoardControllerの定義は、

    <bean class="org.springframework.showcase.coverc.web.SwitchBoardController"
          parent="baseRecipeController"/>

EditRecipeControllerは、SimpleFormControllerのサブクラスなので、ちょっと多くの設定 が必要です。

  • commandNameは、コマンドオブジェクトの名称を指定します
  • commandClassは、コマンドオブジェクトのクラス名を指定します
  • formViewは、フォームビューの論理名を指定します
  • successViewは、成功時のビューを指定します、ここではswitchboard/listRecipes.htmにリダイレクトしています
    <bean class="org.springframework.showcase.coverc.web.EditRecipeController"
          parent="baseRecipeController">
        <property name="commandName" value="recipe"/>
        <property name="commandClass" value="org.springframework.showcase.coverc.domain.Recipe"/>
        <property name="formView" value="editRecipe"/>
        <property name="successView" value="redirect:switchboard/listRecipes.htm"/>
    </bean>

javaソースファイルの説明

モデルクラス

ドメインモデルクラスは、Recipe.java1個のみです。 属性にid, nameを持ち、それぞれのgetter/setterを定義し、cloneを追加した きわめて簡素なものです。

public class Recipe implements Cloneable {
    private Long id;
    private String name;

    // getter/setterは省略

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

サービスクラス

サービスクラスは、RecipeManagerインタフェースとその実装例としてStubRecipeMangerが あります。

RecipeManagerインタフェースは、

  • findAll: すべてのRecipeを取り出すメソッド
  • findById: 指定されたIdのRecipeを取り出すメソッド
  • save: 指定されたRecipeを保存するメソッド

を定義しています。

public interface RecipeManager {
    Collection findAll();
    Recipe findById(Long id);
    void save(Recipe user);
}

StubRecipeManagerでは、TreeMapを使ってRecipeをメモリ上で管理しています。 loadRecipesメソッドでTreeMapに3個のRecipeをセットしています。

  • findAllでは、TreeMapから取りだしたRecipeをArrayListにセットして返しています。

従ってfindAllで戻されたオブジェクトの名前は、recipeListになります。 詳しくは、Spring-MVC/ステップ・バイ・ステップ/Convention over configurationを参照してください。

public class StubRecipeManager implements RecipeManager {
    private Map recipes = new TreeMap();

    public StubRecipeManager() {
        loadRecipes();
    }

    public void save(Recipe recipe) {
        // passed in should be a clone - simply replace
        putRecipe(recipe);
    }

    public Recipe findById(Long id) {
        Recipe recipe = (Recipe) this.recipes.get(id);
        if (recipe != null) {
            return cloneRecipe(recipe);
        }
        return null;
    }

    public Collection findAll() {
        List recipeList = new ArrayList();
        Iterator itr = this.recipes.values().iterator();
        while (itr.hasNext()) {
            Recipe recipe = (Recipe) itr.next();
            recipeList.add(cloneRecipe(recipe));
        }
        return recipeList;
    }
}

コントローラクラス

SwitchBoardControllerは、recipeManagerを属性に持ち、

  • listRecipesメソッド を定義しています。
ModelAndView(). addObject(findAllの戻り値);

としている部分が、規約の使い方を示すための例です。 findAllの戻り値はRecipeを要素に持つArrayListですので、そのオブジェクトは、recipeListとしてモデルに追加されます。 詳しくは、Spring-MVC/ステップ・バイ・ステップ/Convention over configurationを参照してください。

public class SwitchBoardController extends MultiActionController {
    private RecipeManager recipeManager;

    // setRecipeManagerは省略

    public ModelAndView listRecipes(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return new ModelAndView().addObject(this.recipeManager.findAll());
    }
}

EditRecipeControllerも、recipeManagerを属性に持ち、

  • formBackingObject : フォームにオブジェクトをセットするためのメソッド
  • doSubmitAction : submit要求によって呼び出されるメソッド
public class EditRecipeController extends SimpleFormController {
    private RecipeManager recipeManager;

    // setRecipeManagerは省略

    protected Object formBackingObject(HttpServletRequest request) throws Exception {
        long id = ServletRequestUtils.getRequiredLongParameter(request, "id");
        Recipe recipe = this.recipeManager.findById(new Long(id));
        return recipe;
    }

    protected void doSubmitAction(Object object) throws Exception {
        Recipe recipe = (Recipe) object;
        this.recipeManager.save(recipe);
    }
}

本当にこれだけで、よいのかと思うくらい少ない量のソースで、mvc-conventionの例題が 作られています。

コメント

この記事は、

選択肢 投票
おもしろかった 17  
そうでもない 0  
わかりずらい 4  

皆様のご意見、ご希望をお待ちしております。


(Input image string)


トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-06-15 (木) 08:38:47 (476d)
SmartDoc