拦截器概念
(重点)
拦截器(Interceptor) 是一种动态拦截方法调用的机制
简单来说就是在控制方法调用前后的干事情的
-
作用
1.在指定的方法调用前后执行预先设定后的的代码
2.阻止原始方法的执行
-
核心原理:AOP思想
-
拦截器链:多个拦截器按照一定的顺序,对原始被调用功能进行增强
比如:去银行对服务器进行维护,进去时是重重防护,并获取权限进去,干完活处理,又要按之前的顺序倒序返回在之前关卡所得到的内容
过滤器( Filter)与拦截器(Interceptor)的区别
1.拦截内容不同: Filter(过滤器)对所有访问进行增强,Interceptor(拦截器)仅针对springMVC的访问进行增强
2.归属不同: Filter属于servlet技术,Interceptor 属于SpringMVC技术
拦截器作用:增强
自定义拦截器
(重点)
package com.yy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Controller
public class InterceptorController {
@RequestMapping("/handleRun")
public String handleRun() {
System.out.println("业务处理器运行------------main");
return "page.jsp";
}
}
第一步:制作拦截器功能类(通知)
-
MyInterceptor.java拦截器功能类测试代码
package com.yy.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //自定义拦截器需要实现HandleInterceptor接口,实现接口默认是不会报错的,需要自己去重写下面这三个抽象方法 public class MyInterceptor implements HandlerInterceptor { //处理器运行之前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("前置运行----a1"); //返回值为false将拦截原始处理器的运行,表示不向下运行,这时后面的postHandle和afterCompletion不会继续运行了 //返回值是true代表向下放行 //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行 return true; } //处理器运行之后执行 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("后置运行----b1"); } //所有拦截器的后置执行全部结束后,执行该操作 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("完成运行----c1"); } //三个方法的运行顺序为 preHandle -> postHandle -> afterCompletion //如果preHandle返回值为false,三个方法仅运行preHandle }
jsp代码
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %> <html> <body> <h1>拦截器测试中...</h1> </body> </html>
第二步:配置拦截器的执行位置(切入点)
-
配置拦截器的spring-mvc.xml的代码
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.yy"/> <mvc:annotation-driven/> <!--开启拦截器使用--> <mvc:interceptors> <!--开启具体的拦截器的使用,可以配置多个--> <mvc:interceptor> <!--设置拦截器的拦截路径,支持*通配--> <!--/** 表示拦截所有映射--> <!--/* 表示拦截所有/开头的映射--> <!--/user/* 表示拦截所有/user/开头的映射--> <!--/user/add* 表示拦截所有/user/开头,且具体映射名称以add开头的映射--> <!--/user/*All 表示拦截所有/user/开头,且具体映射名称以All结尾的映射--> <mvc:mapping path="/*"/> <mvc:mapping path="/**"/> <mvc:mapping path="/handleRun*"/> <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的--> <mvc:exclude-mapping path="/b*"/> <!--指定具体的拦截器类--> <bean class="com.yy.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
运行结果:
前置运行----a1
业务处理器运行------------main
后置运行----b1
完成运行----c1
拦截器参数
参数分析
HttpServletRequest:请求
HttpServletResponse:响应handler:就是封装了Method方法,简单来说就是操作与原始方法相关的东西,就是通过这个对象去操作
ModelAndView:是handle运行完,返回的东西。通过这个参数可以对执行完的结果进行修正,例如如果你出现了什么问题,会让你去B页面
Exception:如果InterceptorController抛出异常,在这个afterCompletion方法里面可以拦截过滤,然后根据异常做处理
preHandle方法
:handle运行之前要做的事
,写在这个方法里面,例如做参数的格式处理、权限校验等等
postHandle方法
:运行之后对里面数据进行处理
。例如它返回了一个json数据,在这里面我想再加一条JSON数据,就需要在这里面做,比如如果你之前返回的是页面A,我在这里可以换成页面B,比如你之前登录的有session状态,我在这里可以清掉
afterCompletion方法
:就干一件事,如果里面有异常,在这里可以根据异常对它进行处理
拦截器配置项
拦截器工作流程分析
拦截器链配置
当配置多个拦截器时,形成拦截器链
拦截器链的运行顺序参照配置的先后顺序
当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
-
spring-mvc.xml,在这里面我又新建了两个拦截器,基本上与上面的拦截器配置一样,只不过是打印的数据不一样,在这里便不把另外两个拦截器的java代码给出
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.yy"/> <mvc:annotation-driven/> <!--开启拦截器使用--> <mvc:interceptors> <!--开启具体的拦截器的使用,可以配置多个--> <mvc:interceptor> <!--设置拦截器的拦截路径,支持*通配--> <!--/** 表示拦截所有映射--> <!--/* 表示拦截所有/开头的映射--> <!--/user/* 表示拦截所有/user/开头的映射--> <!--/user/add* 表示拦截所有/user/开头,且具体映射名称以add开头的映射--> <!--/user/*All 表示拦截所有/user/开头,且具体映射名称以All结尾的映射--> <mvc:mapping path="/*"/> <mvc:mapping path="/**"/> <mvc:mapping path="/handleRun*"/> <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的--> <mvc:exclude-mapping path="/b*"/> <!--指定具体的拦截器类--> <bean class="com.yy.interceptor.MyInterceptor"/> </mvc:interceptor> <!-- <!–配置多个拦截器,配置顺序即为最终运行顺序–>--> <mvc:interceptor> <mvc:mapping path="/*"/> <bean class="com.yy.interceptor.MyInterceptor2"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/*"/> <bean class="com.yy.interceptor.MyInterceptor3"/> </mvc:interceptor> </mvc:interceptors> </beans>
-
正常运行结果(全为true)
前置运行----a1
前置运行------a2
前置运行--------a3
业务处理器运行------------main
后置运行--------b3
后置运行------b2
后置运行----b1
完成运行--------c3
完成运行------c2
完成运行----c1
责任链模式
责任链模式是一种行为模式
特征:
- 沿着一条预先设定的任务链顺序执行, 每个节点具有独立的工作任务
优势:
- 独立性:只关注当前节点的任务,对其他任务直接放行到下一节点
- 隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可
- 灵活性:可以任意修改链路结构动态新增或删减整体链路责任
- 解耦:将动态任务与原始任务解耦
弊端:
- 链路过长时,处理效率低下
- 可能存在节点上的循环引用现象,造成死循环,导致系统崩溃
拦截器链的运行顺序
- preHandler:与配置顺序相同,必定运行
- postHandler:与配置顺序相反,可能不运行;
- afterCompletion:与配置顺序相反,可能不运行