Spring Handler 매핑 가이드

1. 소개

Spring MVC에서 DispatcherServlet 은 들어오는 모든 HTTP 요청을 수신하고 처리하는 프런트 컨트롤러 역할을합니다.

간단히 말해서 핸들러 매핑의 도움으로 요청을 관련 구성 요소에 전달하여 처리가 발생 합니다 .

HandlerMapping 은 요청과 핸들러 객체 간의 매핑을 정의하는 인터페이스입니다. Spring MVC 프레임 워크는 몇 가지 기성 구현을 제공하지만 인터페이스는 개발자가 사용자 정의 매핑 전략을 제공하기 위해 구현할 수 있습니다.

이 기사에서는 Spring MVC에서 제공하는 BeanNameUrlHandlerMapping , SimpleUrlHandlerMapping , ControllerClassNameHandlerMapping , 구성 및 차이점에 대해 설명합니다.

2. BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping 은 기본 HandlerMapping 구현입니다. BeanNameUrlHandlerMapping 은 요청 URL을 동일한 이름을 가진 빈에 매핑합니다.

이 특정 매핑은 직접 이름 일치 및 "*"패턴을 사용한 패턴 일치를 지원합니다.

예를 들어, 수신 URL "/ foo""/ foo" 라는 빈에 매핑됩니다 . 패턴 매핑의 예는 "/ foo2 /" 또는 "/ fooOne /" 과 같이 이름이 "/ foo"로 시작하는 빈 에 "/ foo *" 에 대한 요청을 매핑하는 것입니다 .

여기에서이 예제를 구성하고 "/ beanNameUrl"에 대한 요청을 처리하는 Bean 컨트롤러를 등록 해 보겠습니다 .

@Configuration public class BeanNameUrlHandlerMappingConfig { @Bean BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() { return new BeanNameUrlHandlerMapping(); } @Bean("/beanNameUrl") public WelcomeController welcome() { return new WelcomeController(); } }

이것은 위의 Java 기반 구성에 해당하는 XML입니다.

이 두 구성 모두에서 Spring MVC에서 제공하는 BeanNameUrlHandlerMapping에 대한 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 구현입니다. 빈 인스턴스와 URL 사이 또는 빈 이름과 URL 사이의 직접적이고 선언적인 매핑을 허용합니다.

"/ simpleUrlWelcome""/ * / simpleUrlWelcome"요청"welcome" 빈에 매핑 해 보겠습니다 .

@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 구성에서 "" 태그 간의 매핑은 java.util.Properties 클래스에서 허용하는 형식으로 수행 해야하며 구문은 path = Handler_Bean_Name을 따라야합니다 .

URL은 일반적으로 슬래시로 시작해야하지만 경로가 하나로 시작하지 않으면 Spring MVC에서 자동으로 추가합니다.

XML에서 위의 예를 구성하는 다른 방법 은 "value" 대신 "props" 속성 을 사용하는 것입니다 . 소품 의 목록이 "소품" 각을 정의 매핑 태그 "키" 매핑 된 URL에이라와 태그의 값이 빈의 이름입니다.

   welcome welcome   

다음 테스트 케이스는 "/ 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에서 제거됨)

The ControllerClassNameHandlerMapping maps URL to a registered controller bean (or a controller annotated with the @Controller annotation) that has, or starts with, the same name.

It can be more convenient in many scenarios especially for simple controller implementations that handle a single request type. The convention used by Spring MVC is to use the name of the class and remove the “Controller” suffix, then change the name to a lower case and return it as the mapping with a leading “/”.

For example “WelcomeController” would return as mapping to “/welcome*”, i.e. to any URL that starts with “welcome”.

Let's configure ControllerClassNameHandlerMapping:

@Configuration public class ControllerClassNameHandlerMappingConfig { @Bean public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() { return new ControllerClassNameHandlerMapping(); } @Bean public WelcomeController welcome() { return new WelcomeController(); } }

Note that ControllerClassNameHandlerMapping is deprecated from Spring 4.3 in favor of annotation driven handler methods.

Another important note is that controller names will always be returned in lowercase (minus the “Controller” suffix). So if we have a controller called “WelcomeBaeldungController“, it will only handle requests to “/welcomebaeldung” and not to “/welcomeBaeldung”.

In both Java config and XML config below, we define ControllerClassNameHandlerMapping bean and register beans for the controllers that we will use to handle requests. We also register a bean of type “WelcomeController” and that bean will handle all requests that start with “/welcome”.

Here's the equivalent XML configuration:

When using the above configuration, requests to “/welcome” will be handled by the “WelcomeController“.

The following code will make sure that requests to “/welcome*” such as “/welcometest” is handled by “WelcomeController” which returns a view name called “welcome“:

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

5. Configuring Priorities

Spring MVC framework allows more than one implementation of HandlerMapping interface at the same time.

Let us create a configuration and register two controllers, both mapped to URL “/welcome”, only using different mapping and returning different view names:

@Configuration public class HandlerMappingDefaultConfig { @Bean("/welcome") public BeanNameHandlerMappingController beanNameHandlerMapping() { return new BeanNameHandlerMappingController(); } @Bean public WelcomeController welcome() { return new WelcomeController(); } }

With no explicit handler mapper registered, a default BeanNameHandlerMapping will be used. Let us assert this behaviour with the test:

@Test public void whenConfiguringPriorities_thenMappedOK() { mockMvc.perform(get("/welcome")) .andExpect(status().isOk()) .andExpect(view().name("bean-name-handler-mapping")); } 

If we explicitly register a different handler mapper, the default mapper will be overridden. However, it is interesting to see what happens when two mappers are explicitly registered:

@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(); } }

To get the control over which mapping is used, the priorities are set using setOrder(int order) method. This method takes one int parameter where lower value mean higher priority.

In XML configuration you can configure priorities by using a property called “order”:

Let us add order properties to handler mapping beans, via following beanNameUrlHandlerMapping.setOrder(1) and simpleUrlHandlerMapping.setOrder(0). The lower value of the order property reflects higher precedence. Let us assert new behaviour with the test:

@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 뷰를 반환 하는 SimpleUrlHandlerMapping 빈에 의해 처리된다는 것을 알 수 있습니다. order 속성 의 값을 적절히 조정 하여 BeanNameHandlerMapping 이 우선 하도록 쉽게 구성 할 수 있습니다 .

6. 결론

이 기사에서는 프레임 워크의 다양한 구현을 탐색하여 Spring MVC 프레임 워크에서 URL 매핑을 처리하는 방법에 대해 설명했습니다.

이 기사와 함께 제공되는 코드는 GitHub에서 찾을 수 있습니다.