Spring Handler Mappingsのガイド
1. 前書き
Spring MVCでは、DispatcherServletはfront controllerとして機能し、すべての着信HTTP要求を受信して処理します。
簡単に言えば、処理は、関連するコンポーネントwith the help of handler mappings.に要求を渡すことによって行われます。
HandlerMappingは、リクエストとhandler objectsの間のマッピングを定義するインターフェースです。 Spring MVCフレームワークは既製の実装を提供しますが、開発者はインターフェイスを実装して、カスタマイズされたマッピング戦略を提供できます。
この記事では、Spring MVCによって提供されるいくつかの実装、つまりBeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、ControllerClassNameHandlerMapping、それらの構成、およびそれらの違いについて説明します。
2. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMappingは、デフォルトのHandlerMapping実装です。 BeanNameUrlHandlerMappingは、リクエストURLを同じ名前のBeanにマップします。
この特定のマッピングでは、名前の直接一致と「*」パターンを使用したパターン一致がサポートされています。
たとえば、着信URL“/foo”は、“/foo”というBeanにマップされます。 パターンマッピングの例は、“/foo*”へのリクエストを“/foo2/”や“/fooOne/”のように“/foo”で始まる名前のBeanにマッピングすることです。
ここでこの例を構成し、“/beanNameUrl”への要求を処理するBeanコントローラーを登録しましょう。
@Configuration
public class BeanNameUrlHandlerMappingConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
@Bean("/beanNameUrl")
public WelcomeController welcome() {
return new WelcomeController();
}
}
これは、上記のJavaベースの構成に相当するXMLです。
これらの構成の両方で、Spring MVCによって提供されるdefining a bean for BeanNameUrlHandlerMapping is not requiredに注意することが重要です。 このBean定義を削除しても問題は発生せず、要求は登録されたハンドラーBeanに引き続きマッピングされます。
これで、“/beanNameUrl”へのすべての要求は、DispatcherServletによって「WelcomeController」に転送されます。 WelcomeControllerは、「welcome」というビュー名を返します。
次のコードはこの構成をテストし、正しいビュー名が返されることを確認します。
public class BeanNameMappingConfigTest {
// ...
@Test
public void whenBeanNameMapping_thenMappedOK() {
mockMvc.perform(get("/beanNameUrl"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
3. SimpleUrlHandlerMapping
次に、SimpleUrlHandlerMappingは最も柔軟なHandlerMappingの実装です。 BeanインスタンスとURLの間、またはBean名とURLの間の直接および宣言マッピングが可能です。
リクエスト“/simpleUrlWelcome”と“/*/simpleUrlWelcome”を“welcome”Beanにマップしましょう。
@Configuration
public class SimpleUrlHandlerMappingConfig {
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map urlMap = new HashMap<>();
urlMap.put("/simpleUrlWelcome", welcome());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
または、同等のXML構成は次のとおりです。
/simpleUrlWelcome=welcome
/*/simpleUrlWelcome=welcome
XML構成では、“<value>”タグ間のマッピングは、java.util.Propertiesクラスで受け入れられる形式で行う必要があり、構文path= Handler_Bean_Nameに従う必要があることに注意してください。
通常、URLは先頭にスラッシュを付ける必要がありますが、パスがスラッシュで始まらない場合、SpringMVCはそれを自動的に追加します。
上記の例をXMLで構成する別の方法は、“value”の代わりに“props”プロパティを使用することです。 Propsには“prop”タグのリストがあり、それぞれがマッピングを定義します。“key”はマップされたURLを参照し、タグの値はBeanの名前です。
welcome
welcome
次のテストケースでは、「/simpleUrlWelcome」へのリクエストが「WelcomeController”」によって処理され、“welcome”というビュー名が返されることを確認します。
public class SimpleUrlMappingConfigTest {
// ...
@Test
public void whenSimpleUrlMapping_thenMappedOK() {
mockMvc.perform(get("/simpleUrlWelcome"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
4. ControllerClassNameHandlerMapping(Spring 5で削除)
ControllerClassNameHandlerMappingは、URLを、同じ名前を持つ、または同じ名前で始まる登録済みコントローラーBean(または@Controllerアノテーションが付けられたコントローラー)にマップします。
特に、単一の要求タイプを処理する単純なコントローラー実装の場合、多くのシナリオでより便利です。 Spring MVCで使用される規則は、クラスの名前を使用して“Controller”サフィックスを削除してから、名前を小文字に変更し、先頭に“/”が付いたマッピングとして返すことです。
たとえば、“WelcomeController”は“/welcome*”へのマッピングとして返されます。 “welcome”で始まる任意のURLに。
ControllerClassNameHandlerMappingを構成しましょう:
@Configuration
public class ControllerClassNameHandlerMappingConfig {
@Bean
public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
return new ControllerClassNameHandlerMapping();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
ControllerClassNameHandlerMappingはdeprecated from Spring 4.3であり、アノテーション駆動型ハンドラーメソッドを優先することに注意してください。
もう1つの重要な注意点は、コントローラー名は常に小文字で返されることです(「Controller」サフィックスを除く)。 したがって、「WelcomeexampleController」というコントローラーがある場合、それは“/welcomeexample”への要求のみを処理し、“/welcomeexample”への要求は処理しません。
以下のJava構成とXML構成の両方で、ControllerClassNameHandlerMapping Beanを定義し、要求の処理に使用するコントローラーのBeanを登録します。 また、タイプ“WelcomeController”のBeanを登録すると、そのBeanは“/welcome”で始まるすべての要求を処理します。
同等のXML構成は次のとおりです。
上記の構成を使用する場合、「/welcome」への要求は「WelcomeController」によって処理されます。
次のコードは、「/welcometest」などの「/welcome *」へのリクエストが「welcome」というビュー名を返す「WelcomeController」によって処理されることを確認します。
public class ControllerClassNameHandlerMappingTest {
// ...
@Test
public void whenControllerClassNameMapping_thenMappedOK() {
mockMvc.perform(get("/welcometest"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
5. 優先順位の構成
Spring MVCフレームワークでは、HandlerMappingインターフェースを同時に複数実装できます。
構成を作成し、2つのコントローラーを登録します。両方のコントローラーはURL「/ welcome」にマップされ、異なるマッピングを使用して異なるビュー名のみを返します。
@Configuration
public class HandlerMappingDefaultConfig {
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
明示的なハンドラマッパーが登録されていない場合、デフォルトのBeanNameHandlerMappingが使用されます。 テストでこの動作をアサートしましょう:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("bean-name-handler-mapping"));
}
別のハンドラーマッパーを明示的に登録すると、デフォルトのマッパーがオーバーライドされます。 ただし、2つのマッパーが明示的に登録されたときに何が起こるかを見るのは興味深いです。
@Configuration
public class HandlerMappingPrioritiesConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping
= new BeanNameUrlHandlerMapping();
return beanNameUrlHandlerMapping;
}
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleUrlHandlerMapping
= new SimpleUrlHandlerMapping();
Map urlMap = new HashMap<>();
urlMap.put("/welcome", simpleUrlMapping());
simpleUrlHandlerMapping.setUrlMap(urlMap);
return simpleUrlHandlerMapping;
}
@Bean
public SimpleUrlMappingController simpleUrlMapping() {
return new SimpleUrlMappingController();
}
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
}
使用するマッピングを制御するには、setOrder(int order)メソッドを使用して優先度を設定します。 このメソッドは1つのintパラメータを取ります。値が小さいほど優先度が高くなります。
XML構成では、“order”というプロパティを使用して優先順位を構成できます。
次のbeanNameUrlHandlerMapping.setOrder(1)およびsimpleUrlHandlerMapping.setOrder(0).を使用して、ハンドラーマッピングBeanにorderプロパティを追加しましょう。orderプロパティの値が小さいほど、優先順位が高くなります。 テストで新しい動作をアサートしましょう:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("simple-url-handler-mapping"));
}
上記の構成をテストすると、“/welcome”への要求は、SimpleUrlHandlerControllerを呼び出してsimple-url-handler-mappingビューを返すSimpleUrlHandlerMappingBeanによって処理されることがわかります。 orderプロパティの値を適宜調整することで、BeanNameHandlerMappingが優先されるように簡単に構成できます。
6. 結論
この記事では、Spring MVCフレームワークでのURLマッピングの処理方法について、フレームワークでのさまざまな実装を検討することで説明しました。
この記事に付随するコードはover on GitHubにあります。