18.4处理程序映射

在以前的Spring版本中,用户需要HandlerMapping在Web应用程序上下文中定义一个或多个 bean,以将传入的Web请求映射到适当的处理程序。通过引入注释控制器,您通常不需要这样做,因为它RequestMappingHandlerMapping@RequestMapping自动在所有@Controllerbean 上查找 注释。但是,请记住,所有HandlerMapping扩展的类AbstractHandlerMapping都具有以下可用于自定义行为的属性:

  • interceptors要使用的拦截器列表。HandlerInterceptor第18.4.1节“使用HandlerInterceptor拦截请求”中讨论
  • defaultHandler当这个处理程序映射不会导致一个匹配的处理程序时,使用默认处理程序。
  • order基于order属性的值(参见org.springframework.core.Ordered接口),Spring会排序上下文中可用的所有处理程序映射,并应用第一个匹配处理程序。
  • alwaysUseFullPath如果trueSpring使用当前Servlet上下文中的完整路径来找到一个适当的处理程序。如果false(默认值),则使用当前Servlet映射中的路径。例如,如果使用Servlet/testing/*并将alwaysUseFullPath属性设置为true,/testing/viewPage.html则使用该属性,而如果该属性设置为false/viewPage.html
  • urlDecode默认为true,从Spring 2.5开始。如果您喜欢比较编码路径,请将此标志设置为false。但是,HttpServletRequest始终以解码形式公开Servlet路径。请注意,与编码路径相比,Servlet路径将不匹配。

以下示例显示如何配置拦截器:

  1. <beans>
  2. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
  3. <property name="interceptors">
  4. <bean class="example.MyInterceptor"/>
  5. </property>
  6. </bean>
  7. </beans>

18.4.1用HandlerInterceptor拦截请求

Spring的处理程序映射机制包括处理程序拦截器,当您希望将特定功能应用于某些请求时,例如,检查主体,这是有用的。

位于处理程序映射中的拦截器必须HandlerInterceptororg.springframework.web.servlet包中实现。这个接口定义了三个方法:preHandle(..)被称为被执行的实际处理程序;postHandle(..)被称为执行的处理程序; 并在完成请求完成后afterCompletion(..)调用。这三种方法应提供足够的灵活性进行各种预处理和后处理。

preHandle(..)方法返回一个布尔值。您可以使用此方法来中断或继续处理执行链。当此方法返回true时,处理程序执行链将继续; 当它返回false时,DispatcherServlet假定拦截器本身已经处理了请求(并且例如呈现适当的视图),并且不会继续执行其他拦截器和执行链中的实际处理程序。

拦截器可以使用interceptors属性进行配置,该属性存在于所有HandlerMapping类中AbstractHandlerMapping。这在下面的示例中显示:

  1. <beans>
  2. <bean id="handlerMapping"
  3. class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
  4. <property name="interceptors">
  5. <list>
  6. <ref bean="officeHoursInterceptor"/>
  7. </list>
  8. </property>
  9. </bean>
  10. <bean id="officeHoursInterceptor"
  11. class="samples.TimeBasedAccessInterceptor">
  12. <property name="openingTime" value="9"/>
  13. <property name="closingTime" value="18"/>
  14. </bean>
  15. </beans>
  1. package samples;
  2. public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
  3. private int openingTime;
  4. private int closingTime;
  5. public void setOpeningTime(int openingTime) {
  6. this.openingTime = openingTime;
  7. }
  8. public void setClosingTime(int closingTime) {
  9. this.closingTime = closingTime;
  10. }
  11. public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  12. Object handler) throws Exception {
  13. Calendar cal = Calendar.getInstance();
  14. int hour = cal.get(HOUR_OF_DAY);
  15. if (openingTime <= hour && hour < closingTime) {
  16. return true;
  17. }
  18. response.sendRedirect("http://host.com/outsideOfficeHours.html");
  19. return false;
  20. }
  21. }

该映射处理的任何请求都被截取TimeBasedAccessInterceptor。如果当前时间在办公时间之外,用户将被重定向到静态HTML文件,例如,您只能在办公时间内访问该网站。

当使用RequestMappingHandlerMapping实际处理程序时,HandlerMethod它的一个实例 标识将被调用的特定控制器方法。

您可以看到,Spring适配器类HandlerInterceptorAdapter可以更容易地扩展HandlerInterceptor接口。

在上面的示例中,配置的拦截器将应用于使用注释控制器方法处理的所有请求。如果要缩小拦截器应用的URL路径,可以使用MVC命名空间或MVC Java配置,或声明类型的bean实例MappedInterceptor。请参见第18.16.1节“启用MVC Java配置或MVC XML命名空间”

请注意,该postHandle方法HandlerInterceptor并不总是非常适用于@ResponseBodyResponseEntity方法。在这种情况下HttpMessageConverter,在postHandle调用之前写入并提交响应,这使得不可能更改响应,例如添加标题。相反,应用程序可以实现ResponseBodyAdvice并将其声明为@ControllerAdvicebean或直接配置它RequestMappingHandlerAdapter