来源:http://chenzhou123520.iteye.com/blog/1702563
背景:项目使用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);
- }
- //……
- }
@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 {
- }
- }
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>
<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;
- }
/** * 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)
- ……
*********************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>
<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?
- ……
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"/>
<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)
*********************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
相关推荐
spring mvc 拦截器获取请求数据信息 解压之后放到项目中 直接运行就可以了 (将流多次运用)
spring拦截器,高级参数绑定,controller返回值
springaop拦截controller日志
做一个简单的spring请求过滤,session存在显示,不存在自动跳转指定页面.
Spring Mvc AOP通过注解方式拦截controller等实现日志管理
AOP拦截器示例,告诉我们初学者理解aop,通过一个银行转帐说明问题。
spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截
假定两个Controller都在同一个工程中。 如果有比较合理的分层设计,这样的需求应该是非常...因为Controller B的实例中,Spring Boot为其进行配置和对象注入,这些准备工作不是简单通过实例化Controller B可以完成。
Spring AOP 拦截器 Advisor Spring AOP 拦截器 Advisor
常用拦截 拦截器HandlerInterceptor 拦截器MethodInterceptor 添加依赖 创建启动类 创建拦截器类 创建控制器 监控control请求耗时,提高性能
Spring MVC 拦截器Spring MVC 拦截器
NULL 博文链接:https://lpm528.iteye.com/blog/1259187
初学者很容易将 Spring MVC 拦截器 和 Spring Cloud OpenFeign 拦截器搞混,误以为OpenFeign拦截器就是SpringMVC拦截器:Spring MVC拦截器发生在客户端 和 服务端之间,在客户端向服务端发送请求时进行拦截处理。...
使用CGLIB编写的Spring的拦截器 非常使用的哦
NULL 博文链接:https://rogerhunt.iteye.com/blog/608778
spring boot jpa连接数据库,设置拦截器拦截指定路径下的文件。
idea软件。SpringBoot的拦截器的博客所写的例子。preHandle()方法的返回值true和false的详细区别还未描述
这一版本的项目中新增了拦截器的一个demo
自己spring boot 拦截器,可以自定义限制跳转路径及自定义不拦截哪些具体路径,具体设置可以看注释,一看就懂,引用哪些包已经包含了,不明白的请浏览,看到后第一时间给您回复