`
chenzhou123520
  • 浏览: 4249840 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

背景:项目使用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
2012-10-21 16:28:25 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:37)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:891)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
……

 

    根据错误提示可以看出是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测试之后发现再次报错,报了另外一个错误,具体信息如下:

 

2012-10-21 16:39:39 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 结果正常,控制台日志信息如下:

*********************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 开涛兄的帮助。

16
4
分享到:
评论
22 楼 hvang1988 2016-09-26  
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
A BeanDefinitionParser that provides the configuration for the <annotation-driven/> MVC namespace element. 

This class registers the following HandlerMappings:

RequestMappingHandlerMapping ordered at 0 for mapping requests to annotated controller methods. 
BeanNameUrlHandlerMapping ordered at 2 to map URL paths to controller bean names. 


意思是AnnotationDrivenBeanDefinitionParser类对<annotation-driven/>配置进行 解析,
解析注册两个类,其中一个是RequestMappingHandlerMapping

所以只需要配置<mvc:annotation-driven/>即启用了RequestMappingHandlerMapping基于方法级别的拦截
21 楼 wojiaowangtao 2016-04-28  
不错,感谢楼主分享
20 楼 zx19924311 2015-12-11  
加入<mvc:annotation-driven /> 就OK 了 楼主太麻烦了

然后:

<mvc:interceptors> 
        <mvc:interceptor>
        <mvc:mapping path="/**"/>
            <bean class="com.xxx.xxx.xxx.Interceptor"/> 
        </mvc:interceptor> 
</mvc:interceptors>
19 楼 kjj 2014-07-28  
very good
18 楼 279704390 2014-07-18  
为什么由RequestMappingHandlerMapping替换DefaultAnnotationHandlerMapping后,页面就无法访问了呢?404
请楼主帮忙分析
17 楼 qingbo921 2014-04-29  
大力推荐<mvc:interceptors> ,不用那么麻烦~
16 楼 qq466862016 2014-04-17  
qq466862016 写道
3.0  没有对应的 handlerMethod 类  ,具体解决办法请参考我的博客

三个拦截器处理三个注解搞定基于注解的权限控制,适用性比较通用于Springmvc web项目
15 楼 qq466862016 2014-04-17  
3.0  没有对应的 handlerMethod 类  ,具体解决办法请参考我的博客
14 楼 clean1981 2013-05-03  
请问我加了@ResponseBody后为什么拦截器要出错。。报的异常是不支持的MEDIATYPE异常,请问现在该怎么办?我已经加了
<bean id="jsonHttpMessageConverter"
		class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<value>text/html;charset=UTF-8</value>
				<value>text/plain;charset=UTF-8</value>
				<value>application/json; charset=UTF-8</value>
				<value>application/x-www-form-urlencoded; charset=UTF-8</value>
			</list>
		</property>
	</bean>
但还是没用
13 楼 magichorse 2013-04-23  
其实springMVC的配置可以这么写
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.chenzhou.examples.erm.util.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

其中path可以修改一下,改成你需要的地址就行。
12 楼 jy02405651 2013-03-21  
不错···解决了我的问题
11 楼 chenzhou123520 2013-03-19  
ka520 写道
楼主,你这样处理,是不是就是为了解决,SPRING AOP不能针对CONTROLLER生效的问题,求回复!

也可以这么说吧,当时是为了做权限控制发现aop对Controller不生效,后来就采用了拦截器的方式。
10 楼 ka520 2013-03-19  
楼主,你这样处理,是不是就是为了解决,SPRING AOP不能针对CONTROLLER生效的问题,求回复!
9 楼 chenzhou123520 2013-01-15  
dj080808 写道
谢谢lz,我google了好久

不客气
8 楼 dj080808 2013-01-15  
谢谢lz,我google了好久
7 楼 chenzhou123520 2013-01-07  
gufen 写道
感谢楼主无私分享,google了好久了。

谢谢鼓励
6 楼 gufen 2013-01-07  
感谢楼主无私分享,google了好久了。
5 楼 chenzhou123520 2012-10-22  
mzh200801 写道
楼主的这种分享方式真心不错,分享知识,也是一种艺术。
这种方式的分享让人受益很大。

谢谢鼓励!
4 楼 mzh200801 2012-10-22  
楼主的这种分享方式真心不错,分享知识,也是一种艺术。
这种方式的分享让人受益很大。
3 楼 onlylau 2012-10-22  
onlylau 写道
针对springmvc3.0版本AnnotationMethodHandlerAdapter
可以试下下面方法:
Class handlerClass = ClassUtils.getUserClass(handler);
ServletHandlerMethodResolver resolver = new ServletHandlerMethodResolver(handlerClass);
Method handlerMethod = methodResolver.resolveHandlerMethod(request);

呵呵,抱歉没注意到ServletHandlerMethodResolver是一个内部私有类

相关推荐

Global site tag (gtag.js) - Google Analytics