• springboot(13):spring 过滤器和拦截器的区别


    在前面我们讲过拦截器怎么使用,参考:拦截器

    和拦截器有个差不多的叫过滤器。

    过滤器和拦截器的区别

    首先看一下下面的流程图:

    在这里插入图片描述
    如上图,其中prehandel、posthandel、afterCompletion是拦截器的方法,filter pre和filter after是过滤器的方法。

    两者区别主要有以下几点:

    1. 触发时机:过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。拦截器是进入servlet之后才触发。
    2. 生命周期:Filter的生命周期由Servlet容器管理,而拦截器由spring提供,并可以使用IoC容器来管理,因此拦截器可以获取IOC容器中的各个bean,而过滤器就不行。
    3. 实现方式:过滤器实现基于回调函数,拦截器(代理模式)的实现基于反射。
    4. 执行方式:过滤器的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。
    5. 影响范围:过滤器可以修改request和response,而拦截器不能。但是过滤器只能在请求的前后使用,而拦截器可以详细到每个方法。

    基于以上区别,过滤器和拦截器的使用场景通常不同。

    拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现。

    拦截器主要应用场景:

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

    过滤器主要应用场景:

    • 过滤敏感词汇(防止sql注入)
    • 设置字符编码
    • URL级别的权限访问控制
    • 压缩响应信息

    过滤器的使用

    有以下两种方式使用过滤器。

    1.使用spring boot提供的FilterRegistrationBean

    先定义Filter:只要实现接口import javax.servlet.Filter,并实现是哪个方法即可,其中最重要的是doFilter方法,在里面写我们的过滤逻辑。代码如下:

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    public class MyFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            Filter.super.init(filterConfig);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            // doFilter()方法中的servletRequest参数的类型是ServletRequest,需要转换为HttpServletRequest类型方便调用某些方法
            System.out.println("filter1");
    
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
    
            String ip = request.getRemoteAddr();
            String url = request.getRequestURL().toString();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date d = new Date();
            String date = sdf.format(d);
    
            System.out.printf("%s %s 访问了 %s%n", date, ip, url);
    
            filterChain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            Filter.super.destroy();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    然后注册我们的Filter:

    import com.example.server.common.MyFilter;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration
    public class FilterConfig {
    
        @Bean
        public FilterRegistrationBean registrationBean() {
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
            // 设置过滤的url
            filterRegistrationBean.addUrlPatterns("/*");
            // 设置优先级
            filterRegistrationBean.setOrder(1);
            return filterRegistrationBean;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.使用原生servlet注解定义Filter

    用@WebFilter就可以进行配置。代码如下:

    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.*;
    import javax.servlet.FilterConfig;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    
    
    @Component
    // 定义filterName 和过滤的url
    @WebFilter(filterName = "myFilter2" ,urlPatterns = "/*")
    @Order(2)
    public class MyFilter2 implements Filter {
    
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            Filter.super.init(filterConfig);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("my filter2");
        }
    
        @Override
        public void destroy() {
            Filter.super.destroy();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在启动类中加另外一个注解:@ServletComponetScan,指定扫描的包。

    @SpringBootApplication
    @ServletComponentScan
    public class FilterTestApplication {
     
    	public static void main(String[] args) {	
    		ConfigurableApplicationContext applicationContext = SpringApplication.run(FilterTestApplication.class, args);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    拦截器的使用

    参考文章:拦截器

    参考文章:
    https://blog.csdn.net/qq_49313444/article/details/107504196
    https://blog.csdn.net/qq_42076204/article/details/125215984

  • 相关阅读:
    LeetCode--代码详解 146.LRU缓存
    Hoops API参考: 3D Graphics System的Set_Color()函数
    服务器创建虚拟环境跑代码
    【大学英语视听说上】绕口令练习
    学习笔记-java代码审计-命令执行
    android studio项目实例-基于Uniapp+SSM实现的Android安全网购平台
    3个ui自动化测试痛点
    理解 Vue.js 中的 immediate: true
    cloudwu/coroutine 源码分析
    内存问题难定位,那是因为你没用 ASAN
  • 原文地址:https://blog.csdn.net/qq_43745578/article/details/128007979