«1. Введение
В Spring MVC DispatcherServlet действует как передний контроллер — получает все входящие HTTP-запросы и обрабатывает их.
Проще говоря, обработка происходит путем передачи запросов соответствующему компоненту с помощью сопоставлений обработчиков.
HandlerMapping — это интерфейс, определяющий сопоставление между запросами и объектами обработчика. В то время как среда Spring MVC предоставляет некоторые готовые реализации, интерфейс может быть реализован разработчиками для обеспечения индивидуальной стратегии сопоставления.
В этой статье обсуждаются некоторые реализации, предоставляемые Spring MVC, а именно BeanNameUrlHandlerMapping, SimpleUrlHandlerMapping, ControllerClassNameHandlerMapping, их конфигурация и различия между ними.
2. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping — это реализация HandlerMapping по умолчанию. BeanNameUrlHandlerMapping сопоставляет URL-адреса запроса с bean-компонентами с тем же именем.
Это конкретное сопоставление поддерживает прямое сопоставление имен, а также сопоставление с шаблоном с использованием шаблона «*».
Например, входящий URL-адрес «/foo» сопоставляется с bean-компонентом с именем «/foo». Примером сопоставления шаблонов является сопоставление запросов к «/foo*» бинам с именами, начинающимися с «/foo», например «/foo2/» или «/fooOne/».
Давайте настроим этот пример здесь и зарегистрируем контроллер компонента, который обрабатывает запросы к «/beanNameUrl»:
@Configuration
public class BeanNameUrlHandlerMappingConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
@Bean("/beanNameUrl")
public WelcomeController welcome() {
return new WelcomeController();
}
}
Это XML-эквивалент приведенной выше конфигурации на основе Java:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean name="/beanNameUrl" class="com.baeldung.WelcomeController" />
Это важно отметить, что в обеих этих конфигурациях определение bean-компонента для BeanNameUrlHandlerMapping не требуется, поскольку оно предоставляется Spring MVC. Удаление этого определения bean-компонента не вызовет проблем, и запросы по-прежнему будут сопоставляться с их зарегистрированными bean-компонентами-обработчиками.
Теперь все запросы к «/beanNameUrl» будут перенаправлены DispatcherServlet на «WelcomeController». WelcomeController возвращает имя представления, которое называется «добро пожаловать».
Следующий код проверяет эту конфигурацию и убеждается, что возвращается правильное имя представления:
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» с bean-компонентом «welcome»:
@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 сопоставление между тегом «\u003cvalue\u003e» должно быть выполнено в форме, принятой классом java.util.Properties, и должно соответствовать синтаксису: path= Handler_Bean_Name.
Обычно URL-адрес должен начинаться с косой черты, однако, если путь не начинается с косой черты, Spring MVC добавляет ее автоматически.
Другой способ настроить приведенный выше пример в XML — использовать свойство «props» вместо «value». У свойств есть список тегов «prop», каждый из которых определяет сопоставление, где «ключ» относится к сопоставленному URL-адресу, а значением тега является имя компонента.
<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» обрабатываются «WelcomeController», который возвращает представление с именем «welcome»:
public class SimpleUrlMappingConfigTest {
// ...
@Test
public void whenSimpleUrlMapping_thenMappedOK() {
mockMvc.perform(get("/simpleUrlWelcome"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
4. ControllerClassNameHandlerMapping (удален in Spring 5)
ControllerClassNameHandlerMapping сопоставляет URL-адрес с зарегистрированным bean-компонентом контроллера (или контроллером, аннотированным аннотацией @Controller), который имеет или начинается с того же имени.
Это может быть удобнее во многих сценариях, особенно для простых реализаций контроллера, обрабатывающих один тип запроса. Соглашение, используемое Spring MVC, состоит в том, чтобы использовать имя класса и удалить суффикс «Контроллер», затем изменить имя на нижний регистр и вернуть его как сопоставление с ведущим «/».
Например, «WelcomeController» вернется как сопоставление с «/welcome*», то есть с любым URL-адресом, начинающимся с «welcome».
Давайте настроим ControllerClassNameHandlerMapping:
@Configuration
public class ControllerClassNameHandlerMappingConfig {
@Bean
public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
return new ControllerClassNameHandlerMapping();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
«
«Обратите внимание, что ControllerClassNameHandlerMapping устарел из Spring 4.3 в пользу методов обработчика, управляемых аннотациями.
Еще одно важное замечание: имена контроллеров всегда будут возвращаться в нижнем регистре (без суффикса «Контроллер»). Итак, если у нас есть контроллер с именем «WelcomeBaeldungController», он будет обрабатывать запросы только к «/welcomeBaeldung», а не к «/welcomeBaeldung».
Как в конфигурации Java, так и в конфигурации XML ниже мы определяем bean-компонент ControllerClassNameHandlerMapping и регистрируем bean-компоненты для контроллеров, которые мы будем использовать для обработки запросов. Мы также регистрируем bean-компонент типа «WelcomeController», и этот bean-компонент будет обрабатывать все запросы, начинающиеся с «/welcome».
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.baeldung.WelcomeController" />
Вот эквивалентная конфигурация XML:
При использовании приведенной выше конфигурации запросы к «/welcome» будут обрабатываться «WelcomeController».
public class ControllerClassNameHandlerMappingTest {
// ...
@Test
public void whenControllerClassNameMapping_thenMappedOK() {
mockMvc.perform(get("/welcometest"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"));
}
}
Следующий код гарантирует, что запросы к «/welcome*», такие как «/welcometest», обрабатываются «WelcomeController», который возвращает имя представления «welcome»:
5. Настройка приоритетов
Среда Spring MVC позволяет использовать более одной реализации интерфейса HandlerMapping одновременно.
@Configuration
public class HandlerMappingDefaultConfig {
@Bean("/welcome")
public BeanNameHandlerMappingController beanNameHandlerMapping() {
return new BeanNameHandlerMappingController();
}
@Bean
public WelcomeController welcome() {
return new WelcomeController();
}
}
Давайте создадим конфигурацию и зарегистрируем два контроллера, оба сопоставлены с URL-адресом «/welcome», только используя разные сопоставления и возвращая разные имена представлений: будет использоваться. Давайте проверим это поведение с помощью теста:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("bean-name-handler-mapping"));
}
Если мы явно зарегистрируем другой преобразователь обработчика, преобразователь по умолчанию будет переопределен. Однако интересно посмотреть, что происходит, когда явно зарегистрированы два модуля отображения:
@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). Этот метод принимает один целочисленный параметр, где более низкое значение означает более высокий приоритет.
В конфигурации XML вы можете настроить приоритеты, используя свойство под названием «порядок»:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="order" value="2" />
</bean>
Давайте добавим свойства порядка к bean-компонентам сопоставления обработчиков, используя следующие beanNameUrlHandlerMapping.setOrder(1) и simpleUrlHandlerMapping.setOrder(0 ). Меньшее значение свойства порядка отражает более высокий приоритет. Давайте проверим новое поведение с помощью теста:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("simple-url-handler-mapping"));
}
При тестировании приведенной выше конфигурации вы видите, что запросы к «/welcome» будут обрабатываться bean-компонентом SimpleUrlHandlerMapping, который вызывает SimpleUrlHandlerController и возвращает simple-url-handler- картографический вид. Мы можем легко настроить BeanNameHandlerMapping так, чтобы он имел приоритет, соответствующим образом изменив значения свойства order.
6. Заключение
В этой статье мы обсудили, как сопоставление URL-адресов обрабатывается в среде Spring MVC, исследуя различные реализации в среде.
Код, сопровождающий эту статью, можно найти на GitHub.