拦截器(interceptor)的作用
拦截器和过滤器区别
一般开发当中,我们都是用Interceptor去做。
拦截器的快速入门
自定义拦截器很简单,只有如下三步:
1、创建拦截器类实现HandlerInterceptor接口
2、配置拦截器
3、测试拦截器的拦截效果
开始入门以前,先准备好环境,我准备了一个目标控制器方法target
@RequestMapping("/target")
@ResponseBody//不进行页面跳转
public ModelAndView target(){
System.out.println("访问目标资源...");
ModelAndView md = new ModelAndView();
md.addObject("name","itcast");
md.setViewName("index");
return md;
}
还有对应跳转的index页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
Hello World!${name}
</body>
</html>
在没有配置拦截器之前,访问该控制器方法,会跳转到页面index并显示Hello World!itcast,并在控制台中输出“访问目标资源…”,这是没有拦截器的效果。
现在我们开始配置拦截器。
现在环境有了以后,我们在itheima主包下创建一个interceptor包,在其下写上一个Myinterceptor类并实现HandlerInterceptor,这是第一步:
package com.itheima.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Myinterceptor1 implements HandlerInterceptor {
/*
这个接口其实有三个方法需要我们去实现,但是在HandlerInterceptor接口内部
这三个方法都被default关键字给修饰了,所以我们需要手动去重写一下
这三个方法分别是preHandle、postHandle、afterCompletion
*/
//在目标方法执行之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandle...");
return false;
}
//在目标方法执行之后 视图返回对象之前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("postHandle...");
}
//在目标方法的流程都执行完毕之后 再执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("afterCompletion...");
}
}
第二步:在spring-mvc.xml配置文件中配置这个类
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些路径下的资源进行拦截操作
/**表示对所有的方法都执行拦截操作
-->
<mvc:mapping path="/**"/>
<!--这是我们写的那个拦截器类-->
<bean class="com.itheima.interceptor.Myinterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
现在第三步就是进行测试。
访问页面:
页面无跳转,并在控制台中输出了:preHandler…
这是因为我们的拦截器起效果了,但是为什么只输出了preHandler呢?
是因为preHandler方法是在目标方法执行之前执行的,所以访问时先执行的是preHandler方法,并输出了其中的输出语句:preHandler…,而返回的是布尔值是false,不准访问,所以后面的所有方法都没有执行。若想后面的方法都执行,则应该将preHandler方法改为true。
改为true以后的页面访问效果:
控制台中:
分析控制台的输出可知:
执行流程是先执行preHandle,然后是目标方法target,然后是postHandle,最后是afterCompletion。
经常使用的就是preHandle,对目标方法访问之前的判断。我们在这里面写上某些控制访问的逻辑代码以实现拦截的效果:
如我们现在要使浏览器端进行访问时携带参数param,且param的值得为yes我们才让它访问目标方法。
那么伪代码就应该是:
如果yes==param,则返回true,允许访问页面
否则返回false,不允许访问该目标页面且跳转到指定的页面(如error页面)
如上图所示。
其次使用比较多的(其实也不算多)是postHandle,它主要作用就是在这个方法中对我们的ModelAndView进行一个修改的作用。
如:
因为我们这个postHandle方法是在目标方法执行之后执行的,我们已经知道目标方法中的代码逻辑是:
@RequestMapping("/target")
@ResponseBody//不进行页面跳转
public ModelAndView target(){
System.out.println("访问目标资源...");
ModelAndView md = new ModelAndView();
md.addObject("name","itcast");
md.setViewName("index");
return md;
}
其中我们设置了name的值为itcast,并返回了md,所以在上图的postHandle方法中我们对目标方法返回过来的ModelAndView类型的对象md进行了name值的修改,我们将其改成了itheima,所以在最后的访问页面呈现的就是Hello World!itheima。
再来看看SpringMVC配置文件中的配置:
也没什么需要说的,就几个需要注意的点,如mapping path="/**“也可以写成
mapping path=”/xxx/**",表示指定的哪个文件下的所有页面访问会被拦截。还有就是我们可以配置多个拦截器进行拦截的问题,比如我们再增加一个Myinterceptor2,那么访问目标控制器方法时先使用哪个拦截器再使用哪个拦截器完全取决于拦截器的配置文件在配置时的先后顺序。
总结
拦截器方法说明