Springboot中拦截器和过滤器的区别


拦截器与过滤器的区别:
springCloud中的zuul过滤器filter
:zuul最重要的两个功能,请求路由和过滤。
在这里插入图片描述

filter过滤:

只能对request和response进行操作,提前过滤掉一些信息。或者设置一些参数。然后在然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是:在过滤器中修改字符编(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等。

interceptor:

重要一点是需要配置SpringMVC,使拦截器生效:可以对request、response、handler、modelAndView、exception进行操作拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:

  • 登录验证,判断用户是否登录
  • 权限验证,判断用户是否有权限访问资源,如校验token
  • 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
  • 处理cookie、本地化、国际化、主题等。
  • 性能监控,监控请求处理时长等。

1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
如下图:
在这里插入图片描述

2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。

过滤器拦截器运行先后步骤:
在这里插入图片描述

其中第2步,SpringMVC的机制是由DispaterServlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的.

3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射,代理分静态代理和动态代理,动态代理是拦截器的简单实现。

何时使用拦截器?何时使用过滤器?
如果是非spring项目,那么拦截器不能用,只能使用过滤器。
如果是处理controller前后,既可以使用拦截器也可以使用过滤器。
如果是处理dispaterServlet前后,只能使用过滤器。

总结:

Interceptor和Filter的不同点:
1)使用范围不同,filter是servlet规范规定的,只能用于web程序中,而Interceptor既可以用于web程序中,也可以用于application、swing程序中
2)规范不同:filter是在servlet规范中定义的,servlet支持,而拦截器是spring容器内的,是spring框架支持的。感觉就是一个是javaweb级别的,一个是spring级别的
3)深度不同:filter只在servlet前后起作用,而interceptor能够深入到方法前后、异常抛出前后等。因此interceptor的使用具有更大的弹性。所以在spring框架中应该优先使用拦截器
4)使用的资源不同,interceptor可以使用spring中的任何资源、对象等,而filter不能

1.spring boot 使用过滤器

两种方式:
1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter
两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter

1.1方式一: 一般调用第3方的过滤器。就使用这种

①、先定义Filter:

package com.hwm.filter;

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // do something 处理request 或response
        System.out.println("filter1");
        // 调用filter链中的下一个filter
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {

    }
}

②、注册自定义Filter

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean registrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
}
1.2方式二:一般自己定义的就使用这种

// 注入spring容器
@Component
// 定义filterName 和过滤的url
@WebFilter(filterName = "my2Filter" ,urlPatterns = "/*")
public class My2Filter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter2");
    }
    @Override
    public void destroy() {

    }
}

然后在启动类上添加注解@ServletComponentScan,该注解用于自动扫描指定包下(默认是与启动类同包下)的WebFilter/WebServlet/WebListener等特殊类。

2.Spring boot拦截器的使用:

2.1定义实现类

定义一个Interceptor 非常简单方式也有几种,我这里简单列举两种
1、类要实现Spring 的HandlerInterceptor 接口
2、类继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter

2.2HandlerInterceptor方法介绍
 boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;
 
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;
 
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;
  • preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
  • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回
  • ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
  • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
  • 接下来让我们来实现一个登陆 and 访问权限校验的拦截器吧
2.3 拦截器实现新建LoginInterceptor
**
 * 这里注意如果implement HandlerInterceptor的话,就必须实现它下面的三个方法。
 * 但我们只需要使用preHandle()方法的话, 就没必要只需要extends方法
 * 然后进行方法的重载即可。
 * @Description TODO
 * @Author Mr.Wu
 * @Date 2019/6/4 15:02
 * @Version 1.0
 **/
@Component
@EnableConfigurationProperties(JwtProperties.class)
public class LoginInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private JwtProperties jwtProperties;

    private static final ThreadLocal<UserInfo> THREAD_LOCAL =new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取cookie中的token
        String token = CookieUtils.getCookieValue(request, this.jwtProperties.getCookieName());
        //解析token,获取用户信息。
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey());
        if(userInfo==null){
            return false;
        }
        //把userInfo放入线程局部变量。
        THREAD_LOCAL.set(userInfo);
        return  true;
    }
2.4新建WebAppConfigurer 实现WebMvcConfigurer接口

其实以前都是继承WebMvcConfigurerAdapter类 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
1、继承WebMvcConfigurationSupport
2、实现WebMvcConfigurer
但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
 
  /**
     * 通过@Bean注解,将我们定义的拦截器注册到Spring容器
     * @return
     */
    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }
 
    /**
     * 重写接口中的addInterceptors方法,添加自定义拦截器
     * @param registry
     */
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }
 
    ....
}

其实下面还有很多方法我这里就省略了,过滤器可以添加多个,可以指定Path,这里的/**是对所有的请求都做拦截。
参考:https://blog.csdn.net/zxd1435513775/article/details/80556034
https://blog.csdn.net/heweimingming/article/details/79993591

过滤器的执行流程:

在这里插入图片描述
正常流程:

  • 请求到达首先会经过pre类型过滤器,而后到达route类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。

异常流程:

  • 整个过程中,pre或者route过滤器出现异常,都会直接进入error过滤器,在error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
  • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,将最终结果返回给请求客户端。
  • 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和route不同的是,请求不会再到达POST过滤器了。

拦截器的执行流程:

参考博文
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值