SpringMVC Interceptor中通过Request获取Controller方法


刚好遇到这个问题,找到了大牛的博客学习记录一下

不是原创


背景:项目使用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配置如下:

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

*********************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 开涛兄的帮助。
感谢chenzhou123520的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值