Spring MVC中的HandlerAdapter

2023/05/19

1. 概述

在本文中,我们重点介绍Spring框架中可用的各种HandlerAdapter实现。

2. 什么是HandlerAdapter

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

它与HandlerMapping结合使用,HandlerMapping将方法映射到特定的URL。

然后DispatcherServlet使用HandlerAdapter调用此方法,servlet并不直接调用该方法,它基本上充当自身与处理程序对象之间的桥梁,实现松耦合设计。

让我们看看这个接口中可用的一些方法:

public interface HandlerAdapter {
    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

support方法用于检查是否支持特定的处理程序实例。在调用该接口的handle()方法之前,应首先调用此方法,以确保是否支持处理程序实例。

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

3. Maven依赖

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

4. HandlerAdapter类型

4.1 SimpleControllerHandlerAdapter

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

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

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

public class SimpleControllerHandlerAdapterExample implements Controller {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView model = new ModelAndView("Greeting");
        model.addObject("message", "Dinesh Madhwal");
        return model;
    }
}

类似的XML配置如下:

<!-- @formatter:off -->
<beans ...>
    <bean name="/greeting.html" class="cn.tuyucheng.taketoday.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>
<!-- @formatter:on -->

BeanNameUrlHandlerMapping类是此处理程序适配器的映射类。

注意:如果在BeanFactory中定义了自定义处理程序适配器,则不会自动注册该适配器。 因此,我们需要在上下文中明确定义它。如果没有定义它并且我们已经定义了一个自定义处理程序适配器,那么我们将得到一个异常,表示没有为处理程序指定适配器。

4.2 SimpleServletHandlerAdapter

此处理程序适配器允许使用任何Servlet与DispatcherServlet一起处理请求。 它通过调用其service()方法,将请求从DispatcherServlet转发到适当的Servlet类。

实现Servlet接口的bean由该适配器自动处理。默认情况下,它没有注册,我们需要像其他普通bean一样在DispatcherServlet的配置文件中注册它:

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

4.3 AnnotationMethodHandlerAdapter

这个适配器类用于执行带有@RequestMapping注解的方法,它用于根据HTTP请求方法和HTTP路径映射方法。

此适配器的映射类为DefaultAnnotationHandlerMapping,它用于在类级别处理@RequestMapping注解,AnnotationMethodHandlerAdaptor用于在方法级别进行处理。

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

让我们定义一个控制器类:

@Controller
public class AnnotationMethodHandlerAdapterExample {

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

@Controller注解表明该类充当控制器的角色。

@RequestMapping注解将getEmployeeName()方法映射到URL “/annotedName”。

根据应用程序是使用基于Java的配置还是基于XML的配置,有2种不同的方式来配置此适配器,让我们看看使用Java配置的第一种方式:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"cn.tuyucheng.taketoday.spring.controller"})
public class ApplicationConfiguration implements WebMvcConfigurer {

    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/");
        bean.setSuffix(".jsp");
        return bean;
    }
}

如果应用程序使用XML配置,那么在Web应用程序上下文XML中配置此处理程序适配器有两种不同的方法。 让我们看一下spring-servlet_AnnotationMethodHandlerAdapter.xml文件中定义的第一种方法:

<!-- @formatter:off -->
<beans ...>
    <context:component-scan base-package="cn.tuyucheng.taketoday.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>
<!-- @formatter:on -->

<context:component-scan>标签用于指定要扫描控制器类的包。

下面是第二种方法:

<!-- @formatter:off -->
<beans ...>
    <mvc:annotation-driven/>
    <context:component-scan base-package="cn.tuyucheng.taketoday.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>
<!-- @formatter:on -->

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

4.4 RequestMappingHandlerAdapter

这个适配器类是在Spring 3.1中引入的,在Spring 3.2中弃用了AnnotationMethodHandlerAdaptor处理程序适配器。

它与RequestMappingHandlerMapping类一起使用,该类执行使用@RequestMapping注解标注的方法

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

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

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

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

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

@Controller
public class RequestMappingHandlerAdapterExample {

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

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

让我们看一下使用Java配置的第一种方法:

@ComponentScan("cn.tuyucheng.taketoday.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配置,那么在Web应用程序上下文XML中配置此处理程序适配器有两种不同的方法。 让我们看一下spring-servlet_RequestMappingHandlerAdapter.xml文件中定义的第一种方法:

<!-- @formatter:off -->
<beans ...>
    <context:component-scan base-package="cn.tuyucheng.taketoday.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>
<!-- @formatter:on -->

下面是第二种方法:

<!-- @formatter:off -->
<beans ...>
    <mvc:annotation-driven />
    
    <context:component-scan base-package="cn.tuyucheng.taketoday.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>
<!-- @formatter:on -->

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

如果我们需要自定义RequestMappingHandlerMapping,那么我们需要从应用上下文XML中去掉这个标签,并在应用程序上下文XML中手动配置它。

4.5 HttpRequestHandlerAdapter

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

此方法的返回类型为void,它不会返回其他处理程序适配器生成的ModelAndView返回类型。 基本上它用于生成二进制响应,并且不会生成要渲染的视图。

5. 总结

在本文中,我们介绍了Spring框架中可用的各种类型的处理程序适配器。

使用默认配置对于我们来说是足够的,但是当我们需要理解基础知识时,了解框架的灵活性是非常有必要的。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章