码迷,mamicode.com
首页 > 编程语言 > 详细

Spring MVC的拦截器

时间:2016-08-14 13:11:49      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

什么是拦截器?

拦截器是指通过统一拦截从浏览器发送到服务器的请求来完成我们对功能的增强。

Java过滤器跟SpringMVC的拦截器有什么不同?

定义:拦截器是可以拦截我们配置的方法,并且在我们的方法请求前后去做一些处理,比如做字符编码,验证校验等。

而过滤器:是在javaweb中,你传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符.。 

实现方式:

拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
其它具体区别:
1.配置方式的不同;
2.执行顺序的不同,过滤器根据filter mapping配置的先后顺序,而拦截器按照配置的顺序,但是可以通过order控制顺序。
3.规范;过滤器是在Servlet规范中定义的,是Servlet容器支持的,拦截器是基于spring框架实现的,受spring容器管理。
4.使用范围:过滤器只能对action方法起作用,而拦截器 几乎对所有方法起作用。
拦截器的实现
Interceptor拦截器主要有两种实现方式,一种是实现Spring 的HandlerInterceptor 接口,另外一种是继承实现了Spring 的HandlerInterceptor 接口的类。

常见应用场景

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;

3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

实现HandlerInterceptor接口

 HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

 这里我们来看一下源码:

/**
	 * Intercept the execution of a handler. Called after HandlerMapping determined
	 * an appropriate handler object, but before HandlerAdapter invokes the handler.
	 * <p>DispatcherServlet processes a handler in an execution chain, consisting
	 * of any number of interceptors, with the handler itself at the end.
	 * With this method, each interceptor can decide to abort the execution chain,
	 * typically sending a HTTP error or writing a custom response.
	 * <p><strong>Note:</strong> special considerations apply for asynchronous
	 * request processing. For more details see
	 * {@link org.springframework.web.servlet.AsyncHandlerInterceptor}.
	 * <p>The default implementation returns {@code true}.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler chosen handler to execute, for type and/or instance evaluation
	 * @return {@code true} if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
	 * @throws Exception in case of errors
	 */
	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}
让我们来翻译一下上面的注释,看看作者是怎么解释这个方法的。

在确定适当的处理对象调用HandlerMapping HandlerAdapter就调用处理程序之前该拦截方法会调用执行,也就是说该方法会在请求处理之前调用。Spring的拦截器是链式调用的,并且可以存在多个拦截器,当这个方法执行完成之后需要返回一个布尔值,来告诉拦截器是否执行下一个方法。每一个拦截器可以决定中止执行链,通常发送一个HTTP错误或编写一个自定义的响应如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法

/ * *


*拦截处理程序的执行。后调用HandlerAdapter实际


*调用处理程序,但在DispatcherServlet的呈现视图。


*可以公开的其他对象模型通过给定的ModelAndView的看法。


* <P> DispatcherServlet的过程处理程序在执行链组成


*任何数量的拦截与处理器本身最后。


*用这种方法,每个拦截可以后处理一个执行,


*在执行链的逆顺序中得到应用。


*强>注:< /强>特别考虑适用于异步


*请求处理。更多细节请看


* {@链接org。springframework.com.Servlet asynchandlerinterceptor }。


*默认实现是空的。


* @param要求当前HTTP请求


* @param响应当前的HTTP响应


* @param处理器处理器(或{@链接handlermethod })开始异步


*执行,进行类型和/或实例检查


* @param ModelAndView的{ @代码,处理程序返回ModelAndView }


*(也可以是“@代码”)


“在错误的情况下抛出异常”


* /
	default void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception {
	}
postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行
/ * *


*在完成请求处理后的回调,即渲染后


*视图。将被调用处理程序执行的任何结果,从而允许


*为适当的资源清理。


* <BR>注意:只会在这个拦截器的{ @代码prehandle叫}


*方法已成功地完成并返回{代码真}!


* <BR>与{ @代码posthandle }的方法,该方法将被调用的每


*在链中以相反的顺序,所以第一个拦截将是


*被调用的最后一个。


*强>注:< /强>特别考虑适用于异步


*请求处理。更多细节请看


* {@链接org。springframework.网站。Servlet asynchandlerinterceptor }。


*默认实现是空的。


* @param要求当前HTTP请求


* @param响应当前的HTTP响应


* @param处理器处理器(或{@链接handlermethod })开始异步


*执行,进行类型和/或实例检查


* @param前抛出的异常处理程序的执行上,如果任何


“在错误的情况下抛出异常”


* /
default void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}
根据注释我们可以总结出这个方法也是在当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行,而且跟postHandle方法的执行顺序一样,
链中以相反的顺序,所以第一个拦截将是最后一个调用的,这里作者还特别强调了适用于异步编程。

这里方法主要用来做资源清理工作的。

这里做一个小例子,需求是为了测量某一个方法的执行时间,找到痛点并进行优化,也就是上面适用场景之3。

 public class PerformanceInterceptor implements HandlerInterceptor{ 
	    	   /** 
		     * preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,
		     * SpringMVC中的Interceptor拦截器是链式的,可以同时存在 
		     * 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,
		     * 而且所有的Interceptor中的preHandle方法都会在 
		     * Controller方法调用之前调用。SpringMVC的这种Interceptor链式结构也是可以进行中断的,
		     * 这种中断方式是令preHandle的返 
		     * 回值为false,当preHandle的返回值为false的时候整个请求就结束了。 
		     */
	    	@Override  
	        public boolean preHandle(HttpServletRequest request,  
	            HttpServletResponse response,Object handler)throws Exception{{  
	            long startTime = System.currentTimeMillis();  //开始时间
	            request.setAttribute("startTime",startTime);  
	            return true;  
	        }
	            
	            /** 
	             * 这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。
	             * postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之 
	             * 后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet
	             * 进行视图的渲染之前执行,
	             * 也就是说在这个方法中你可以对ModelAndView进行操 
	             * 作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该
	             * 方法反而会后调用
	             * ,这跟Struts2里面的拦截器的执行过程有点像, 
	             * 只是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法
	             * ,Struts中调用ActionInvocation的invoke方法就是调用下一个Interceptor 
	             * 或者是调用action,然后要在Interceptor之前调用的内容都写在调用invoke之前,
	             * 要在Interceptor之后调用的内容都写在调用invoke方法之后。 
	             */
	        @Override  
	        public void postHandle(HttpServletRequest request,HttpServletResponse response,  
	            Object handler,ModelAndView modelAndView)throws Exception{  
	            long startTime = (Long)request.getAttribute("startTime"); //获取开始时间
	            long endTime = System.currentTimeMillis();  
	            modelAndView.addObject("handlingTime",endTime-startTime);   //得出最终结果
	        }
	        /** 
	         * 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。
	         * 该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行, 
	         * 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle
	         * 方法的返回值为true时才会执行。 
	         */
	        @Override  
	        public void afterCompletion(HttpServletRequest request,  
	            HttpServletResponse response,Object handler,Exception ex)throws Exception{  
	        	 request.removeAttribute("startTime");   //资源情理工作
	        }  
	    } 

 

接着要配置我们的xml文件

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-3.0.xsd  
     http://www.springframework.org/schema/mvc  
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
 这样在SpringMVC的配置文件中就可以使用mvc标签了,mvc标签中有一个mvc:interceptors是用于声明SpringMVC的拦截器的。

<mvc:interceptors>  
    <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->  
    <bean class="com.cn.web.interceptor.PerformanceInterceptor"/>  
</mvc:interceptors>  




 



Spring MVC的拦截器

标签:

原文地址:http://blog.csdn.net/liaodehong/article/details/52203373

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!