1前書き

Spring MVCでは、

DispatcherServlet

はリンクとして機能します:/java-front-controller-pattern[フロントコントローラ] – すべての入ってくるHTTPリクエストを受け取り、それらを処理します。

簡単に言うと、処理はハンドラマッピングの助けを借りて関連するコンポーネントにリクエストを渡すことによって行われます




_.

_


HandlerMapping

は、要求とリンクとの間のマッピングを定義するインターフェースです。/spring-mvc-handler-adapters[handler objects]。 Spring MVCフレームワークはいくつかの既製の実装を提供しますが、カスタマイズされたマッピング戦略を提供するために開発者がインタフェースを実装することができます。

この記事では、Spring MVCが提供するいくつかの実装、つまり

BeanNameUrlHandlerMapping



SimpleUrlHandlerMapping



ControllerClassNameHandlerMapping

、それらの設定、およびそれらの違いについて説明します。


2.



BeanNameUrlHandlerMapping



BeanNameUrlHandlerMapping

は、デフォルトの

HandlerMapping

実装です。

BeanNameUrlHandlerMapping

は、要求URLを同じ名前のBeanにマップします。

この特定のマッピングは、直接名のマッチング、および「** 」パターンを使用したパターンマッチングもサポートしています。

たとえば、着信URL

“/foo”



“/foo”

というBeanにマップされます。パターンマッピングの例としては、

“/foo2/”



“/fooOne/”

のように、

“/foo ** “への要求を

“/foo”で始まる名前のBeanにマッピングすることが挙げられます。

ここでこの例を設定し、

“/beanNameUrl”

へのリクエストを処理するBeanコントローラを登録しましょう。

@Configuration
public class BeanNameUrlHandlerMappingConfig {
    @Bean
    BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
        return new BeanNameUrlHandlerMapping();
    }

    @Bean("/beanNameUrl")
    public WelcomeController welcome() {
        return new WelcomeController();
    }
}

これは、上記のJavaベースの設定と同じXMLです。

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/beanNameUrl" class="com.baeldung.WelcomeController"/>

Spring MVCで提供されているように、これらの両方の設定で、

BeanNameUrlHandlerMapping

のBeanを定義する必要はありません。この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<String, Object> urlMap = new HashMap<>();
        urlMap.put("/simpleUrlWelcome", welcome());
        simpleUrlHandlerMapping.setUrlMap(urlMap);

        return simpleUrlHandlerMapping;
    }

    @Bean
    public WelcomeController welcome() {
        return new WelcomeController();
    }
}

あるいは、これと同等のXML構成です。

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <value>
           /simpleUrlWelcome=welcome
           /** /simpleUrlWelcome=welcome
        </value>
    </property>
</bean>
<bean id="welcome" class="com.baeldung.WelcomeController"/>

XML設定では、

“<値>”

タグ間のマッピングは、

java.util.Properties

クラスで受け入れられる形式で実行する必要があり、構文は次のようになります。

URLは通常先頭にスラッシュを付ける必要がありますが、パスが最初から始まらない場合は、Spring MVCによって自動的に追加されます。

XMLで上記の例を設定する別の方法は、

“value”

の代わりに

“props”

プロパティを使用することです。

Props

には

“ prop”

タグのリストがあり、それぞれがマッピングを定義します。ここで、

“key”

はマッピングされたURLを参照し、タグの値はBeanの名前です。

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/simpleUrlWelcome">welcome</prop>
            <prop key="/** /simpleUrlWelcome">welcome</prop>
        </props>
    </property>
</bean>

次のテストケースでは、 “/

simpleUrlWelcome

“への要求が ”

” welcome ”

というビュー名を返す”

WelcomeController ”

によって処理されることを確認しています。

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

は、アノテーション駆動型ハンドラーメソッドのために、Spring 4.3からは非推奨になりました。

もう一つの重要な注意点は、コントローラ名は常に小文字で返されるということです( “Controller”サフィックスを除く)。そのため、

WelcomeBaeldungController

という名前のコントローラーがある場合、それは

“/welcomebaeldung”

への要求のみを処理し、

“/welcomeBaeldung”

への要求は処理しません。

以下のJava設定とXML設定の両方で、

ControllerClassNameHandlerMapping

Beanを定義し、リクエストを処理するために使用するコントローラ用のBeanを登録します。また、

“ WelcomeController”

タイプのBeanを登録し、そのBeanが

“/welcome”

で始まるすべての要求を処理します。

これは、同等のXML構成です。

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

上記の設定を使用する場合、“/

welcome

”へのリクエストは、“

WelcomeController

”によって処理されます。

次のコードは、 “/

welcometest

“などの “/

welcome

** “への要求が、 “WelcomeController”によって処理され、 ”

welcome

“というビュー名を返すことを確認します。

public class ControllerClassNameHandlerMappingTest {
   //...

    @Test
    public void whenControllerClassNameMapping__thenMappedOK() {
        mockMvc.perform(get("/welcometest"))
          .andExpect(status().isOk())
          .andExpect(view().name("welcome"));
    }
}


5優先順位の設定

Spring MVCフレームワークは同時に

HandlerMapping

インターフェースの複数の実装を可能にします。

設定を作成し、2つのコントローラを登録します。両方とも「/welcome」というURLにマッピングされます。異なるマッピングを使用し、異なるビュー名を返すだけです。

@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<String, Object> 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”

というプロパティを使用して優先順位を設定できます。

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="order" value="2"/>
</bean>

次に示す

beanNameUrlHandlerMapping.setOrder(1)

および

simpleUrlHandlerMapping.setOrder(0)を介して、

order__プロパティをハンドラマッピングBeanに追加してみましょう。テストで新しい動作を表明しましょう。

@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

viewを返す

SimpleUrlHandlerMapping

Beanによって処理されることがわかります。

order

プロパティの値を適宜調整することで、

BeanNameHandlerMapping

を優先するように簡単に設定できます。


6. 結論

この記事では、フレームワーク内のさまざまな実装を調べることによって、Spring MVCフレームワークでURLマッピングがどのように処理されるかを説明しました。

この記事に付随するコードはhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-java/[over on GitHub]にあります。