【SSM】SSM之SpringMVC框架:拦截器的应用与分析

一:拦截器的应用

在Web应用中,拦截器可以用来处理异常、记录日志、登录拦截或权限认证等操作。在SpringMVC中,定义一个拦截器也十分简单,Spring提供了一个拦截器的接口HandlerInterceptor,实现该接口即可自定义一个拦截器。我们还是拿上篇博客创建的工程为例,对其进行改造。

1、创建一个类,实现接口HandlerInterceptor:

在src下新建一个包“cn.jingpengchong.hello.interceptor”,创建一个类MyInterceptor,让它实现接口HandlerInterceptor。

package cn.jingpengchong.hello.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 MyInterceptor implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle");
		return false;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle");
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion");
	}
}
2、在配置文件中配置该拦截器:

拦截所有请求:

<mvc:interceptors>
	<bean class="cn.jingpengchong.hello.interceptor.MyInterceptor"/>
</mvc:interceptors>

拦截特定请求:

<mvc:interceptors>
	<mvc:interceptor>
		
		<!-- 拦截所有的请求,这个必须写在前面,也就是写在【不拦截】的上面 -->
        <mvc:mapping path="/**" />
        <!-- 但是排除下面这些,也就是不拦截请求 -->
        <mvc:exclude-mapping path="/login.html" />
        <mvc:exclude-mapping path="/account/login.do" />
		<bean class="cn.jingpengchong.hello.interceptor.MyInterceptor"/>
	</mvc:interceptor>
</mvc:interceptors>

在这里我们配置拦截所有请求。

3、测试:

控制器HelloController中的方法如下:

@RequestMapping("hello")
public String hello() {
	System.out.println("hello");
	return "hello";
}

发布该项目,在浏览器发送请求后结果如下:
在这里插入图片描述
控制台信息如下:
在这里插入图片描述
将拦截器中的preHandle()方法的返回值设置为true后,再次发布项目,发送请求后结果如下:
在这里插入图片描述
控制台打印的信息如下:
在这里插入图片描述
从结果来看,我们知道,第一次的请求被拦截了,而第二次被放行了;并且我们直观的发现了拦截其中三个方法和handler的执行顺序为:preHandle->handler->postHandle->afterCompletion。那么其内部是如何执行的呢?下面就来分析一下。

二:拦截器的源码分析

之前的流程就不再说了,可以参考博客:springmvc一个请求的执行过程
这次我们直接从DispatcherServlet类中的doDispatch()方法开始分析,我们知道在doDispatch()方法的此处会根据映射器获得与请求相匹配的handler方法:
在这里插入图片描述
在下面的代码中,又将该handler方法传给了适配器:
在这里插入图片描述
映射处理器会在此处调用执行applyPreHandle()方法:
在这里插入图片描述
在applyPreHandle()方法内,会获得该程序的所有拦截器,其中就有一个我们自定义的拦截器MyInterceptor:
在这里插入图片描述
接着便对拦截器进行遍历,逐个调用其preHandle()方法:
在这里插入图片描述
在 ConversionServiceExposingInterceptor的preHandle()方法中,只设置了一个属性,并返回了true:
在这里插入图片描述
由于该方法返回了true,所以if判断语句为false,跳过if代码块不执行:
在这里插入图片描述
下面就遍历到了自定义的拦截器MyInterCeptor,并调用自定义拦截器的preHandle()方法:
在这里插入图片描述
在MyInterCeptor的preHandle()方法中执行了一条打印语句,并返回了false:
在这里插入图片描述
在这里插入图片描述
由于该方法返回了false,所以if的判断语句为true,所以执行了if代码块并返回了false:
在这里插入图片描述
由于applyPreHandle()方法返回了false,因此这里为true,方法直接就结束了,而并没有执行下面的processDispatchResult()方法,当然就没有执行render()方法,也当然没有执行getRequestDispatcher()方法,最终也没有进行请求转发,因此页面的响应结果就如我们第一次执行所显示的那样,什么都没有:
在这里插入图片描述
但是如果MyInterceptor的preHandle()方法返回了true,则上图的if判断为false,因此程序接着向下执行,并在此处执行了handler方法:
在这里插入图片描述
在这里插入图片描述
上面的方法执行完毕后获得了一个ModelAndView对象mv:
在这里插入图片描述
接着向下执行,又执行到了applyPostHandle()方法:
在这里插入图片描述
在applyPostHandle()方法中,获得了所有拦截器组成的数组后在遍历的时候从后向前遍历,因此先执行了自定义拦截器MyInterceptor的postHandle()方法:
在这里插入图片描述
在MyInterceptor的postHandle()方法中,我们只输出了一条语句:
在这里插入图片描述
在这里插入图片描述
在applyPostHandle()方法执行完毕后,就执行到了processDispatchResult()方法:
在这里插入图片描述
在processDispatchResult()方法中执行了render()方法,在该方法内解析视图,并调用解析后的视图的render()方法,并在视图的render()方法中执行getRequestDispatcher()方法,并接着调用forward()方法进行请求转发操作。这些在之前已经做了论述,此处不再介绍:
在这里插入图片描述
当执行了render()方法后,接着向下执行,由于mappedHandler不为null,所以就执行到了triggerAfterCompletion()方法:
在这里插入图片描述
在triggerAfterCompletion()方法方法中按照同样的套路获得拦截器数组,并遍历,逐个调用其afterCompletion()方法:
在这里插入图片描述
由于是倒着遍历,所以第一次就执行到了自定义的拦截器MyInterceptor的afterCompletion()方法,在该方法中,我们只打印了一条语句:
在这里插入图片描述
在这里插入图片描述
当该方法执行完毕后triggerAfterCompletion()又调用了HandlerInterceptorAdapter中的afterCompletion()方法,但该方法是个空方法:
在这里插入图片描述
该方法结束后triggerAfterCompletion()方法也就结束了,triggerAfterCompletion()方法结束后processDispatchResult()方法也就结束了,我们的分析也到此结束吧,呼~

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值