«1. Обзор

В этой статье мы сосредоточимся на различных реализациях адаптеров обработчиков, доступных в среде Spring.

2. Что такое Handleradapter?

HandlerAdapter — это, по сути, интерфейс, который очень гибко облегчает обработку HTTP-запросов в Spring MVC.

Он используется в сочетании с HandlerMapping, который сопоставляет метод с определенным URL-адресом.

Затем DispatcherServlet использует HandlerAdapter для вызова этого метода. Сервлет не вызывает метод напрямую — он в основном служит мостом между собой и объектами обработчика, что приводит к слабосвязанной конструкции.

Давайте рассмотрим различные методы, доступные в этом интерфейсе:

public interface HandlerAdapter {
    boolean supports(Object handler);
    
    ModelAndView handle(
      HttpServletRequest request,
      HttpServletResponse response, 
      Object handler) throws Exception;
    
    long getLastModified(HttpServletRequest request, Object handler);
}

API поддержки используется для проверки того, поддерживается ли конкретный экземпляр обработчика. Этот метод следует вызывать первым перед вызовом метода handle() этого интерфейса, чтобы убедиться, поддерживается ли экземпляр обработчика или нет.

API дескриптора используется для обработки определенного HTTP-запроса. Этот метод отвечает за вызов обработчика путем передачи объекта HttpServletRequest и HttpServletResponse в качестве параметра. Затем обработчик выполняет логику приложения и возвращает объект ModelAndView, который затем обрабатывается DispatcherServlet.

3. Зависимость Maven

Начнем с зависимости Maven, которую нужно добавить в pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

Последнюю версию артефакта spring-webmvc можно найти здесь.

4. Типы HandlerAdapter

4.1. SimpleControllerHandlerAdapter

Это адаптер обработчика по умолчанию, зарегистрированный Spring MVC. Он имеет дело с классами, реализующими интерфейс контроллера, и используется для пересылки запроса объекту контроллера.

Если веб-приложение использует только контроллеры, нам не нужно настраивать HandlerAdapter, поскольку фреймворк использует этот класс в качестве адаптера по умолчанию для обработки запроса.

Давайте определим простой класс контроллера, используя старый стиль контроллера (реализующий интерфейс контроллера):

public class SimpleController implements Controller {
    @Override
    public ModelAndView handleRequest(
      HttpServletRequest request, 
      HttpServletResponse response) throws Exception {
        
        ModelAndView model = new ModelAndView("Greeting");
        model.addObject("message", "Dinesh Madhwal");
        return model;
    }
}

Аналогичная конфигурация XML:

<beans ...>
    <bean name="/greeting.html"
      class="com.baeldung.spring.controller.SimpleControllerHandlerAdapterExample"/>
    <bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Класс BeanNameUrlHandlerMapping является классом сопоставления для этого обработчика. адаптер.

Примечание. Если в BeanFactory определен пользовательский адаптер-обработчик, этот адаптер не регистрируется автоматически. Таким образом, нам нужно определить его явно в контексте. Если он не определен и мы определили пользовательский адаптер обработчика, то мы получим исключение, говорящее о том, что адаптер для обработчика не указан.

4.2. SimpleServletHandlerAdapter

Этот адаптер обработчика позволяет использовать любой сервлет для работы с DispatcherServlet для обработки запроса. Он перенаправляет запрос от DispatcherServlet в соответствующий класс Servlet, вызывая его метод service().

Bean-компоненты, реализующие интерфейс Servlet, автоматически обрабатываются этим адаптером. Он не зарегистрирован по умолчанию, и нам нужно зарегистрировать его, как и любой другой обычный компонент, в файле конфигурации DispatcherServlet:

<bean name="simpleServletHandlerAdapter" 
  class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter" />

4.3. AnnotationMethodHandlerAdapter

Этот класс адаптера используется для выполнения методов, помеченных аннотацией @RequestMapping. Он используется для сопоставления методов на основе методов HTTP и путей HTTP.

Классом сопоставления для этого адаптера является DefaultAnnotationHandlerMapping, который используется для обработки аннотации @RequestMapping на уровне типа, а AnnotationMethodHandlerAdaptor используется для обработки на уровне метода.

Эти два класса уже зарегистрированы фреймворком при инициализации DispatcherServlet. Однако, если другие адаптеры обработчика уже определены, нам также необходимо определить их в файле конфигурации.

Определим класс контроллера:

@Controller
public class AnnotationHandler {
    @RequestMapping("/annotedName")
    public ModelAndView getEmployeeName() {
        ModelAndView model = new ModelAndView("Greeting");        
        model.addObject("message", "Dinesh");       
        return model;  
    }  
}

Аннотация @Controller указывает, что этот класс выполняет роль контроллера.

Аннотация @RequestMapping сопоставляет метод getEmployeeName() с URL-адресом /name.

«Существует 2 различных способа настройки этого адаптера в зависимости от того, использует ли приложение конфигурацию на основе Java или конфигурацию на основе XML. Давайте рассмотрим первый способ с использованием конфигурации Java:

@ComponentScan("com.baeldung.spring.controller")
@Configuration
@EnableWebMvc
public class ApplicationConfiguration implements WebMvcConfigurer {
    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/");
        bean.setSuffix(".jsp");
        return bean;
    }
}

Если приложение использует конфигурацию XML, то существует два различных подхода к настройке этого адаптера обработчика в контексте XML веб-приложения. Давайте взглянем на первый подход, определенный в файле spring-servlet_AnnotationMethodHandlerAdapter.xml:

<beans ...>
    <context:component-scan base-package="com.baeldung.spring.controller" />
    <bean 
      class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    <bean 
      class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Тег \u003ccontext:component-scan /\u003e используется для указания пакета для сканирования классов контроллера.

Давайте рассмотрим второй подход:

<beans ...>
    <mvc:annotation-driven/>
    <context:component-scan base-package="com.baeldung.spring.controller" />
    <bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Тег \u003cmvc:annotation-driven\u003e автоматически зарегистрирует эти два класса в Spring MVC. Этот адаптер устарел в Spring 3.2, а в Spring 3.1 был представлен новый адаптер-обработчик RequestMappingHandlerAdapter.

4.4. RequestMappingHandlerAdapter

Этот класс адаптера был введен в Spring 3.1, а адаптер-обработчик AnnotationMethodHandlerAdaptor в Spring 3.2 объявлен устаревшим.

Используется с классом RequestMappingHandlerMapping, который выполняет методы, аннотированные @RequestMapping.

RequestMappingHandlerMapping используется для поддержки сопоставления URI запроса с обработчиком. Как только обработчик получен, DispatcherServlet отправляет запрос соответствующему адаптеру обработчика, который затем вызывает метод handlerMethod().

Сопоставления уровня типа и уровня метода обрабатывались в два разных этапа в версии Spring до 3.1.

Первым этапом был выбор контроллера с помощью DefaultAnnotationHandlerMapping, а вторым этапом был вызов фактического метода с помощью AnnotationMethodHandlerAdapter.

Начиная с версии Spring 3.1 существует только один этап, который включает в себя идентификацию контроллера, а также метод, который необходимо вызвать для обработки запроса.

Давайте определим простой класс контроллера:

@Controller
public class RequestMappingHandler {
    
    @RequestMapping("/requestName")
    public ModelAndView getEmployeeName() {
        ModelAndView model = new ModelAndView("Greeting");        
        model.addObject("message", "Madhwal");        
        return model;  
    }  
}

Существует 2 разных способа настройки этого адаптера в зависимости от того, использует ли приложение конфигурацию на основе Java или конфигурацию на основе XML.

Давайте рассмотрим первый способ с использованием конфигурации Java:

@ComponentScan("com.baeldung.spring.controller")
@Configuration
@EnableWebMvc
public class ServletConfig implements WebMvcConfigurer {
    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/");
        bean.setSuffix(".jsp");
        return bean;
    }
}

Если приложение использует конфигурацию XML, то существует два различных подхода к настройке этого адаптера обработчика в контексте XML веб-приложения. Давайте взглянем на первый подход, определенный в файле spring-servlet_RequestMappingHandlerAdapter.xml:

<beans ...>
    <context:component-scan base-package="com.baeldung.spring.controller" />
    
    <bean 
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    
    <bean
      class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    
    <bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

И вот второй подход:

<beans ...>
    <mvc:annotation-driven />
    
    <context:component-scan base-package="com.baeldung.spring.controller" />
    
    <bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Этот тег автоматически зарегистрирует эти два класса в Spring MVC.

Если нам нужно настроить RequestMappingHandlerMapping, нам нужно удалить этот тег из XML контекста приложения и вручную настроить его в XML контекста приложения.

4.5. HttpRequestHandlerAdapter

Этот адаптер обработчика используется для обработчиков, обрабатывающих HttpRequests. Он реализует интерфейс HttpRequestHandler, который содержит единственный метод handleRequest() для обработки запроса и генерации ответа.

Тип возвращаемого значения этого метода — void, и он не генерирует тип возвращаемого значения ModelAndView, который создается другими адаптерами-обработчиками. В основном он используется для генерации двоичных ответов и не создает представление для рендеринга.

5. Запуск приложения

Если приложение развернуто на локальном хосте с номером порта 8082 и корневым контекстом является spring-mvc-handlers:

http://localhost:8082/spring-mvc-handlers/

6. Заключение

В этой статье , мы обсудили различные типы адаптеров обработчиков, доступных в среде Spring.

Большинство разработчиков, вероятно, будут придерживаться значений по умолчанию, но стоит понять, насколько гибка инфраструктура, когда нам нужно выйти за рамки основ.

Исходный код этого руководства можно найти в проекте GitHub.