基于注解风格的Spring-MVC的拦截器
Spring-MVC如何使用拦截器,官方文档只给出了非注解风格的例子。那么基于注解风格如何使用拦截器呢?
基于注解基本上有2个可使用的定义类,分别是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter:
<bean?class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
1、DefaultAnnotationHandlerMapping
?????? DefaultAnnotationHandlerMapping本身支持自定义拦截器,只需按如下进行配置:
2?????<property?name="interceptors">
3?????????<list>
4????????????????<bean?class="packageName.XXXInterceptor"?/>
5?????????</list>
6?????</property>
7?</bean>
Interceptor的定义为:
?2?????@Override
?3?????public?boolean?preHandle(HttpServletRequest?req,?HttpServletResponse?resp,?Object?handler)?{
?4??
?5?????????String?className?=?handler.getClass().getName();// packageName.ClassName
?6?????????if?(Error)?{
?7?????????????return false;
?8?????????}
?9?????????return true;
10?????}
11?}
2、AnnotationMethodHandlerAdapter
?????? 目前,笔者没找到如何给AnnotationMethodHandlerAdapter配置自定义Interceptor的方法,但是有个customArgumentResolver可以利用一下,来充当Interceptor。
2?????<property?name="customArgumentResolver">
3?????????<bean?class="packageName.XXXResolver"/>
4?????</property>
5?</bean>
Resolver的定义为:
?2??
?3?????@Override
?4?????public?Object?resolveArgument(MethodParameter?methodParameter,?NativeWebRequest?webRequest)?throws?Exception?{
?5??
?6?????????String?className?=?methodParameter.getMethod().getDeclaringClass().getName();//?packageName.ClassName
?7?
?8?????????//?如何取得Response和Request
?9?????????HttpServletResponse?resp?=?(HttpServletResponse)?webRequest.getNativeResponse();
10??????? HttpServletRequest?req?=?(HttpServletRequest)?webRequest.getNativeRequest();
11??
12??????? if?(Error)?{
13??????????? if (!resp.isCommitted()) resp.sendError(ERROR_STATUS);
14??????? }
15??????? return?UNRESOLVED;????
16?????}
17?}
18?
????? 仔细的人会看出,第二种方法其实根本不是拦截。其实第二种只是在映射Controller,调用方法的时候,给每一个方法的参数增加了一个切点。
上例在出错的时候往HttpServletResponse写错误状态,来通知web容器进行错误重定向,达到了拦截器的作用。
这么做有一个缺点,就是每个参数都有自己的切点,比如方法有3个参数就会调3次resolveArgument。为了避免出错,需要判断一下resp.isCommitted。
????? customArgumentResolver的初衷不是用来做Interceptor的,但有些环境却不得不使用它,比如部署在GAE上。
GAE是不支持DefaultAnnotationHandlerMapping的,因为此类用到了org.springframework.beans.BeanUtils.findEditorByConvention,这个方法会调用java.lang.ClassLoader.getSystemClassLoader,而这正是GAE所不允许的。
PS:
文中提到软件的版本:
spring - 2.5.X