#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(おもしろかった[16],そうでもない[0],わかりずらい[4]) #vote(おもしろかった[17],そうでもない[0],わかりずらい[4]) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha