Руководство по отображению Spring Handler

Руководство по отображению 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.