什么是拦截器
说明
1.Spring MVC也可以使用拦截器对请求进任拦截处理,用户可以自定义拦截器来实现特定的功能。
2.自定义的拦截器必须实现HandlerInterceptor:接口
自定义拦截器的三个方法
1.preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理。
2.postHandle():这个方法在目标方法处理完请求后执行
3.afterCompletion():这个方法在完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
自定义拦截器执行流程分析图
自定义拦截器执行流程说明
1.如果preHanle方法返回false,则不再执行目标方法,可以在此指定返回页面
2.postHandle在目标方法被执行后执行。可以在方法中访问到目标方法返回的ModelAndView对象
3.若preHandle返回true,则afterCompletion方法在渲染视图之后被执行。
4.若preHandle返回false,则afterCompletion方法不会被调用
5.在配置拦截器时,可以指定该拦截器对哪些请求生效,哪些请求不生效
应用实例
1.创建自定义的拦截器,com/stein/springMVC/interceptor/MyInterceptor.java
@Component //需要注入到容器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("---MyInterceptor-preHandle()被调用--");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---MyInterceptor-postHandle()被调用--");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("---MyInterceptor-afterCompletion()被调用--");
}
}
2.在springMVC中进行配置,web/WEB-INF/springMVC-servlet.xml
说明:
拦截器Interceptor是由springMVC来配置
过滤器Filter是由web.xml来配置
1)配置方法一,只配置一个拦截器
可以直接放在<interceptors>里面,注意有s
然后可以不配置<mvc:mapping>,默认拦截所有
<mvc:interceptors>
<ref bean="myInterceptor"/>
</mvc:interceptors>
2)配置方法二,放在子<mvc:interceptor>里面,注意没有s
可以配置多个<mvc:interceptor>
但必须配置<mvc:mapping> ,否则使用时报错
path的值,是对应的requestMapping,支持通配符操作
交换mapping和ref标签的位置,软件会报错
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/h*" />
<ref bean="myInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3.创建访问页面,web/interceptor.jsp
<h1>拦截器</h1>
<a href="<%=request.getContextPath()%>/hello">--目标方法hello</a><br><br>
<a href="<%=request.getContextPath()%>/hi">--目标方法hi</a><br><br>
<a href="<%=request.getContextPath()%>/ok">--目标方法ok</a><br><br>
4.测试
hi方法被拦截
ok方法没有拦截
---MyInterceptor-preHandle()被调用--
hi
---MyInterceptor-postHandle()被调用--
---MyInterceptor-afterCompletion()被调用--
ok
注意事项和细节
1、默认配置是都所有的目标方法都进行拦截,也可以指定拦截目标方法,比如只是拦截hi
<mvc:interceptor>
<mvc:mapping path="/hi"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
2、mvc:mapping支持通配符,同时指定不对哪些目标方法进行拦截
<mvc:interceptor>
<mvc:mapping path="/h*"/>
<mvc:exclude-mapping path="/hello"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
3、拦截器需要配置才生效,不配置是不生效的。
@component + springMVC配置
4、如果preHandler()方法返回了false,就不会执行目标方法(前提是目标方法被拦截),程序员可以在这里根据业务需要指定跳转页面。
Debug代码
1.修改com/stein/springMVC/interceptor/InterceptorHandler.java的hi方法
添加参数user,便于查看ModelAndView传递的数据
@RequestMapping("/hi")
public String hi(User user){
System.out.println("hi~"+user);
return "success";
}
2.Debug模式启动,点击页面hi方法
3.后端可以看到,handler就是目标方法,同时拦截器的preHandle方法被调用
4.然后可以走到目标方法hi
5.继续运行到postHandle,可以看到modelAndView附带了参数,以及视图
6.通过Ctrl+N查找DispatcherServlet的render方法,可以看到mv依然为空
7.通过返回view视图,通过render渲染数据
8.最后返回afterCompletion,看到目标方法,以及有异常初选的话,会封装到Exception中去
9.也可以使用postman对user进行赋值,这样走debug的时候,有具体的数据
多个拦截器
多个拦截器执行流程示意图
应用实例1
代码实现
1.创建第二个拦截器,com/stein/springMVC/interceptor/MyInterceptor02.java
注意使用注解@Component将其注入,否则后面配置不会生效
@Component
public class MyInterceptor02 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("---MyInterceptor02.preHandle()被调用---");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("---MyInterceptor02.postHandle()---");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("---MyInterceptor02.afterCompletion()---");
}
2.配置web/WEB-INF/springMVC-servlet.xml
第一个拦截器,排除/hi路径
配置第二个拦截器,再次强调,对应的拦截器要注入
可以看出,是按照配置的顺序,设定拦截器的生效顺序的
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/h*" />
<mvc:exclude-mapping path="/hi"/>
<ref bean="myInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/h*"/>
<ref bean="myInterceptor02"/>
</mvc:interceptor>
</mvc:interceptors>
3.测试
测试1:点击hello方法
可以看到执行的流程
---MyInterceptor-preHandle()被调用--
---MyInterceptor02.preHandle()被调用---
hello
---MyInterceptor02.postHandle()---
---MyInterceptor.postHandle()被调用--
---MyInterceptor02.afterCompletion()---
---MyInterceptor.afterCompletion()被调用--
测试2:点击hi方法
因为拦截器1排除了目标方法hi,所以只有一个拦截
---MyInterceptor02.preHandle()被调用---
hi
---MyInterceptor02.postHandle()---
---MyInterceptor02.afterCompletion()---
测试3:点击ok方法
因为没有拦截器对其生效,所以没有拦截
ok
注意事项和细节
1.如果A拦截器的preHandle()返回false,则直接返回browser,后面都不在执行
2.如果B拦截器的preHandle()返回false,就直接执行第1个拦截器的afterCompletion()方法,如果拦截器更多,规则类似
3.上述两种情况,都不会执行目标方法hi();
4.说明:前面说的规则,都是目标方法被拦截的前提
应用实例2
1.需求:如果用户提交的数据有禁用词(比如病毒),则在第1个拦截器就返回,不再执行目标方法,功能效果示意图
2.创建跳转的页面,web/WEB-INF/page/warning.jsp
<h1>不要乱说讲话</h1>
3.修改拦截器的preHandler方法,com/stein/springMVC/interceptor/MyInterceptor02.java
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("---MyInterceptor02.preHandle()被调用---");
String keyword = request.getParameter("keyword");
if("病毒".equals(keyword)){
System.out.println("true已经执行");
//绝对路径(推荐):以 / 开头,表示从当前 Web 应用的根目录(Context Root)开始
//request.getRequestDispatcher("web/WEB-INF/page/warning.jsp").forward(request, response);会找不到
request.getRequestDispatcher("/WEB-INF/page/warning.jsp").forward(request, response);
return false;
}
System.out.println("keyword="+keyword);
return true;
}
4.使用postman测试。post方法测试结果如需求1示例图,下面是get方法测试
结果一致
---MyInterceptor02.preHandle()被调用---
true已经执行