天天看點

SpringMVC(8) - 處理器映射

參考: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上配置它。

繼續閱讀