拦截器与过滤器的区别

优质博文:IT-BLOG-CN

拦截器Interceptor和过滤器Filter都是基于AOP(Aspect Oriented Programming,面向切面编程)思想实现的,用来解决项目中某一类问题的两种“工具”,两者在使用上有时候可能会分不清,希望能够通过本章解决这个痛点。

一、拦截器

拦截器InterceptorSpringMVC中实现的一种基于Java反射(动态代理)机制的方法增强工具,是面向切面AOP编程中应用的一种统一处理方案。拦截器的实现是继承HandlerInterceptor接口,并实现接口的preHandlepostHandleafterCompletion方法,对目标方法进行增强。可以访问action上下文、堆栈里的对象,可以多次被调用。
【1】preHandle:请求方法前置拦截,该方法会在Controller处理之前进行调用,Spring中可以有多个Interceptor,这些拦截器会按照设定的Order顺序调用,当有一个拦截器在preHandle中返回false的时候,请求就会终止。
【2】postHandlepreHandle返回结果为true时,在Controller方法执行之后,视图渲染之前被调用。
【3】afterCompletion:在preHandle返回ture,并且整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。此方法主要用来进行资源清理。

@Component
public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取用户信息
        EmpsInformationEntity ee = CommonTool.getEmpsInfo();

        if (ee == null || StringUtils.isEmpty(ee.getEid())) {
            // 跳转登录
            redirectToLoginPage(request, response);
            return false;
        }

        // 模块权限
        PermissionConfig permission = getPermissionConfig(handler);
        boolean hasPermission = checkPermission(request, response, permission);
        if (!hasPermission) {
            if (isAjax(request, permission)) {
                response.getWriter().write("permission error");
            } else {
                List<String> codes = getModuleCode(permission);
                if (CollectionUtils.isNotEmpty(codes)) {
                    response.sendRedirect(String.format(screenPopupConfig.getIamErrorPage(), codes.get(0), ee.getEid()));
                    return false;
                }
                response.sendRedirect(request.getContextPath() + "/noPermisson");
            }
            return false;
        }

        request.setAttribute("Eid", ee.getEid());
        request.setAttribute("Ename", ee.getEmpName());
        /**
         * 多语言环境
         */
        if (request.getRequestURI().indexOf("/lastOrderId") == -1) {
            // 取值
            CultureHelper.initPreRequest(request, response, ee.getDept());
        }
        accessMetric(ee, request);
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

编写完拦截器之后,通过一个配置类设置拦截器,并且可以通过addPathPatternsexcludePathPatterns执行哪些请求需要被拦截,哪些不需要被拦截。

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Autowired
    private UserInterceptor userInterceptor;

    // 或者通过@Bean注入
    /** @Bean
     * public UserInterceptor getUserInterceptor() {
     *     return new UserInterceptor();
     **/ }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/error");
    }
}

应用场景: 主要是用在插件上,扩展件上比如hibernate spring struts2等有点类似面向切片的技术,在用之前先要在配置文件即xml文件里声明一段的那个东西。
【1】日志记录:记录请求操作日志(用户ip,访问时间等)
【2】权限检查:判断用户是否有权限访问资源,如校验token日志记录
【3】性能监控:记录请求->响应时间,preHandle:记录开始时间,afterCompletion:记录结束时间,开始时间相减去结束时间
【4】登录验证:判断用户是否登录
【5】sign校验,封禁校验等
【6】处理cookie,主题,国际化,本地化等
【7】filter可以实现的功能intercepter基本上都能实现

二、过滤器

过滤器Filter基于Servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截配置好的客户端请求,然后对RequestResponse进行处理。Filter过滤器随着web应用的启动而启动,只初始化一次。Filter的使用比较简单,继承Filter接口,实现对应的initdoFilter以及destroy方法即可。
【1】init:在容器启动时调用初始化方法,只会初始化一次。
【2】doFilter:每次请求都会调用doFilter方法,通过FilterChain调用后续的方法。
【3】destroy:当容器销毁时,执行destory方法,只会被调用一次。

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化拦截器");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //做一些处理
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        System.out.println("销毁拦截器");
    }
}

Filter配置类

@Slf4j
@Configuration
public class FilterConfiguration {//不拦截路径
    private static List<String> exclusionUrlList=new ArrayList<>();
    //拦截路径
    private static List<String> inclusionUrlList=new ArrayList<>();

    static {
        exclusionUrlList.add("/favicon.ico");
        exclusionUrlList.add("/**/*.css");
        exclusionUrlList.add("/**/*.js");
        exclusionUrlList.add("/ok");
        inclusionUrlList.add("/api/**");
    }

    @Bean
    public FilterRegistrationBean filterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new MyFilter());
        registration.addInitParameter(FILTER_INIT_PARAM_EXCLUSION_URLS,String.join(",", exclusionUrlList));
        registration.addInitParameter(AJAX_URL_PATTERNS,String.join(",", inclusionUrlList));
        registration.addUrlPatterns("/*");
        registration.setName("testFilter");
     return registration;
    }
}

过滤器Filter的三种配置方式:
【1】通过@WebFilter注解配置

1.初始化Filter

@WebFilter(urlPatterns = "/test001")
@Order(1) //order值越小,过滤器越靠前,此处配置无效
public class MyFilter implements Filter {
    @Override
    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
        System.out.println("##############TestFilter init##############");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //在DispatcherServlet之前执行
        System.out.println("##############doFilter before##############");
        filterChain.doFilter(servletRequest, servletResponse);
        // 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("##############doFilter after##############");
    }

    @Override
    public void destroy() {
        System.out.println("##############TestFilter destroy##############");
    }
}

//2.在启动类添加 @ServletComponentScan

@SpringBootApplication 
@ServletComponentScan 
public class TestbootApplication { 
  public static void main(String[] args) { 
    SpringApplication.run(TestbootApplication.class, args); 
  } 
}

【2】通过@Bean来配置:初始化Filter

@Component
public class MyFilter implements Filter {
    @Override
    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
        System.out.println("##############Filter3 init##############");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //在DispatcherServlet之前执行
        System.out.println("##############doFilter3 before##############");
        filterChain.doFilter(servletRequest, servletResponse);
        // 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后
        System.out.println("##############doFilter3 after##############");
    }

    @Override
    public void destroy() {
        System.out.println("##############Filter3 destroy##############");
    }
}

注册到config

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean testFilter3RegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new MyFilter());
        registration.addUrlPatterns("/hello");
        registration.setOrder(1); // 值越小越靠前,此处配置有效
        return registration;
    }

    @Bean
    public FilterRegistrationBean testFilter4RegistrationBean() {
        FilterRegistrationBean registration = new FilterRegistrationBean(new MyFilter1());
        registration.addUrlPatterns("/hello");
        registration.setOrder(2);
        return registration;
    }
}

【3】Spring MVCweb.xml进行配置:1、初始化Filter;2、web.xml文件中配置Filter

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

应用场景: 传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者strutsaction进行业务逻辑处理。例如在过滤器中修改字符编码CharacterEncodingFilter、在过滤器中修改HttpServletRequest的一些参数XSSFilter(自定义过滤器),如:过滤低俗文字、危险字符、敏感词过滤、响应信息压缩、控制权限、控制转向、做一些业务逻辑判断等

三、拦截器与过滤器的区别

拦截器与过滤器执行时机不同: 请求进入Servlet之前,过滤器的doFilter方法进行过滤,进入Servlet容器之后,执行Controller方法之前,拦截器的preHandle方法进行拦截,执行Controller之后,视图渲染之前postHandle方法进行拦截,请求结束之后,拦截器的postHandle方法执行。

拦截器基于Java发射机制实现,过滤器基于函数回调方式实现。在实际应用中拦截器主要用于权限控制、日志打印、参数校验,过滤器主要用于跨域问题解决、编码转换

在这里插入图片描述

区别过滤器拦截器备注
配置位置配置在web.xml配置在springmvc.xml
定义位置Filter定义在java.servlet包下接口HandlerInterceptor定义在org.springframework.web.servlet包下
使用范围FilterServlet规范规定的而拦截器既可以用于Web程序,也可以用于ApplicationSwing程序中。
遵循规范Filter是遵循Servlet规范而拦截器是在Spring容器内的,是Spring框架支持的。
实现方式Filter基于函数回掉Interceptor基于java反射
作用Filter在只在Servlet前后起作用,Filter通常不考虑servlet的实现拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入hook into请求的生命周期Spring构架的程序中,要优先使用拦截器。几乎所有Filter能够做的事情,interceptor都能够轻松的实现
调用方Filter是被Server(like Tomcat)调用Interceptor是被Spring调用因此Filter总是优先于Interceptor执行
Spring关系Filter不能够使用Spring容器资源Interceptor是被Spring调用Spring中使用Interceptor更容易

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/149913.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】表的增删改查(基础)

一、新增&#xff08;Create&#xff09; 先创建一张表&#xff1a; create table student (id int,sn int comment 学号,name varchar(20),email varchar(20));1.1 单行数据 全列插入 插入两条记录&#xff0c;value_list 数量必须和定义表的列的数量及顺序一致 insert i…

4、智能家居框架设计和代码文件工程建立

目录 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 SourceInsight创建新工程步骤 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 创建一个名为si的文件夹用于保存SourceInsight生成的文件信息&#xff0c;然后在SourceInsig…

【软考篇】中级软件设计师 第四部分(一)

中级软件设计师 第四部分&#xff08;一&#xff09; 二十九. 程序设计语言概述29.1 解释、编译29.3 编译程序29.4 后缀式29.5 文法定义29.6 正规式29.7 有限自动机29.8 语法分析方法 三十. 法律法规30.1 作品所属权30.2 商标有效期30.3 职务作品所属权30.4 单位与委托30.5 商标…

Redis:详解5大数据类型及其常用命令

目录 Redis键&#xff08;key&#xff09;字符串&#xff08;String&#xff09;简介常用命令数据结构简介常用命令 列表&#xff08;List&#xff09;简介常用命令数据结构 集合&#xff08;Set&#xff09;简介常用命令数据结构 哈希&#xff08;Hash&#xff09;简介常用命令…

基于安卓android微信小程序的装修家装小程序

项目介绍 巧匠家装小程序的设计主要是对系统所要实现的功能进行详细考虑&#xff0c;确定所要实现的功能后进行界面的设计&#xff0c;在这中间还要考虑如何可以更好的将功能及页面进行很好的结合&#xff0c;方便用户可以很容易明了的找到自己所需要的信息&#xff0c;还有系…

SOLIDWORKS Flow Simulation阀门内流体仿真

Flow Simulation 导读 阀门作为输送系统中的控制设备其主要功能是接通管路中的流体介质,又或是调节流体的流量、压力等&#xff0c;在阀门的设计中&#xff0c;流量系数Cv,Kv&#xff0c;以及流阻系数都是基本参数&#xff0c;本节将讲解通过SOLIDWORKS Flow Simulation在三维…

lxml基本使用

lxml是python的一个解析库&#xff0c;支持HTML和XML的解析&#xff0c;支持XPath解析方式&#xff0c;而且解析效率非常高 XPath&#xff0c;全称XML Path Language&#xff0c;即XML路径语言&#xff0c;它是一门在XML文档中查找信息的语言&#xff0c;它最初是用来搜寻XML文…

Netty实战专栏 | NIO详解

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Netty实战专栏 ✨特色专栏&#xff1a…

C语言之深入指针(二)(详细教程)

C语言之深入指针 文章目录 C语言之深入指针1. 传值调用和传址调用2. 数组名的理解3. 使用指针访问数组3. ⼀维数组传参的本质 1. 传值调用和传址调用 写一个函数用来交换a b的值 传值调用&#xff1a; #include <stdio.h> void Swap1(int x, int y) {int tmp 0;tmp x;…

第十八章 Swing程序设计

Swing用于开发桌面窗体程序&#xff0c;是JDK的第二代GUI框架&#xff0c;其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早&#xff0c;其性能、开发效率等不及一些其他流行技术&#xff0c;所以目前市场上大多数桌面窗体程序都不是由Java开发…

rabbitmq 集群搭建

RabbitMQ集群介绍 RabbitMQ集群是一组RabbitMQ节点&#xff08;broker&#xff09;的集合&#xff0c;它们一起工作以提供高可用性和可伸缩性服务。 RabbitMQ集群中的节点可以在同一物理服务器或不同的物理服务器上运行。 RabbitMQ集群的工作原理是&#xff0c;每个节点在一个…

12-使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Python杂谈--关于iter迭代器的一些讨论

首先我们来看下面一段代码&#xff1a; for i in range(5):print(i) 这是一段非常简单的代码&#xff0c;它会打印出“0-5”这五个数字。 此时在range()迭代器中&#xff0c;它的start为空(默认为无穷小)&#xff0c;stop为5&#xff0c;step为空(默认为1)。 此时我们在看下…

hidl hwbinder和binder混合使用相关的joinThreadPool问题解答

背景&#xff1a; 今天一个学员在群里有个提问如下图&#xff0c;怎么有两个joinThread&#xff0c;会执行么&#xff1f;joinThread不是死循环等待数据吗&#xff1f; /frameworks/av/media/mediaserver/main_mediaserver.cpp 当开始看到这个时候确实也觉得最后的hw的join根本…

电脑篇——将串口映射到远程电脑上

通过Windows自带的远程桌面连接功能&#xff0c;可以通过修改本地资源选项&#xff0c;将本机的串口/端口映射到远程电脑上。 即可将端口映射到远程电脑上。 &#xff08;在远程的电脑的设备管理器中可能不会显示&#xff0c;但是用串口调试相关的工具&#xff0c;是可以找到相…

JVM——类加载器(JDK8及之前,双亲委派机制)

目录 1.类加载器的分类1.实现方式分类1.虚拟机底层实现2.JDK中默认提供或者自定义 2.类加载器的分类-启动类加载器3.类加载器的分类-Java中的默认类加载器4.类加载器的分类-扩展类加载器5.类加载器的分类-类加载器的继承 2.类加载器的双亲委派机制 类加载器&#xff08;ClassLo…

文件上传_白名单、内容校验、竞争上传

服务端校验—后缀名白名单校验 服务端校验—文件内容头校验 竞争上传

ROS 学习应用篇(五)服务Server学习之自定义服务与调用

在之前我学着如何建立一个话题Topic的消息类型&#xff0c;那时候建立了一个msg文件&#xff0c;包括&#xff0c;消息名称和消息数据类型&#xff08;int还是什么之类的。&#xff09;&#xff0c;将其链接到CMakeList&#xff0c;.xml文件补录需要的依赖&#xff0c;CMakeLis…

十九章总结

一.Java绘图类 1.Graphics类 Graphics类是所有图形上下文的抽象基类&#xff0c;它允许应用程序在组件以及闭屏图像上进行绘制。Graphics类封装了Java支持的基本绘图操作所需的状态信息&#xff0c;主要包括颜色、字体、画笔、文本、图像等。 2.Graphics2D类 Graphics2…