Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。 (springmvc也可以用过滤器)
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。 (普通Javaweb工程不会用)
*过滤器在 url-pattern 中配置了/之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
拦截器能做的事,过滤器都能做,过滤器能做的事,拦截器可能就做不了。
它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
如图,当发请求的时候,如果过滤器拦截的是/*的话,那么发任何请求,都会经过我的过滤器,如果过滤器说了我放行你,那么请求才会被放过去,后台的servlet和jsp才会真正的执行。
拦截器和过滤器的功能类似。
这里的处理器指的是Controller类。而不是之前的Servlet或者jsp
这里也不是过滤器,而是拦截器。
拦截器里面也有代码,放行,放行之前和放行之后都有代码
拦截器只能拦截controller里面的方法
步骤
1.编写拦截器类
2.配置拦截器
MyInterceptor1类
预处理方法,controller方法在执行前执行
//自定义拦截器
//jdk1.8对接口进行了增强,接口中允许你直接写方法而且实现了的,接口中的方法都实现过了
public class MyInterceptor1 implements HandlerInterceptor {
@Override
//重写预处理方法,controller方法在执行前执行
//返回值true,放行,执行下一个拦截器,如果没有,执行controller中的放法
//返回值false.不放行,直接跳到某个页面,提示相关信息
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor执行了");
return true;
}
}
UserController
@RequestMapping("/testInterceptor")
public String testInterceptor() {
System.out.println("testInterceptor执行了.......");
return "success";
}
SpringMVC.xml
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--你要拦截过具体的方法,拦截和不拦截二者只需要选取其中一个,一个拦了,剩下的就不拦截了-->
<!--第一级访问目录是user的都拦截-->
<mvc:mapping path="/user/*"/>
<!--你不要拦截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<bean class="cn.yujie.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
success.jsp
<h1>拦截成功</h1>
<%System.out.println("success.jsp执行了");%>
当preHandle中的返回值为false,意思为不放行,并且跳转到错误页面。此时
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor执行了");
request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return false;
}
error.jsp
<h1>错误页面</h1>
postHandle后处理方法,controller方法执行之后,success.jsp执行之前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor执行了...前");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
@Override
//后处理方法,controller方法执行之后,success.jsp执行之前
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor执行了...后");
}
@Override
//后处理方法,controller方法执行之后,success.jsp执行之前
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor执行了...后");
request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
也是一样的效果
afterCompletion是success.jsp页面执行完之后,该方法会执行
//success.jsp页面执行完之后,该方法会执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor执行了...最后");
}
预处理在controller之前执行,可以用来做一些逻辑的判断,比如判断用户有没有登录,如果登录了,放行,没有登录,就跳转到登录页面中去,后处理也就是方法执行之后进行处理,最后一般可以用来释放一些资源。
如图,再加一个拦截器2
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--你要拦截过具体的方法,拦截和不拦截二者只需要选取其中一个,一个拦了,剩下的就不拦截了-->
<!--第一级访问目录是user的都拦截-->
<mvc:mapping path="/user/*"/>
<!--你不要拦截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<bean class="cn.yujie.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
<!--配置第二个拦截器-->
<mvc:interceptor>
<!--你要拦截过具体的方法,拦截和不拦截二者只需要选取其中一个,一个拦了,剩下的就不拦截了-->
<!--对所有资源进行拦截-->
<mvc:mapping path="/**"/>
<!--你不要拦截的方法-->
<!-- <mvc:exclude-mapping path=""/>-->
<bean class="cn.yujie.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
如图,发送请求的时候,先走1拦截器,再走2拦截器,最后到controller,当controller执行完之后,先返回到2后处理,再到1的后处理,然后就执行success.jsp.当success执行完,最后再走2的最后的方法,再走1的最后的方法