Springboot 拦截器
- 定义
- 使用场景
- 拦截器与过滤器的区别
- 实现步骤
- 全局拦截器的局限性
- 全局拦截器VS局部拦截器
- 局部拦截器
- 自定义局部拦截器
- 使用多个局部拦截器
定义
拦截器是Spring MVC框架中的一个重要组件,它是一种
AOP
(面向切面编程)的实现方式,专门拦截对控制层的请求。拦截器可以用于判断用户权限、拦截WebSocket请求等。
使用场景
Springboot拦截器具有多种作用,主要包括请求预处理
、请求日志记录
、鉴权和权限控制
、异常处理
等。拦截器是一种特殊的组件,可以在请求处理的过程中对请求和响应进行拦截和处理。在不修改原有代码的情况下,实现对请求和响应的统一处理。
拦截器与过滤器的区别
- 拦截器是基于java的反射机制的,而过滤器是基于函数的回调。
- 拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。
- 拦截器只对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值、栈里面的对象,而过滤器不可以。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
实现步骤
- 实现
HandlerInterceptor
接口。 - 将拦截器加入
WebMvcConfigrer
。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求处理之前进行拦截
System.out.println("Pre Handle method is Calling");
return true; // 返回true表示继续向下执行,返回false则中断执行。
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在请求处理之后,但在视图渲染之前进行拦截
System.out.println("Post Handle method is Calling");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在整个请求结束之后进行拦截,即在DispatcherServlet渲染了对应的视图之后执行。
System.out.println("Request and Response is completed");
}
}
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加全局拦截
registry.addInterceptor(new MyInterceptor());
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
}
全局拦截器的局限性
每个请求方法都会执行拦截器处理,增加项目性能消耗
全局拦截器VS局部拦截器
局部拦截器
要求如下:
- 执行特定方法才执行拦截器处理
- 不同方法可执行不同拦截器处理
- 单个方法可能要求多个业务类型拦截处理(比如同时需要执行耗时统计和记录日志)
那如何实现这样的局部拦截器呢,很简单,只要使用 Acri 框架处理即可,使用方式如下:
- 引入依赖
<dependency>
<groupId>cn.fntop</groupId>
<artifactId>acri-core</artifactId>
<version>1.0.0</version>
</dependency>
- 注册
AcriIntercepter
拦截器
@Configuration
public class AcriConfig implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 全局拦截
registry.addInterceptor(new AcriIntercepter(applicationContext));
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
- 使用
@Acri
注解
配置项 | 默认值 | 备注 |
---|---|---|
value | null | 具体拦截处理器,实现AcriProcessor并注入Spring容器 |
before | false | 是否处理请求前执行doBefore方法 |
during | false | 是否处理请求方法后执行doDuring方法 |
after | false | 是否在返回响应后执行doAfter方法 |
@Acri(value = AcriStopWatchProcessor.class, before = true, during = true, after = true)
@GetMapping("/login")
public String login() {
log.info("登录中");
return "登录成功";
}
AcriStopWatchProcessor是框架自带的耗时统计拦截
before = true //请求之前执行AcriStopWatchProcessor.doBefore()
方法
自定义局部拦截器
- 实现
implements AcriProcessor
并注入Spring容器
@Slf4j
@Component
public class LogProcessor implements AcriProcessor {
@Override
public void doBefore(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("doBefore");
}
@Override
public void doDuring(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
log.info("doDuring");
}
@Override
public void doAfter(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("doAfter");
}
}
- 使用
//表示请求前执行LogProcessor.doBefore方法,请求后执行LogProcessor.doAfter()方法
//during=false表示不执行doDuring方法
@Acri(value = LogProcessor.class, before = true, during = false, after = true)
@GetMapping("/login")
public String login() {
log.info("登录中");
return "登录成功";
}
- 效果
使用多个局部拦截器
@Acries(more = {@Acri(value = AcriStopWatchProcessor.class, before = true, after = true)
, @Acri(value = LogProcessor.class, before = true, after = true)})
详细文档参考:Acri