- 追加された行はこの色です。
- 削除された行はこの色です。
#freeze
[[Spring-MVC/ステップ・バイ・ステップ]]
2008/04/14からのアクセス回数 &counter;
#contents
mvc-conventionのサンプルプログラムは、とてもシンプルで素晴らしいのですが、
規約をどのように使用したかを解説していないので、ソースを見ただけでは理解
しにくいので、ここで説明します。
** 設定ファイルの説明 [#bcc9406e]
サンプルの設定ファイルは、
- web.xml
- applicationContext.xml
- coverc-servlet.xml
最後のcoverc-servlet.xmlは、「サーブレット名-servlet.xml」がサーブレット関連Bean定義ファイルの
デフォルトファイル名です。DsipatcherServletの初期化で使用されます。
*** web.xmlの設定 [#k104e4bd]
web.xmlでSpring-MVC特有の定義は、
#pre{{
<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に以下のように定義ファイルを列記します。
#pre{{
<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 [#b9d80f43]
applicationContext.xmlの定義は至って簡単です。
webアプリケーションで共通に利用されるrecipeManagerの定義をしています。
#pre{{
<bean id="recipeManager" class="org.springframework.showcase.coverc.service.StubRecipeManager"/>
}}
*** coverc-servlet.xml [#ub9f2ead]
coverc-servlet.xmlでは、
- ControllerClassNameHandlerMappingの定義
- SwitchBoardControllerの定義
- EditRecipeControllerの定義
- viewNameTranslatorの定義
- viewResolverの定義
をしています。
ControllerClassNameHandlerMappingは、コントローラのクラス名でHTTP要求を振り分けるHandlerMapppingです。
#pre{{
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
}}
DefaultRequestToViewNameTranslatorは、ModelAndViewオブジェクトにビューの名前が定義
されていない場合に、デフォルトのview名称を返してくれるクラスです。
詳しくは、[[Spring-MVC/ステップ・バイ・ステップ/Convention over configuration]]を参照してください。
#pre{{
<bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>
}}
InternalResourceViewResolverは、論理ビュー名称から、実際のビューファイル名にマッピングしています。
ここでは、xxxという論理ビュー名に対するビューファイルとして、/WEB-INF/jsp/xxx.jspを返すように
- prefixに/WEB-INF/jspを指定
- suffixに.jspを指定
しています。
#pre{{
<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"とすることで、
必要な属性のみを定義することができます。
#pre{{
<bean id="baseRecipeController" abstract="true">
<property name="recipeManager" ref="recipeManager"/>
</bean>
}}
SwitchBoardControllerの定義は、
#pre{{
<bean class="org.springframework.showcase.coverc.web.SwitchBoardController"
parent="baseRecipeController"/>
}}
EditRecipeControllerは、SimpleFormControllerのサブクラスなので、ちょっと多くの設定
が必要です。
- commandNameは、コマンドオブジェクトの名称を指定します
- commandClassは、コマンドオブジェクトのクラス名を指定します
- formViewは、フォームビューの論理名を指定します
- successViewは、成功時のビューを指定します、ここではswitchboard/listRecipes.htmにリダイレクトしています
#pre{{
<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ソースファイルの説明 [#rce5b505]
*** モデルクラス [#h1f7c550]
ドメインモデルクラスは、Recipe.java1個のみです。
属性にid, nameを持ち、それぞれのgetter/setterを定義し、cloneを追加した
きわめて簡素なものです。
#pre{{
public class Recipe implements Cloneable {
private Long id;
private String name;
// getter/setterは省略
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
}}
*** サービスクラス [#g38f3e78]
サービスクラスは、RecipeManagerインタフェースとその実装例としてStubRecipeMangerが
あります。
RecipeManagerインタフェースは、
- findAll: すべてのRecipeを取り出すメソッド
- findById: 指定されたIdのRecipeを取り出すメソッド
- save: 指定されたRecipeを保存するメソッド
を定義しています。
#pre{{
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]]を参照してください。
#pre{{
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;
}
}
}}
*** コントローラクラス [#wbd60333]
SwitchBoardControllerは、recipeManagerを属性に持ち、
- listRecipesメソッド
を定義しています。
ModelAndView(). addObject(findAllの戻り値);
としている部分が、規約の使い方を示すための例です。
findAllの戻り値はRecipeを要素に持つArrayListですので、そのオブジェクトは、recipeListとしてモデルに追加されます。
詳しくは、[[Spring-MVC/ステップ・バイ・ステップ/Convention over configuration]]を参照してください。
#pre{{
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要求によって呼び出されるメソッド
#pre{{
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の例題が
作られています。
** コメント [#qec290b0]
この記事は、
#vote(おもしろかった[13],そうでもない[0],わかりずらい[2])
#vote(おもしろかった[13],そうでもない[0],わかりずらい[3])
皆様のご意見、ご希望をお待ちしております。
#comment_kcaptcha