用 handler mapping 可以映射請求到合適的 handler ,比如用 SimpleUrlHandlerMapping 或者 BeanNameUrlHandlerMapping 。首先我們來(lái)看 handler mapping 這個(gè)概念。
最基本的 HandlerMapping 提供的功能是 HandlerExecutionchain 的傳遞,必須包括請求匹配的處理器,也可能包括一系列應用于這個(gè)請求的的攔截器。當請求發(fā)生時(shí), DispatcherServlet 將請求遞交給 hangler mapping, 讓其檢測請求并提出一個(gè)合適的 HandlerExecutionChain.DispatcherServlet 將執行該處理器和攔截器。
Handler mappings 對攔截器的配置是可選的,包括前,后執行或者前后都執行,功能很強大。很多已經(jīng)支持的功能可以在 HandlerMappings 配置中定制。選擇一個(gè)處理器的 handler mapping 定制不僅基于請求的 URL ,而且基于請求相關(guān)的 session 的狀態(tài)。
所有 handler mapping 類(lèi)都要繼承 AbstractHandlerMapping 。下面是共有的屬性。
Interceptors: 攔截器
defaultHandler: 默認的處理器,當沒(méi)有匹配的處理器時(shí)使用。
Order: 基于 order 屬性的值。
BeanNameUrlHandlerMapping 簡(jiǎn)單而強大,根據定義在 web 應用環(huán)境的 bean 的名字映射 http 請求。比如說(shuō)我們要讓一名用戶(hù)增加一賬號,我們已經(jīng)提供了合適的表單控制器, jsp 或者 velocity 視圖渲染表單。
如果使用 BeanNameUrlHandlerMapping, 請求 http://samples.com/editaccoutn.form. 配置如下: <beans>
- <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
- <bean name="/editaccount.form" class="org.springframework.web.servlet.mvc.SimpleFormController">
- <property name="formView" value="account"/>
- <property name="successView" value="account-created"/>
- <property name="commandName" value="account"/>
- <property name="commandClass" value="samples.Account"/>
- </bean>
- <beans>
所有請求的 url / editaccount.form 都會(huì )被 SimpleFormController 處理。當然在 web.xml 也要作如下的配置。
- <web-app>
- <servlet>
- <servlet-name>sample</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- maps the sample dispatcher to *.form -->
- <servlet-mapping>
- <servlet-name>sample</servlet-name>
- <url-pattern>*.form</url-pattern>
- </servlet-mapping>
- </web-app>
需要注意的是,你想用 BeanNameUrlHandlerMapping 是,并不需要定義。如果沒(méi)有定義處理類(lèi),則 DispatcherServlet 默認創(chuàng )建它。
SimpleUrlHandlerMapping 功能更強大。下面是例子
- <web-app>
- <servlet>
- <servlet-name>sample</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <!-- maps the sample dispatcher to *.form -->
- <servlet-mapping>
- <servlet-name>sample</servlet-name>
- <url-pattern>*.form</url-pattern>
- </servlet-mapping>
- <!-- maps the sample dispatcher to *.html -->
- <servlet-mapping>
- <servlet-name>sample</servlet-name>
- <url-pattern>*.html</url-pattern>
- </servlet-mapping>
- </web-app>
上面例子表示以 .form 或者 .html 結尾的請求都會(huì )被下面的處理器處理。
- <beans>
- <!-- no 'id' required, HandlerMapping beans are automatically detected by the DispatcherServlet -->
- <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
- <property name="mappings">
- <value>
- /*/account.form=editAccountFormController
- /*/editaccount.form=editAccountFormController
- /ex/view*.html=helpController
- /**/help.html=helpController
- </value>
- </property>
- </bean>
- <bean id="helpController"
- class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
- <bean id="editAccountFormController"
- class="org.springframework.web.servlet.mvc.SimpleFormController">
- <property name="formView" value="account"/>
- <property name="successView" value="account-created"/>
- <property name="commandName" value="Account"/>
- <property name="commandClass" value="samples.Account"/>
- </bean>
- <beans>
上面配置的意思很容易看明白的。
我們也可以用 HandlerInterceptor 攔截請求。攔截器必須實(shí)現 HandlerInterceptor 接口。這個(gè)接口定義了三個(gè)方法。見(jiàn)代碼:
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception;
- void postHandle(
- HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- throws Exception;
- void afterCompletion(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception;
上面三個(gè)方面分別負責預處理,后置處理和請求完成后的處理。下面是例子:
- <beans>
- <bean id="handlerMapping"
- class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
- <property name="interceptors">
- <list>
- <ref bean="officeHoursInterceptor"/>
- </list>
- </property>
- <property name="mappings">
- <value>
- /*.form=editAccountFormController
- /*.view=editAccountFormController
- </value>
- </property>
- </bean>
- <bean id="officeHoursInterceptor"
- class="samples.TimeBasedAccessInterceptor">
- <property name="openingTime" value="9"/>
- <property name="closingTime" value="18"/>
- </bean>
- <beans>
- 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 < closingTime) {
- return true;
- } else {
- response.sendRedirect("http://host.com/outsideOfficeHours.html");
- return false;
- }
- }
- }
我們看到,攔截器類(lèi)是繼承了 HandlerInterceptorAdapter ,而 HandlerInterceptorAdapter 基本實(shí)現了 HandlerInterceptor 接口,接下來(lái)就是我們根據需要改寫(xiě)上面的三個(gè)某些方法了,而不需要全部實(shí)現。