1. 概述
本文將重點介紹 Spring 框架中可用的各種 Handler Adapter 實現。
2. 什麼是 HandlerAdapter?
HandlerAdapter 基本上是一個接口,它以一種靈活的方式在 Spring MVC 中促進 HTTP 請求的處理。
它與HandlerMapping 配合使用,HandlerMapping 將方法映射到特定的 URL。
DispatcherServlet 然後使用HandlerAdapter 調用該方法。 servlet 不直接調用該方法——它基本上充當其與 handler 對象之間的橋樑,從而實現鬆耦合設計。
下面是此接口中可用的各種方法:
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() 方法之前,應首先調用此方法,以確保處理器實例是否被支持。
handle API 用於處理特定 HTTP 請求。 此方法負責通過將 HttpServletRequest 和 HttpServletResponse 對象作為參數來調用處理器。 處理器執行應用程序邏輯並返回 ModelAndView 對象,然後由 DispatcherServlet 處理。
3. Maven 依賴
讓我們從需要添加到 pom.xml 中的 Maven 依賴開始:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.5</version>
</dependency>最新版本的 spring-webmvc 構件可以在 這裏 找到。
4. HandlerAdapter 的類型
4.1. <em>SimpleControllerHandlerAdapter</em>
這是 Spring MVC 默認註冊的 handler 適配器。它處理實現 <em>Controller</em> 接口的類,並用於將請求轉發到控制器對象。
如果 Web 應用程序僅使用控制器,則我們不需要配置 <em>HandlerAdapter</em>,因為框架將此類作為處理請求的默認適配器。
讓我們定義一個簡單的控制器類,使用舊風格的控制器(實現 <em>Controller</em> 接口):
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. <em lang="en">SimpleServletHandlerAdapter</em>
此 Handler 適配器允許使用任何 <em lang="en">Servlet</em> 與 <em lang="en">DispatcherServlet</em> 協作,處理請求。它通過調用其 <em lang="en">service()</em> 方法,將請求從 <em lang="en">DispatcherServlet</em> 轉發到相應的 <em lang="en">Servlet</em> 類。
該適配器會自動處理實現 <em lang="en">Servlet</em> 接口的 Bean。默認情況下,它未註冊,因此需要在 <em lang="en">DispatcherServlet</em> 的配置文件中像任何其他普通 Bean 那樣進行註冊:
<bean name="simpleServletHandlerAdapter"
class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter" />4.3. `AnnotationMethodHandlerAdapter</h3
此適配器類用於執行帶有 @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。
根據應用程序是否使用基於Java的配置或基於XML的配置,有2種不同的配置方式。下面我們來看使用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 配置,則配置此處理程序適配器在 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><context:component-scan /> 標籤用於指定掃描 控制器類所在的包。
我們來看一下第二種方法:
<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><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()。
在 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;
}
}可以通過以下兩種方式配置此適配器,具體取決於應用程序是否使用基於 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 配置,則配置此 HandlerAdapter 的方法有兩種,分別在 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>以下是第二個方法:
<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
這個適配器用於處理 HttpRequest 的處理器。它實現了 HttpRequestHandler 接口,其中包含一個 handleRequest() 方法,用於處理請求並生成響應。
該方法的返回值類型為 void,它不生成像其他適配器那樣產生的 ModelAndView 返回類型。它主要用於生成二進制響應,並且不生成視圖進行渲染。
5. 運行應用程序
如果應用程序部署在 localhost 上,端口號為 8082,並且上下文根為 spring-mvc-handlers,則:
http://localhost:8082/spring-mvc-handlers/6. 結論
在本文中,我們討論了 Spring 框架中可用的各種 HandlerAdapter 類型。
大多數開發者可能會堅持使用默認設置,但瞭解框架的靈活性對於超出基本功能的需求來説,絕對值得學習。