HandlerAdapters in Spring MVC – Spring MVC中的HandlerAdapters

最后修改: 2017年 1月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll focus on the various handler adapters implementations available in the Spring framework.

在这篇文章中,我们将重点介绍Spring框架中的各种处理程序适配器的实现。

2. What Is a Handleradapter?

2.什么是处理程序适配器?

The HandlerAdapter is basically an interface which facilitates the handling of HTTP requests in a very flexible manner in Spring MVC.

HandlerAdapter基本上是一个接口,它在Spring MVC中以非常灵活的方式促进了对HTTP请求的处理。

It’s used in conjunction with the HandlerMapping, which maps a method to a specific URL.

它与HandlerMapping一起使用,后者将一个方法映射到一个特定的URL。

The DispatcherServlet then uses a HandlerAdapter to invoke this method. The servlet doesn’t invoke the method directly – it basically serves as a bridge between itself and the handler objects, leading to a loosely coupling design.

DispatcherServlet然后使用HandlerAdapter来调用这个方法。Servlet并不直接调用该方法–它基本上充当了自己和处理程序对象之间的桥梁,从而导致了松散的耦合设计。

Let’s take a look at various methods available in this interface:

让我们来看看这个接口中的各种方法。

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

The supports API is used to check if a particular handler instance is supported or not. This method should be called first before calling the handle() method of this interface, in order to make sure whether the handler instance is supported or not.

supports API被用来检查某个处理程序实例是否被支持。在调用这个接口的handle()方法之前,应该先调用这个方法,以便确定处理程序实例是否被支持。

The handle API is used to handle a particular HTTP request. This method is responsible for invoking the handler by passing the HttpServletRequest and HttpServletResponse object as the parameter. The handler then executes the application logic and returns a ModelAndView object, which is then processed by the DispatcherServlet.

handle API被用来处理一个特定的HTTP请求。该方法负责通过传递HttpServletRequestHttpServletResponse对象作为参数来调用处理器。然后处理程序执行应用逻辑并返回一个ModelAndView对象,然后由DispatcherServlet处理。

3. Maven Dependency

3.Maven的依赖性

Let’s start with the Maven dependency that needs to be added to pom.xml:

我们先来看看需要添加到pom.xml的Maven依赖。

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

The latest version of the spring-webmvc artifact can be found here.

最新版本的spring-webmvc构件可以在这里找到。

4. Types of HandlerAdapter

4、HandlerAdapter的类型

4.1. SimpleControllerHandlerAdapter

4.1.SimpleControllerHandlerAdapter

This is the default handler adapter registered by Spring MVC. It deals with classes implementing Controller interface and is used to forward a request to a controller object.

这是由Spring MVC注册的默认处理适配器。它处理实现Controller接口的类,用于将请求转发给控制器对象。

If a web application uses only controllers then we don’t need to configure any HandlerAdapter as the framework uses this class as the default adapter for handling a request.

如果一个Web应用程序只使用控制器,那么我们不需要配置任何HandlerAdapter,因为框架使用这个类作为处理请求的默认适配器。

Let’s define a simple controller class, using the older style of controller (implementing the Controller interface):

让我们定义一个简单的控制器类,使用老式的控制器(实现Controller接口)。

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;
    }
}

The similar XML configuration:

类似的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>

The BeanNameUrlHandlerMapping class is the mapping class for this handler adapter.

BeanNameUrlHandlerMapping类是这个处理器适配器的映射类。

Note: If a custom handler adapter is defined in BeanFactory, then this adapter is not automatically registered. Thus, we need to define it explicitly in the context. If it is not defined and we have defined a custom handler adapter, then we will get an exception that says that no adapter for a handler is specified.

注意:如果在BeanFactory中定义了一个自定义处理程序适配器,那么这个适配器不会被自动注册。因此,我们需要在上下文中明确地定义它。如果它没有被定义,而我们已经定义了一个自定义的处理程序适配器,那么我们将得到一个异常,即没有指定处理程序的适配器。

4.2. SimpleServletHandlerAdapter

4.2. SimpleServletHandlerAdapter

This handler adapter allows the use of any Servlet to work with DispatcherServlet for handling the request. It forwards the request from DispatcherServlet to the appropriate Servlet class by calling its service() method.

这个处理适配器允许使用任何ServletDispatcherServlet合作来处理请求。它通过调用service() method,将请求从DispatcherServlet转发到适当的Servlet类。

The beans which implement the Servlet interface are automatically handled by this adapter. It is not registered by default and we need to register it like any other normal bean in the configuration file of DispatcherServlet:

实现Servlet接口的Bean会自动被这个适配器处理。它没有被默认注册,我们需要在DispatcherServlet的配置文件中像其他普通Bean一样注册它。

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

4.3. AnnotationMethodHandlerAdapter

4.3.AnnotationMethodHandlerAdapter

This adapter class is used to execute the methods that are annotated with @RequestMapping annotation. It is used to map the methods based on HTTP methods and HTTP paths.

这个适配器类用于执行被注解为@RequestMapping的方法。它被用来映射基于HTTP方法和HTTP路径的方法。

The mapping class for this adapter is DefaultAnnotationHandlerMapping, which is used to process the @RequestMapping annotation at the type level and AnnotationMethodHandlerAdaptor is used to process at a method level.

这个适配器的映射类是DefaultAnnotationHandlerMapping,用于在类型级别处理@RequestMapping注释,AnnotationMethodHandlerAdaptor用于在方法级别处理。

These two classes are already registered by the framework when the DispatcherServlet is initialized. However, if the other handler adapters are already defined, then we need to define it as well in the configuration file.

DispatcherServlet被初始化时,这两个类已经被框架注册了。然而,如果其他处理程序适配器已经被定义,那么我们也需要在配置文件中定义它。

Let’s define a controller class:

让我们来定义一个控制器类。

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

The @Controller annotation indicates that this class serves the role of controller.

@Controller注解表明该类起到了控制器的作用

The @RequestMapping annotation maps the getEmployeeName() method to the URL /name.

@RequestMapping 标注将getEmployeeName()方法映射到URL /name.

There are 2 different ways of configuring this adapter depending on whether the application uses Java-based configuration or XML based configuration. Let us look at the first way using Java configuration:

根据应用程序是使用基于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;
    }
}

If the application uses XML configuration, then there are two different approaches for configuring this handler adapter in web application context XML. Let us take a look at the first approach defined in the file spring-servlet_AnnotationMethodHandlerAdapter.xml:

如果应用程序使用XML配置,那么在Web应用程序上下文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>

The <context:component-scan /> tag is used to specify the package to scan for controller classes.

<context:component-scan />标签用于指定扫描controller类的包。

Let us take a look at the second approach:

让我们看一下第二种方法。

<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>

The <mvc:annotation-driven> tag will automatically register these two classes with spring MVC. This adapter was deprecated in Spring 3.2 and a new handler adapter called RequestMappingHandlerAdapter was introduced in Spring 3.1.

<mvc:annotation-driven>标签会自动将这两个类注册到spring MVC。这个适配器在Spring 3.2中被弃用,在Spring 3.1中引入了一个新的处理适配器,名为RequestMappingHandlerAdapter

4.4. RequestMappingHandlerAdapter

4.4.RequestMappingHandlerAdapter

This adapter class was introduced in Spring 3.1, deprecating the AnnotationMethodHandlerAdaptor handler adapter in Spring 3.2.

这个适配器类是在Spring 3.1中引入的,在Spring 3.2中废弃了AnnotationMethodHandlerAdaptorhandler适配器。

It’s used with RequestMappingHandlerMapping class, which executes methods annotated with @RequestMapping.

它与RequestMappingHandlerMapping类一起使用,后者执行带有@RequestMapping注释的方法。

The RequestMappingHandlerMapping is used to maintain the mapping of the request URI to the handler. Once the handler is obtained, the DispatcherServlet dispatches the request to the appropriate handler adapter, which then invokes the handlerMethod().

RequestMappingHandlerMapping用于维护请求URI与处理程序之间的映射。一旦获得处理程序,DispatcherServlet将请求分配给适当的处理程序适配器,然后调用handlerMethod()

The type-level and method-level mappings were processed in two different stages in the Spring version prior to 3.1.

在3.1之前的Spring版本中,类型级和方法级的映射在两个不同的阶段被处理。

The first stage was to select the controller by DefaultAnnotationHandlerMapping and the second stage was to invoke the actual method by AnnotationMethodHandlerAdapter.

第一阶段是通过DefaultAnnotationHandlerMapping选择控制器,第二阶段是通过AnnotationMethodHandlerAdapter调用实际方法。

From Spring version 3.1, there is only one stage, which involves identifying the controller as well as which method needs to be invoked to process the request.

从Spring 3.1版本开始,只有一个阶段,即识别控制器以及需要调用哪个方法来处理请求。

Let’s define a simple controller class:

让我们来定义一个简单的控制器类。

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

There are 2 different ways of configuring this adapter depending on whether the application uses Java-based configuration or XML based configuration.

根据应用程序是使用基于Java的配置还是基于XML的配置,有两种不同的方式来配置这个适配器。

Let’s look at the first way using Java configuration:

让我们来看看使用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;
    }
}

If the application uses XML configuration, then there are two different approaches for configuring this handler adapter in web application context XML. Let us take a look at the first approach defined in the file spring-servlet_RequestMappingHandlerAdapter.xml:

如果应用程序使用XML配置,那么在Web应用程序上下文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>

And here’s the second approach:

而这里是第二个方法。

<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>

This tag will automatically register these two classes with Spring MVC.

这个标签将自动向Spring MVC注册这两个类。

If we need to customize the RequestMappingHandlerMapping, then we need to remove this tag from the application context XML and manually configure it in the application context XML.

如果我们需要定制RequestMappingHandlerMapping,那么我们需要从应用上下文XML中删除这个标签,并在应用上下文XML中手动配置它。

4.5. HttpRequestHandlerAdapter

4.5.HttpRequestHandlerAdapter

This handler adapter is used for the handlers that process HttpRequests. It implements the HttpRequestHandler interface, which contains a single handleRequest() method for processing the request and generating the response.

这个处理程序适配器被用于处理HttpRequests的处理程序。它实现了HttpRequestHandler接口,其中包含一个处理请求和生成响应的handleRequest() 方法。

The return type of this method is void and it doesn’t generate ModelAndView return type as produced by other handler adapters. It’s basically used to generate binary responses and it doesn’t generate a view to render.

这个方法的返回类型是无效的,它不会像其他处理程序适配器所产生的那样产生ModelAndView返回类型。它基本上是用来生成二进制响应的,它并不生成一个视图来渲染。

5. Running the Application

5.运行应用程序

If the application is deployed on localhost with the port number 8082 and the context-root is spring-mvc-handlers:

如果应用程序被部署在localhost上,端口号为8082,并且context-root为spring-mvc-handlers

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

6. Conclusion

6.结论

In this article, we discussed various types of handler adapters available in Spring framework.

在这篇文章中,我们讨论了Spring框架中可用的各种类型的处理程序适配器。

Most developers will probably stick to the defaults, but it’s well worth understanding just how flexible the framework when we need to go beyond the basics.

大多数开发者可能会坚持使用默认值,但当我们需要超越基本功能时,非常值得了解该框架的灵活性。

The source code of this tutorial can be found in the GitHub project.

本教程的源代码可以在GitHub项目中找到。