Spring拦截器中通过request获取到该请求对应Controller中的method对象

转载 2015年08月20日 23:33:34

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

 

AdminController

 

Java代码  收藏代码
  1. @Controller  
  2. @RequestMapping("/admin")  
  3. public class AdminController {  
  4.   
  5.     /** 
  6.      * init:初始页面. <br/> 
  7.      * 
  8.      * @author chenzhou 
  9.      * @param request 请求 
  10.      * @param response 响应 
  11.      * @return 登陆页 
  12.      * @since JDK 1.6 
  13.      */  
  14.     @RequestMapping("/init")  
  15.     public ModelAndView init(HttpServletRequest request,  
  16.             HttpServletResponse response){  
  17.         Map<String, Object> model = new HashMap<String, Object>();  
  18.         List<Role> roleList = this.adminService.getRoleList();  
  19.         model.put("roleList", roleList);  
  20.         return new ModelAndView(this.getLoginPage(), model);  
  21.     }  
  22.   
  23.     //……  
  24. }  
 

 

LoginInterceptor

 

Java代码  收藏代码
  1. public class LoginInterceptor extends HandlerInterceptorAdapter {  
  2.     /** 
  3.      * This implementation always returns <code>true</code>. 
  4.      */  
  5.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  6.         throws Exception {  
  7.         return true;  
  8.     }  
  9.   
  10.     /** 
  11.      * This implementation is empty. 
  12.      */  
  13.     public void postHandle(  
  14.             HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
  15.             throws Exception {  
  16.     }  
  17.   
  18.     /** 
  19.      * This implementation is empty. 
  20.      */  
  21.     public void afterCompletion(  
  22.             HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
  23.             throws Exception {  
  24.     }  
  25. }  

 

servlet xml配置文件定义:

Xml代码  收藏代码
  1. <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />   
  2. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>  
  3. <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  
  4.     <property name="interceptors">  
  5.         <list>  
  6.             <bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>  
  7.         </list>  
  8.     </property>  
  9. </bean>    

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

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

 

Java代码  收藏代码
  1. /** 
  2.  * This implementation always returns <code>true</code>. 
  3.  */  
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  5.     throws Exception {  
  6.     System.out.println("*********************preHandle********************");  
  7.     System.out.println(handler.getClass());  
  8.     HandlerMethod handlerMethod = (HandlerMethod) handler;  
  9.     System.out.println(handlerMethod.getMethod());  
  10.     return true;  
  11. }  

 

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

 

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

 

Shell代码  收藏代码
  1. *********************preHandle********************  
  2. class com.chenzhou.examples.erm.web.AdminController  
  3. 2012-10-21 16:28:25 org.apache.catalina.core.StandardWrapperValve invoke  
  4. 严重: Servlet.service() for servlet erm threw exception  
  5. java.lang.ClassCastException: com.chenzhou.examples.erm.web.AdminController cannot be cast to org.springframework.web.method.HandlerMethod  
  6.     at com.chenzhou.examples.erm.util.interceptor.LoginInterceptor.preHandle(LoginInterceptor.java:37)  
  7.     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:891)  
  8.     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)  
  9.     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)  
  10.     at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)  
  11.     at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)  
  12.     at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  
  13. ……  

 

    根据错误提示可以看出是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配置如下:

 

Xml代码  收藏代码
  1. <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />   
  2. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>  
  3. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">   
  4.     <property name="interceptors">  
  5.         <list>  
  6.             <bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>  
  7.         </list>  
  8.     </property>  
  9. </bean>  

 

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

 

Shell代码  收藏代码
  1. 2012-10-21 16:39:39 org.apache.catalina.core.StandardWrapperValve invoke  
  2. 严重: Servlet.service() for servlet erm threw exception  
  3. 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?  
  4. ……  

 

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

 

Xml代码  收藏代码
  1. <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />   
  2. <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>  
  3. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">   
  4.     <property name="interceptors">  
  5.         <list>  
  6.             <bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"/>  
  7.         </list>  
  8.     </property>  
  9. </bean>  
  10. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>  

 

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

Shell代码  收藏代码
  1. *********************preHandle********************  
  2. class org.springframework.web.method.HandlerMethod  
  3. 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 开涛兄的帮助。

拦截器中读取request中的流后,controller 无法获取到数据解决方案

一般我们会在InterceptorAdapter拦截器中对请求的token进行验证 如果是content-type 是 application/x-www-form-urlencoded  则没...
  • Heng_Ji
  • Heng_Ji
  • 2017年02月06日 15:18
  • 4241

利用SpringMVC拦截器控制Controller返回值

背景:需求是在Controller中方法没有实现时,返回模拟结果。主要用于项目初期前台跟后台的交互,Web项目就是在前台发出请求然后后台响应并返回结果。本示例利用拦截器和注解实现跳过执行方法直接返回定...
  • jaune161
  • jaune161
  • 2014年09月28日 11:54
  • 39388

handler method 参数绑定常用的注解详解

引言: 接上一篇文章,对@RequestMapping进行地址映射讲解之后,该篇主要讲解request 数据到handler method 参数数据的绑定所用到的注解和什么情形下使用; 简...
  • qq_36040184
  • qq_36040184
  • 2017年03月17日 21:24
  • 682

@RequestBody的正确使用方法

最近在接收一个要离职同事的工作,接手的项目是用SpringBoot搭建的,其中看到了这样的写法: @RequestMapping("doThis") public String do...
  • li954644351
  • li954644351
  • 2016年04月15日 11:53
  • 65482

Spring中 interceptor 获取方法级对象

背景:在拦截器中,对Controller中的方法级注解判断,控制用户访问权限 实现: mvc-servlet.xml中配置拦截器...
  • leely5001
  • leely5001
  • 2015年05月08日 20:31
  • 1403

Spring-boot 配置Aop获取controller里的request中的参数以及其返回值

首先在你的Maven的pom文件里加入aop的依赖: org.springframework.boot spring-boot-starter-aop 在spring ...
  • jiaobuchong
  • jiaobuchong
  • 2015年12月28日 17:41
  • 22786

SpringMVC里拦截器preHandle里的参数究竟是什么意思

今天我的create和update老是报错:create接口: @RequestMapping(value = "/oftenTraveller/create", method = {RequestM...
  • bbbbln
  • bbbbln
  • 2016年11月20日 13:56
  • 7396

restful服务端无法获取post参数的解决方法

使用spring + cxf 搭建的restful webservice,在接收post请求参数时,我使用如下方法来解析: public class InMessageInterceptor ext...
  • u012799221
  • u012799221
  • 2016年11月10日 15:14
  • 2239

Spring Boot实现一个监听用户请求的拦截器

项目中需要监听用户具体的请求操作,便通过一个拦截器来监听,并继续相应的日志记录 项目构建与Spring Boot,Spring Boot实现一个拦截器很容易...
  • canot
  • canot
  • 2016年10月12日 12:43
  • 4243

解决spring设置filter过滤器结合rest风格获取post请求body参数输入流问题

由于最近在使用spring+jersey开发要设置基于servlet的filter。当在filter中通过request.getReader或者getInputStream读取body中的json参数...
  • xianSky2015
  • xianSky2015
  • 2016年07月24日 14:22
  • 9959
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring拦截器中通过request获取到该请求对应Controller中的method对象
举报原因:
原因补充:

(最多只允许输入30个字)