通过处理器映射,你可以将web请求映射到正确的处理器(handler)上。Spring内置了很多处理器映射策略,例如:SimpleUrlHandlerMapping
或者BeanNameUrlHandlerMapping
。现在我们先来看一下HandlerMapping
的基本概念。
HandlerMapping
的基本功能是将请求传递到HandlerExecutionChain
上。首先,这个HandlerExecutionChain
必须包含一个能处理该请求的处理器。其次,这个链也可以包含一系列可以拦截请求的拦截器。当收到请求时,DispatcherServlet
将请求交给处理器映射,让它检查请求并找到一个适当的HandlerExecutionChain
。然后,DispatcherServlet
执行定义在链中的处理器和拦截器(interceptor)。
在处理器映射中通过配置拦截器(包括处理器执行前、执行后、或者执行前后运行拦截器)将使其功能更强大。同时也可以通过自定义HandlerMapping
来支持更多的功能。比如,一个自定义的处理器映射不仅可以根据请求的URL,而且还可以根据和请求相关的session状态来选择处理器。
下面我们将讲述Spring中最常用的两个处理器映射。它们都是AbstractHandlerMapping
的子类,同时继承了下面这些属性:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping
是一个简单但很强大的处理器映射,它将收到的HTTP请求映射到bean的名字上(这些bean需要在web应用上下文中定义)。例如,为了实现一个用户新建账号的功能,我们提供了FormController (关于CommandController和FormController请参考第 13.3.4 节 “命令控制器”)和显示表单的JSP视图(或Velocity模版)。当使用BeanNameUrlHandlerMapping
时,我们用如下方式将包含http://samples.com/editaccount.form
的访问请求映射到指定的FormController上:
< 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 >
所有对/editaccount.form
的请求就会由上面的FormController处理。当然我们得在web.xml
中定义servlet-mapping,接受所有以.form
结尾的请求。
<
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
>
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
<!--
maps the sample dispatcher to *.form
-->
<
servlet-mapping
>
<
servlet-name
>
sample
</
servlet-name
>
<
url-pattern
>
*.form
</
url-pattern
>
</
servlet-mapping
>
...
</
web-app
>
注意
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
要使用BeanNameUrlHandlerMapping
,无须(如上所示)在web应用上下文中定义它。缺省情况下,如果在上下文中没有找到处理器映射,DispatcherServlet
会为你创建一个BeanNameUrlHandlerMapping
!
另一个更强大的处理器映射是SimpleUrlHandlerMapping
。它在应用上下文中可以进行配置,并且有Ant风格的路径匹配功能。(请参考org.springframework.util.PathMatcher
的JavaDoc)。下面几个例子可以帮助理解:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
The above web.xml
configuration snippet enables all requests ending with .html and .form
to be handled by the sample dispatcher servlet.
上面的web.xml设置允许所有以.html
和.form
结尾的请求都由这个sample DispatcherServlet
处理。
< 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 >
这个处理器映射首先将对所有目录中文件名为help.html
的请求传递给helpController
。 helpController
是一个UrlFilenameViewController
(要了解更多关于控制器的信息,请参阅 第 13.3 节 “控制器”)。对ex
目录中所有以view
开始,以.html
结尾的请求都会被传递给helpController
。 同样的,我们也为editAccountFormController
定义了两个映射。
Spring的处理器映射支持拦截器。当你想要为某些请求提供特殊功能时,例如对用户进行身份认证,这就非常有用。
处理器映射中的拦截器必须实现org.springframework.web.servlet
包中的HandlerInterceptor
接口。这个接口定义了三个方法,一个在处理器执行前被调用,一个在处理器执行后被调用,另一个在整个请求处理完后调用。这三个方法提供你足够的灵活度做任何处理前后的操作。
preHandle(..)
方法有一个boolean返回值。使用这个值,你可以调整执行链的行为。当返回true
时,处理器执行链将继续执行,当返回false
时,DispatcherServlet
认为该拦截器已经处理完了请求(比如显示正确的视图),而不继续执行执行链中的其它拦截器和处理器。
下面的例子提供了一个拦截器,它拦截所有请求,如果当前时间不是在上午9点到下午6点,它将用户重定向到某个页面。
< 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;
}
}
}
所有的请求都将被TimeBasedAccessInterceptor
截获,如果当前时间不在上班时间,用户会被重定向到一个静态html页面,提供诸如只有上班时间才能访问网站之类的告示。
Spring还提供了一个adapter类HandlerInterceptorAdapter
让用户更方便的扩展HandlerInterceptor
接口。