1.拦截器与过滤器的区别
:::tips 过滤器就是过滤掉一些不需要的东西(eg:你家大米里面有石头,你需要把石头筛掉,这就是过滤)。拦截器是你希望干预他的进程(eg:不明人员想进校园,被保安拦下,要有证件才能入内。这就是拦截器)。 :::
- 拦截器是基于java的反射机制的,而过滤器是基于函数的回调。
- 拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。
- 拦截器只对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
- 拦截器可以访问action上下文、值、栈里面的对象,而过滤器不可以。
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
- 拦截器可以获取IOC容器中的各个bean,而过滤器不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
2.拦截器与过滤器的触发时机
:::tips
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
过滤器包裹servlet,servlet包裹住拦截器。
:::
3.Springboot中使用Filter过滤器
:::danger
使用场景:在过滤器中修改字符编码(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等。
缺点:一个过滤器实例只能在容器初始化时调用一次
:::
方式一
:::tips
@Order里边的数字越小代表越先被该Filter过滤,@WebFilter代表这是个Filter类并把这个类注入到容器中
:::
【步骤1 】
:::info
自定义 MyFilter implements Filter 重写doFilter()方法
:::
//
@Slf4j
@Order(3)
@WebFilter(filterName ="myFilter3" ,urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("MyFilter3---开始");
chain.doFilter(request,response);
}
}
【步骤二】 :::info 启动类添加注解:@ServletComponentScan :::
@ServletComponentScan
@SpringBootApplication
public class SpringbootFilterInterceptorApp {
public static void main(String[] args) {
SpringApplication.run(SpringbootFilterInterceptorApp.class, args);
}
}
方式二
【步骤1 】
:::info
自定义 MyFilter implements Filter 重写doFilter()方法
:::
@Slf4j
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("执行过滤器MyFilter---开始");
chain.doFilter(request,response);
}
}
【步骤二:】 :::info 自定义MyConfig配置类,并注册自定义类到FilterRegistrationBean :::
@Configuration
public class MyConfig {
@Bean
MyFilter myFilter() {
return new MyFilter();
}
@Bean
public FilterRegistrationBean<MyFilter> filterRegistrationBean(MyFilter myFilter) {
FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(myFilter);
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
4.springboot中使用Interceptor拦截器
:::danger
使用场景:比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。
优点:同时一个拦截器实例在一个controller生命周期之内可以多次调用。
缺点:只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
:::
使用拦截器步骤:
:::info
创建拦截器实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter类:
- 继承关系:HandlerInterceptorAdapter—->AsyncHandlerInterceptor—>HandlerInterceptor
- 通过继承关系可知,我们可以直接通过继承拦截器适配器类来创建自定义的拦截器,这样需要哪个方法就直接重写哪个即可
自定义配置类继承 WebMvcConfigurerAdapter 类或者 WebMvcConfigurationSupport类 :
同样道理,使用适配器类 ::: 【步骤一】
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("进入拦截器之前>>>>>>>>>>>>>");
String name = request.getParameter("name");
if (name.equals("mck")){
return true;
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("进入拦截器中>>>>>>>>>>>>>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("拦截器结束>>>>>>>>>>>>>");
}
}
【步骤二】 ```java @Configuration public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public MyInterceptor getMyInterceptor() {
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getMyInterceptor())
.addPathPatterns("/**")//// 拦截所有路径
.excludePathPatterns("/system/max/login");// 不拦截的路径
}
}
**工作原理**<br />一个拦截器,只有preHandle方法返回true,postHandle、afterCompletion才有可能被执行;如果preHandle方法返回false,则该拦截器的postHandle、afterCompletion必然不会被执行。拦截器不是Filter,却实现了Filter的功能,其原理在于:
1. 所有的拦截器(Interceptor)和处理器(Handler)都注册在HandlerMapping中。
1. Spring MVC中所有的请求都是由DispatcherServlet分发的。
1. 当请求进入DispatcherServlet.doDispatch()时候,首先会得到处理该请求的Handler(即Controller中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。
**拦截器工作流程:**
```java
1.Interceptor2.preHandle
2.Interceptor1.preHandle
3.Controller处理请求
4.Interceptor1.postHandle
5.Interceptor2.postHandle
6.渲染视图view
2.Interceptor1.afterCompletion
2.Interceptor2.afterCompletion
如果在Interceptor1.preHandle中报错或返回false ,那么接下来的流程就会被中断,但注意被执行过的拦截器的afterCompletion仍然会执行。
和Filter共存时的执行顺序
:::danger
拦截器是在DispatcherServlet这个servlet中执行的,因此所有的请求最先进入Filter,最后离开Filter。其顺序如下。
Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter
:::
5.拦截器和过滤器如何取舍
:::danger 在使用场景上有些时候都能使用,但是我们怎么去区分到底使用哪个更好呢?
- 当需要过滤掉其中的部分信息,只留一部分时,就用过滤器。
- 当需要对其流程进行更改,做相关的记录时用拦截器。 :::