Руководство по отображению Spring Handler
1. Вступление
В Spring MVCDispatcherServlet действует какfront controller - принимает все входящие HTTP-запросы и обрабатывает их.
Проще говоря, обработка происходит путем передачи запросов соответствующему компонентуwith the help of handler mappings.
HandlerMapping - это интерфейс, который определяет соответствие между запросами иhandler objects. В то время как Spring MVC Framework предоставляет некоторые готовые реализации, интерфейс может быть реализован разработчиками для обеспечения настраиваемой стратегии отображения.
В этой статье обсуждаются некоторые реализации, предоставляемые Spring MVC, а именноBeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,ControllerClassNameHandlerMapping, их конфигурация и различия между ними.
2. BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping - это реализацияHandlerMapping по умолчанию. BeanNameUrlHandlerMapping отображает URL-адреса запросов на одноименные компоненты.
Это конкретное сопоставление поддерживает прямое сопоставление имен, а также сопоставление с шаблоном с использованием шаблона «*».
Например, входящий URL“/foo” отображается на bean-компонент с именем“/foo”. Примером сопоставления шаблонов является сопоставление запросов к“/foo*” компонентам с именами, начинающимися с“/foo”, например“/foo2/” или“/fooOne/”.
Давайте настроим этот пример здесь и зарегистрируем bean-контроллер, который обрабатывает запросы к“/beanNameUrl”:
@Configuration
public class BeanNameUrlHandlerMappingConfig {
@Bean
BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
@Bean("/beanNameUrl")
public WelcomeController welcome() {
return new WelcomeController();
}
}
Это XML-эквивалент вышеупомянутой конфигурации на основе Java:
Важно отметить, что в обеих этих конфигурацияхdefining a bean for BeanNameUrlHandlerMapping is not required предоставляется Spring MVC. Удаление этого определения 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. Он допускает прямое и декларативное сопоставление между экземплярами и URL-адресами компонента или между именами и компонентами компонента.
Давайте сопоставим запросы“/simpleUrlWelcome” и“/*/simpleUrlWelcome” к bean-компоненту“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 сопоставление между тегом“<value>” должно выполняться в форме, принятой классомjava.util.Properties, и должно следовать синтаксису:path= Handler_Bean_Name.
URL-адрес обычно должен быть с косой чертой в начале, однако, если путь не начинается с единицы, Spring MVC добавляет его автоматически.
Другой способ настроить приведенный выше пример в XML - использовать свойство“props” вместо“value”. 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 (удалено весной 5)
ControllerClassNameHandlerMapping отображает URL-адрес зарегистрированного bean-компонента контроллера (или контроллера, помеченного аннотацией@Controller), который имеет или начинается с того же имени.
Это может быть более удобным во многих сценариях, особенно для простых реализаций контроллера, которые обрабатывают один тип запроса. Соглашение, используемое Spring MVC, заключается в использовании имени класса и удалении суффикса“Controller”, затем изменении имени на нижний регистр и возврате его как сопоставления с ведущим“/”.
Например,“WelcomeController” вернется как отображение на“/welcome*”, т.е. на любой URL-адрес, который начинается с“welcome”.
Настроим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 в пользу методов обработчиков, управляемых аннотациями.
Еще одно важное замечание: имена контроллеров всегда будут возвращаться в нижнем регистре (без суффикса «Controller»). Итак, если у нас есть контроллер с именем «WelcomeexampleController», он будет обрабатывать запросы только к“/welcomeexample”, а не к“/welcomeexample”.
Как в конфигурации Java, так и в конфигурации XML ниже мы определяем bean-компонентControllerClassNameHandlerMapping и регистрируем bean-компоненты для контроллеров, которые мы будем использовать для обработки запросов. Мы также регистрируем компонент типа“WelcomeController”, и этот компонент будет обрабатывать все запросы, начинающиеся с“/welcome”.
Вот эквивалентная конфигурация XML:
При использовании вышеуказанной конфигурации запросы к «/welcome» будут обрабатываться «WelcomeController».
Следующий код гарантирует, что запросы к «/welcome *», такие как «/welcometest», обрабатываются «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.
Давайте создадим конфигурацию и зарегистрируем два контроллера, оба сопоставленных с 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"));
}
Если мы явно зарегистрируем другой обработчик отображения, преобразователь по умолчанию будет переопределен. Тем не менее, интересно посмотреть, что происходит, когда два преобразователя явно зарегистрированы:
@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). Этот метод принимает один параметрint, где меньшее значение означает более высокий приоритет.
В конфигурации XML вы можете настроить приоритеты, используя свойство с именем“order”:
Давайте добавим свойстваorder к bean-компонентам отображения обработчика, следуя заbeanNameUrlHandlerMapping.setOrder(1) иsimpleUrlHandlerMapping.setOrder(0).. Меньшее значение свойстваorder отражает более высокий приоритет. Давайте утверждать новое поведение с тестом:
@Test
public void whenConfiguringPriorities_thenMappedOK() {
mockMvc.perform(get("/welcome"))
.andExpect(status().isOk())
.andExpect(view().name("simple-url-handler-mapping"));
}
При тестировании вышеуказанной конфигурации вы видите, что запросы к“/welcome” будут обрабатываться компонентомSimpleUrlHandlerMapping, который вызываетSimpleUrlHandlerController и возвращает представлениеsimple-url-handler-mapping. Мы можем легко настроитьBeanNameHandlerMapping на приоритет, соответствующим образом настроив значения свойстваorder.
6. Заключение
В этой статье мы обсудили, как URL-сопоставления обрабатываются в среде Spring MVC путем изучения различных реализаций в среде.
Код, сопровождающий эту статью, можно найтиover on GitHub.