背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置。我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Controller中的目标method方法对象。Controller和拦截器代码如下:

AdminController

@Controller
@RequestMapping("/admin")
public class AdminController { /**
* init:初始页面. <br/>
*
* @author chenzhou
* @param request 请求
* @param response 响应
* @return 登陆页
* @since JDK 1.6
*/
@RequestMapping("/init")
public ModelAndView init(HttpServletRequest request,
HttpServletResponse response){
Map<String, Object> model = new HashMap<String, Object>();
List<Role> roleList = this.adminService.getRoleList();
model.put("roleList", roleList);
return new ModelAndView(this.getLoginPage(), model);
} //……
}

LoginInterceptor

public class LoginInterceptor extends HandlerInterceptorAdapter {
/**
* This implementation always returns <code>true</code>.
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
} /**
* This implementation is empty.
*/
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
} /**
* This implementation is empty.
*/
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}

servlet xml配置文件定义:

<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>
</list>
</property>
</bean>

我的需求是想在preHandle方法中通过request获取该请求访问的目标Controller中的方法对象。之前找了很久也没有找到比较好的方案,就采取了最老土的通过比较requestURL和Controller类和方法上的RequestMappingURL来进行获取,这样也能勉强实现,但是这种方式我自己都觉得特别恶心。首先,这种方式需要使用反射来获取Controller中的所有方法,然后遍历method数组,逐个进行RequestMappingURL的比对,效率低下。其次,如果RequestMapping定义了类似于@RequestMapping("/{id}")这种动态参数url,则无法进行比较。

因为上面这种方式不好,我就一直想找一个更好的方案。不得已只能向人求助,第一个就想到了Iteye上对于Spring研究得很熟悉的jinnianshilongnian龙年兄,我相信经常上iteye的博友们对龙年兄应该都很熟悉。龙年兄给了我一个方案,就是通过把handler对象转换为HandlerMethod类型,然后直接getMethod,代码如下:

/**
* This implementation always returns <code>true</code>.
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("*********************preHandle********************");
System.out.println(handler.getClass());
HandlerMethod handlerMethod = (HandlerMethod) handler;
System.out.println(handlerMethod.getMethod());
return true;
}

注:HandlerMethod类是Spring 3.1.0.RELEASE版本中才有的,之前我使用的Spring 3.0.6.RELEASE版本,里面是找不到这个类的

根据龙年兄提供的方法,测试之后报错,报错信息如下:

*********************preHandle********************
class com.chenzhou.examples.erm.web.AdminController
-- :: org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet erm threw exception
java.lang.ClassCastException: com.chenzhou.examples.erm.web.AdminController cannot be cast to org.springframework.web.method.HandlerMethod
at com.chenzhou.examples.erm.util.interceptor.LoginInterceptor.preHandle(LoginInterceptor.java:)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:)
……

根据错误提示可以看出是HandlerMethod handlerMethod = (HandlerMethod) handler;这一步报错了,根据System.out.println(handler.getClass());打印的结果可以得知handler是该请求访问的Controller类,无法转换成HandlerMethod对象。这次还是龙年兄帮我找出了原因,解决方案是使用

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> 
替换 
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

因为DefaultAnnotationHandlerMapping只能返回Controller对象,不会映射到Controller中的方法级别。替换之后servlet xml配置如下:

<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>
</list>
</property>
</bean>

重启tomcat测试之后发现再次报错,报了另外一个错误,具体信息如下:

-- :: org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet erm threw exception
javax.servlet.ServletException: No adapter for handler [public org.springframework.web.servlet.ModelAndView com.chenzhou.examples.erm.web.AdminController.init(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]: Does your handler implement a supported interface like Controller?
……

这一次,请求根本没有到达拦截器容器就已经报错了,错误提示的意思是找不到handler对象对应的Adapter类。我在RequestMappingHandlerMapping类对应的spring-webmvc-3.1.0.RELEASE.jar 包里找到了该类对应的Adapter类:RequestMappingHandlerAdapter,然后在servlet xml中进行了配置:

<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

然后重新启动tomcat后访问http://localhost:8080/erm/admin/init 结果正常,控制台日志信息如下:

Shell代码

*********************preHandle********************
class org.springframework.web.method.HandlerMethod
public org.springframework.web.servlet.ModelAndView com.chenzhou.examples.erm.web.AdminController.init(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)

从日志信息可以看出,handler对象在经过类型转换后转换成了HandlerMethod类型,通过handler.getMethod方法,获取到了该请求访问的方法为com.chenzhou.examples.erm.web.AdminController.init

注:非常感谢jinnianshilongnian 开涛兄的帮助。

Spring拦截器中通过request获取到该请求对应Controller中的method对象的更多相关文章

  1. spring拦截器中修改响应消息头

    问题描述 前后端分离的项目,前端使用Vue,后端使用Spring MVC. 显然,需要解决浏览器跨域访问数据限制的问题,在此使用CROS协议解决. 由于该项目我在中期加入的,主要负责集成shiro框架 ...

  2. Spring 拦截器——HandlerInterceptor

    采用Spring拦截器的方式进行业务处理.HandlerInterceptor拦截器常见的用途有: 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2 ...

  3. spring 拦截器简介

    spring 拦截器简介 常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等.2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直 ...

  4. spring拦截器和注解处理日志操作

    整体思想:通过拦截器拦截所有的请求,处理含有自定义注解的方法,通过request得到需要的参数. 拦截器代码: package com.zktx.platform.log2; import java. ...

  5. Spring 拦截器实现+后台原理(HandlerInterceptor)

    过滤器跟拦截器的区别 spring mvc的拦截器是只拦截controller而不拦截jsp,html 页面文件的.这就用到过滤器filter了,filter是在servlet前执行的,你也可以理解成 ...

  6. Spring拦截器和过滤器

    什么是拦截器 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者 ...

  7. Spring拦截器总结

    本文是对慕课网上"搞定SSM开发"路径的系列课程的总结,详细的项目文档和课程总结放在github上了.点击查看 Spring过滤器WebFilter可以配置中文过滤 拦截器实现步骤 ...

  8. 过滤器 ;spring拦截器 切片 小结

    1. springMVc的拦截器 实现HandlerInterceptor接口,如下: public class HandlerInterceptor1 implements HandlerInter ...

  9. 如何实现 Https拦截进行 非常规“抓包” 珍惜Any 看雪学院 今天 前段时间在自己做开发的时候发现一个很好用的工具,OKHttp的拦截器(何为拦截器?就是在每次发送网络请求的时候都会走的一个回调)大概效果如下:

    如何实现 Https拦截进行 非常规“抓包” 珍惜Any 看雪学院 今天 前段时间在自己做开发的时候发现一个很好用的工具,OKHttp的拦截器(何为拦截器?就是在每次发送网络请求的时候都会走的一个回调 ...

随机推荐

  1. Delphi启动/停止Windows服务,启动类型修改为"自动"

    unit U_StartServices; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Contr ...

  2. 数据分析≠Hadoop+NoSQL

    数据分析≠Hadoop+NoSQL 目录(?)[+]           Hadoop让大数据分析走向了大众化,然而它的部署仍需耗费大量的人力和物力.在直奔Hadoop之前,是否已经将现有技术推向极限 ...

  3. 【Demo 0025】注册/反注册窗体类RegisterClassEx/UnregisterClass

    所有窗体在创建前都必须注册窗体类,只有注册的窗体类才被系统认知并允许实例化,换句话说通过注册告诉进程窗体管理器此类窗体的属性如: 背景色,窗体上的鼠标样式以及窗体事件处理函数等;  有一些控件类系统自 ...

  4. python模块学习---HTMLParser(解析HTML文档元素)

    HTMLParser是Python自带的模块,使用简单,能够很容易的实现HTML文件的分析. 本文主要简单讲一下HTMLParser的用法. 使用时需要定义一个从类HTMLParser继承的类,重定义 ...

  5. 清华申请退学博士作品:完全用Linux工作,凸Windows

    清华申请退学博士作品:完全用Linux工作 按尽管我们已经不习惯看长篇大论, 但我还是要说, 这是一篇值得你从头读到尾的长篇文章. 2005年9月22日,清华在读博士生王垠在水木社区BLOG上发表了& ...

  6. 一步一步重写 CodeIgniter 框架 (10) —— 使用 CodeIgniter 类库(续)

    上一节简单实现了 CI 的类库扩展模型,所以 _ci_load_class 和 _ci_init_class 写的不是很完备.根据上节课的分析,当 system/libraries 目录下存在 Ema ...

  7. Android SurfaceView实战 带你玩转flabby bird (下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43063331,本文出自:[张鸿洋的博客] 1.概述 在Android Surfa ...

  8. C/C++ 内存布局详解(经典)(很久前不知哪儿转载的)

    一个由C/C++编译的程序除了存放函数二进制代码的程序代码段(code段)外,数据占用的内存大致分为以下几个部分: 1.栈区(stack) 存放局部变量.函数参数.返回数据.返回地址等.系统自动分配释 ...

  9. BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )

    写了一个早上...就因为把长度为m的也算进去了... dp(i, j)表示准考证号前i个字符匹配了不吉利数字前j个的方案数. kmp预处理, 然后对于j进行枚举, 对数字0~9也枚举算出f(i, j) ...

  10. java--多线程之前台幕后

    前台程序是相对于后台程序来说的,那么什么是后台程序呢? [后台程序]就是在启动了start()之前,调用了setDaemon(true)方法,这个线程就变成了后台.如果一个进程中只用后台线程在运行,那 ...