Перейти к основному содержимому

HandlerAdapters в Spring MVC

· 7 мин. чтения

Задача: Медиана двух отсортированных массивов

Даны два отсортированных массива размерами n и m. Найдите медиану слияния этих двух массивов.
Временная сложность решения должна быть O(log(m + n)) ...

ANDROMEDA

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. Симплконтроллерхандлерадаптер

Это адаптер обработчика по умолчанию, зарегистрированный 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.foreach.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. АннотацияМетодHandlerAdapter

Этот класс адаптера используется для выполнения методов, помеченных аннотацией @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.foreach.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.foreach.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>

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

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

<beans ...>
<mvc:annotation-driven/>
<context:component-scan base-package="com.foreach.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>

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

4.4. Рекестмаппингхандлерадаптер

Этот класс адаптера был введен в 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.foreach.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.foreach.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.foreach.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

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

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

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

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

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

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

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

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

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