SpringMVC 学习笔记(六)拦截器
5.1、处理器拦截器简介
Spring Web MVC的处理器拦截器(如无特殊说明,下文所说的拦截器即处理器拦截器)
类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
5.1.1、常见应用场景
1、日志记录:
记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:
如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:
有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:
读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:
如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。
项目的代码框架如下所示
首先我们自定义一个拦截器,该拦截器需要实现HandlerInterceptor
package com.ibigsea.springmvc.Interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class FirstInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub System.out.println("FirstInterceptor :preHandle is called"); return true; } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub System.out.println("FirstInterceptor :postHandle is called"); } public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub System.out.println("FirstInterceptor :afterCompletion is called"); } }
再次在spring-mvc.xml中对拦截器进行配置
<?xml version="1.0" encoding="UTF-8"?> <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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 配置自动扫描包 扫描com.ibigsea.springmvc 包下的类,后期会使用spring进行管理 --> <context:component-scan base-package="com.ibigsea.springmvc"/> <!-- 配置视图解析器 如返回helloworld 为 [/WEB-INF/pages/helloworld.jsp] --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 后缀 --> <property name="suffix" value=".jsp"/> </bean> <!--将自定义的转换器加入到框架中--> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.ibigsea.springmvc.handler.EmployeeConverts"/> </set> </property> </bean> <!-- 视图相关配置 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/" /> <!-- 视图前缀 --> <property name="suffix" value=".jsp" /> <!-- 视图后缀 --> </bean> <!-- 存储区域设置信息 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" /> <!-- 国际化资源文件 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="message" /> </bean> <mvc:interceptors> <!-- 配置我们定义的自定义拦截器 --> <bean class="com.ibigsea.springmvc.Interceptor.FirstInterceptor"></bean> <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <property name="paramName" value="lang" /> </bean> </mvc:interceptors> <!-- 配置运行可以访问静态资源文化 --> <mvc:default-servlet-handler/> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> </beans>
注意配置拦截器有两种方式,上面那种配置拦截器对任何访问的路径都有效,我们如果只规定访问特定的url的时候拦截器才有效,可以采用下面的配置
<!-- 只允许特定的url --> <mvc:interceptor> <mvc:mapping path="/emps"/> <bean class="com.ibigsea.springmvc.Interceptor.FirstInterceptor"></bean> </mvc:interceptor>
只有访问/emp操作的时候,拦截器才有效
我们来看看拦截器的执行操作流程
FirstInterceptor :preHandle is called
handle :testGuojihua is called
FirstInterceptor :postHandle is called
FirstInterceptor :afterCompletion is called
preHandle:该方法在目标方法执行之前被调用,可以执行日志记录或者登陆操作判断,返回值:true表示继续流程(如调用下一个拦截器或目标方法),如果返回值是false,不再执行后续的拦截器和目标方法;
postHandle:在目标方法执行成功之后,但在渲染视图之前,将页面视图返回给客户端之前执行,此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
我们来看看两个拦截器的执行顺序,我们在添加一个拦截器
我们在添加一个自定义拦截器
package com.ibigsea.springmvc.Interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class SecondInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub System.out.println("SecondInterceptor :preHandle is called"); return true; } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub System.out.println("SecondInterceptor :postHandle is called"); } public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub System.out.println("SecondInterceptor :afterCompletion is called"); } }
在spring-mvc.xml中进行配置
<?xml version="1.0" encoding="UTF-8"?> <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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 配置自动扫描包 扫描com.ibigsea.springmvc 包下的类,后期会使用spring进行管理 --> <context:component-scan base-package="com.ibigsea.springmvc"/> <!-- 配置视图解析器 如返回helloworld 为 [/WEB-INF/pages/helloworld.jsp] --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 后缀 --> <property name="suffix" value=".jsp"/> </bean> <!--将自定义的转换器加入到框架中--> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.ibigsea.springmvc.handler.EmployeeConverts"/> </set> </property> </bean> <!-- 视图相关配置 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/" /> <!-- 视图前缀 --> <property name="suffix" value=".jsp" /> <!-- 视图后缀 --> </bean> <!-- 存储区域设置信息 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" /> <!-- 国际化资源文件 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="message" /> </bean> <mvc:interceptors> <!-- 配置我们定义的自定义拦截器 --> <bean class="com.ibigsea.springmvc.Interceptor.FirstInterceptor"></bean> <bean class="com.ibigsea.springmvc.Interceptor.SecondInterceptor"></bean> <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <property name="paramName" value="lang" /> </bean> </mvc:interceptors> <!-- 配置运行可以访问静态资源文化 --> <mvc:default-servlet-handler/> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven> </beans>
正常情况下,我们来看下运行的时序
FirstInterceptor :preHandle is called
SecondInterceptor :preHandle is called
handle :testGuojihua is called
SecondInterceptor :postHandle is called
FirstInterceptor :postHandle is called
SecondInterceptor :afterCompletion is called
FirstInterceptor :afterCompletion is called
对于prehandle按照配置的顺序执行,对于postHandle按照配置的反序执行,对于afterCompletion按照配置的反序执行
第二种情况:如果将first的prehandle返回值设置成false
FirstInterceptor :preHandle is called
只会执行FirstInterceptor :preHandle方法
第三种情况first的prehandle返回值设置成true,second的prehandle返回值设置成false
FirstInterceptor :preHandle is called
SecondInterceptor :preHandle is called
FirstInterceptor :afterCompletion is called
相当的经典
代码的下载地址为:
https://pan.baidu.com/s/1Vi_iDNZOwwubmvf9yxZ2ag
posted on 2018-04-17 22:59 luzhouxiaoshuai 阅读(202) 评论(0) 编辑 收藏 举报