參考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#mvc-handlermapping
在以前的Spring版本中,使用者需要在Web應用程式上下文中定義一個或多個HandlerMapping bean,以将傳入的Web請求映射到适當的處理器。通過引入帶注解的控制器,就不需要像之前那樣定義了,因為RequestMappingHandlerMapping會自動在所有@Controller bean上查找@RequestMapping注解。但是,請記住,從AbstractHandlerMapping擴充的所有HandlerMapping類都具有以下可用于自定義其行為的屬性:
- 攔截器:使用的攔截器清單
- defaultHandler:當此處理器映射未找到比對的處理器時使用的預設處理器。
- order:基于order屬性的值(參考org.springframework.core.Ordered接口),Spring對上下文中可用的所有處理程式映射進行排序,并應用第一個比對的處理器。
- alwaysUseFullPath:如果為true,則Spring使用目前Servlet上下文中的完整路徑來查找适當的處理器序。如果為false(預設值),則使用目前Servlet映射中的路徑。例如,如果使用 /testing/* 映射Servlet并且将alwaysUseFullPath屬性設定為true,則使用 /testing/viewPage.html,而如果該屬性設定為false,則使用/viewPage.html。
- urlDecode:從Spring 2.5開始,預設為true。如果希望比較編碼路徑,将此标志設定為false。但是,HttpServletRequest始終以解碼形式暴露Servlet路徑。請注意,Servlet路徑與編碼路徑相比是不比對的。
以下示例顯示如何配置攔截器:
<beans>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<bean class="example.MyInterceptor"/>
</property>
</bean>
<beans>
1. 使用HandlerInterceptor攔截請求
Spring的處理器映射機制包括處理器攔截器,當想要将特定功能應用于某些請求(例如,檢查認證資訊)時,它們很有用。
位于處理器映射中的攔截器必須從org.springframework.web.servlet.HandlerInterceptor。該接口定義了三種方法,這三種方法應該提供足夠的靈活性來進行各種預處理和後處理,方法如下:
- 在執行實際處理程式之前調用preHandle(..)
- 執行處理程式後調用postHandle(..)
- 完成請求完成後調用afterCompletion(..)
preHandle(..)方法傳回一個布爾值。可以使用此方法來中斷或繼續執行鍊的處理。當此方法傳回true時,處理程式執行鍊将繼續;當它傳回false時,DispatcherServlet假定攔截器本身已處理請求(例如,呈現了适當的視圖),并且不繼續執行執行鍊中的其他攔截器和實際處理器。
可以使用interceptors屬性配置攔截器,該屬性存在于從AbstractHandlerMapping擴充的所有HandlerMapping類中。示例:
<beans>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="officeHoursInterceptor"/>
</list>
</property>
</bean>
<bean id="officeHoursInterceptor" class="samples.TimeBasedAccessInterceptor">
<property name="openingTime" value="9"/>
<property name="closingTime" value="18"/>
</bean>
</beans>
TimeBasedAccessInterceptor攔截此映射處理的任何請求。如果目前時間不在辦公時間,則會将使用者重定向到靜态HTML檔案,例如,隻能在辦公時間通路該網站。
package samples;
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
Calendar cal = Calendar.getInstance();
int hour = cal.get(HOUR_OF_DAY);
if (openingTime <= hour && hour < closingTime) {
return true;
}
response.sendRedirect("http://host.com/outsideOfficeHours.html");
return false;
}
}
注:使用RequestMappingHandlerMapping時,實際的處理器是HandlerMethod的一個執行個體,它辨別将被調用的特定控制器方法。
如上例,Spring擴充卡類HandlerInterceptorAdapter使擴充HandlerInterceptor接口變得更容易。
提示:在上面的示例中,配置的攔截器将應用于使用帶注解的控制器方法處理的所有請求。如果要縮小攔截器應用的URL路徑,可以使用MVC命名空間或MVC Java配置,或者聲明類型為MappedInterceptor的bean執行個體來執行此操作。
請注意,HandlerInterceptor的postHandle方法并不總是非常适合與@ResponseBody和ResponseEntity方法一起使用。在這種情況下,HttpMessageConverter在調用postHandle之前寫入并送出響應,這使得無法更改響應,例如添加響應頭。相反,應用程式可以實作ResponseBodyAdvice并将其聲明為@ControllerAdvice bean或直接在RequestMappingHandlerAdapter上配置它。