过滤器、监听器、拦截器的区别
- 过滤器(filter)、监听器(Listener)是JavaWeb的三大组件。
- 而拦截器(Interceptor)是Spring框架中的。
我们主要是要分清除过滤器和拦截器的区别:
- 实现原理:过滤器是基于函数回调实现的,而拦截器是基于java的反射机制。
- 使用范围:过滤器Filter的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。而拦截器是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。
- 触发时机:
从图中我看可以看出,过滤器Filter是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。而拦截器Interceptor是在请求进入servlet后,在进入Controller之前进行预处理的,Controller中渲染了对应的视图之后请求结束。
执行顺序
配置Filter:
package com.qcby.demo.config;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
@Component
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 前置过滤");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter 处理中");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("Filter 后置过滤");
}
}
自定义拦截器:
package com.qcby.demo.config;
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("Interceptor 前置拦截");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor 后置拦截");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor 最终拦截");
}
}
配置拦截器:
package com.qcby.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**") // 设置要拦截的
.excludePathPatterns("/test1");// 设置不拦截的
}
}
控制器:
package com.qcby.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("test")
public class TestController {
@GetMapping("/test1")
public String test() {
return "123456";
}
}
项目启动之后,我们会发现过滤器的init()方法,随着容器的启动进行了初始化:
然后浏览器访问对应的端口号:http://localhost:8080/test/test1,会有以下输出:
这样就验证了我们前边的过滤器和拦截器的触发顺序。
对于拦截器的触发时机,在只有一个拦截器时:
有多个拦截器时:
过滤器的应用场景
- 过滤敏感词汇(防止sql注入)
- 设置字符编码
- URL级别的权限访问控制
- 压缩响应信息
拦截器的应用场景
- 登录验证,判断用户是否登录。
- 权限验证,判断用户是否有权限访问资源,如校验token
- 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
- 处理cookie、本地化、国际化、主题等。
- 性能监控,监控请求处理时长等。
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现)