18.4处理程序映射
在以前的Spring版本中,用户需要HandlerMapping
在Web应用程序上下文中定义一个或多个 bean,以将传入的Web请求映射到适当的处理程序。通过引入注释控制器,您通常不需要这样做,因为它RequestMappingHandlerMapping
会@RequestMapping
自动在所有@Controller
bean 上查找 注释。但是,请记住,所有HandlerMapping
扩展的类AbstractHandlerMapping
都具有以下可用于自定义行为的属性:
interceptors
要使用的拦截器列表。HandlerInterceptor
在第18.4.1节“使用HandlerInterceptor拦截请求”中讨论。defaultHandler
当这个处理程序映射不会导致一个匹配的处理程序时,使用默认处理程序。order
基于order属性的值(参见org.springframework.core.Ordered
接口),Spring会排序上下文中可用的所有处理程序映射,并应用第一个匹配处理程序。alwaysUseFullPath
如果true
Spring使用当前Servlet上下文中的完整路径来找到一个适当的处理程序。如果false
(默认值),则使用当前Servlet映射中的路径。例如,如果使用Servlet/testing/*
并将alwaysUseFullPath
属性设置为true,/testing/viewPage.html
则使用该属性,而如果该属性设置为false/viewPage.html
。urlDecode
默认为true
,从Spring 2.5开始。如果您喜欢比较编码路径,请将此标志设置为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>
18.4.1用HandlerInterceptor拦截请求
Spring的处理程序映射机制包括处理程序拦截器,当您希望将特定功能应用于某些请求时,例如,检查主体,这是有用的。
位于处理程序映射中的拦截器必须HandlerInterceptor
从org.springframework.web.servlet
包中实现。这个接口定义了三个方法:preHandle(..)
被称为前被执行的实际处理程序;postHandle(..)
被称为后执行的处理程序; 并在完成请求完成后afterCompletion(..)
调用。这三种方法应提供足够的灵活性进行各种预处理和后处理。
该preHandle(..)
方法返回一个布尔值。您可以使用此方法来中断或继续处理执行链。当此方法返回true
时,处理程序执行链将继续; 当它返回false时,DispatcherServlet
假定拦截器本身已经处理了请求(并且例如呈现适当的视图),并且不会继续执行其他拦截器和执行链中的实际处理程序。
拦截器可以使用interceptors
属性进行配置,该属性存在于所有HandlerMapping
类中AbstractHandlerMapping
。这在下面的示例中显示:
<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>
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;
}
}
该映射处理的任何请求都被截取TimeBasedAccessInterceptor。如果当前时间在办公时间之外,用户将被重定向到静态HTML文件,例如,您只能在办公时间内访问该网站。
当使用RequestMappingHandlerMapping实际处理程序时,HandlerMethod它的一个实例 标识将被调用的特定控制器方法。
您可以看到,Spring适配器类HandlerInterceptorAdapter可以更容易地扩展HandlerInterceptor接口。
在上面的示例中,配置的拦截器将应用于使用注释控制器方法处理的所有请求。如果要缩小拦截器应用的URL路径,可以使用MVC命名空间或MVC Java配置,或声明类型的bean实例
MappedInterceptor
。请参见第18.16.1节“启用MVC Java配置或MVC XML命名空间”。
请注意,该postHandle
方法HandlerInterceptor
并不总是非常适用于@ResponseBody
和ResponseEntity
方法。在这种情况下HttpMessageConverter
,在postHandle
调用之前写入并提交响应,这使得不可能更改响应,例如添加标题。相反,应用程序可以实现ResponseBodyAdvice
并将其声明为@ControllerAdvice
bean或直接配置它RequestMappingHandlerAdapter
。