过滤器(Filter)与拦截器(Interceptor)区别

news2024/10/5 1:23:40

1 过滤器(Filter)

Servlet 中的过滤器 Filter 实现了 javax.servlet.Filter 接口的服务器端程序,主要用途是设置字符集(CharacterEncodingFilter)、控制权限、控制转向、用户是否已经登陆、有没有权限访问该页面等。

其工作原理是,只要你在 web.xml 文件配置好要拦截的客户端请求,它都会帮你拦截到请求。此时,其实你可以对请求或响应(request、response)统一设置编码;它随 web 应用启动而启动,只初始化一次,以后就可以拦截相关请求。只有当你的 web 应用停止或重新部署的时候才销毁。

  • Filter 可以认为是 Servlet 的一种”加强版”。它主要用于对用户请求进行预处理,也可以对
    HttpServletResponse 进行后处理,是个典型的处理链;
  • Filter 可以对用户请求生成响应,和 Servlet 相同;
  • 处理流程:用户请求 -> Filter 预处理 -> Servlet 处理请求生成响应 -> Filter 对响应进行后处理。

1.1 Filter 的用处

  • 在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest;
  • 根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 头和数据;
  • 在 HttpServletResponse 到达客户端之前,拦截 HttpServletResponse;
  • 根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse头和数据。

Filter 有如下几个种类。

1.2 Filter 的种类

  • 用户授权的 Filter:Filter 负责检查用户请求,根据请求过滤用户非法请求;

  • 日志 Filter:详细记录某些特殊的用户请求;

  • 负责解码的 Filter:包括对非标准编码的请求解码;

  • 能改变 XML 内容的 XSLT Filter 等。

Filter 可以负责拦截多个请求或响应,一个请求或响应也可以被多个 Filter 拦截。

1.3 创建 Filter 的步骤

  1. 创建 Filter 处理类,并实现 javax.servlet.Filter 接口;
  2. web.xml 文件中配置 Filter(或者使用 @WebFilter 注解)。

javax.servlet.Filter 接口中定义了三个方法:

  • void init(FilterConfig config) 用于完成 Filter 的初始化;

  • void destory() 用于 Filter 销毁前,完成某些资源的回收;

  • void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) 实现过滤功能。

doFilter 方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)。它们的分界线为,是否调用了 chain.doFilter()。执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

2 拦截器(Interceptor)

拦截器是在面向切面编程中应用的,就是 service 或一个方法前/后调用一个方法。是基础 Java 的反射机制。拦截不是在 web.xml,而是在 AOP(Aspect-Oriented Programming)中用于某个方法或字段被访问之前,进行拦截。然后在之前或之后加入某些操作,甚至在抛出异常的时候做业务逻辑的操作。拦击器是 AOP 的一种实现策略。

2.1 拦截器的实现方式

SpringMVC 中的 Interceptor 拦截请求是通过 HandlerInterceptor 来实现的。在 SpringMVC 中定义 Interceptor 主要有两种方式:

  • 实现 Spring 的 HandlerInterceptor 接口或者继承了实现 HandlerInterceptor 接口的类(比如HandlerInterceptorAdapter);
  • 实现 Spring 的 WebRequestInterceptor 接口,或者继承了实现WebRequestInterceptor接口的类。

Interceptor 中的方法:

preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法

顾名思义,该方法将在请求处理之前进行调用。

SpringMVC 中的 Interceptor 是链式调用。在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor,每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法。

所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和Controller 都不会再执行;当返回值为 true 时就会继续调用下一个 Interceptor 的 preHandle 方法。如果已经是最后一个 Interceptor 的时候就会是调用当前请求的Controller 方法。

postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法

由 preHandle 方法的解释我们知道,这个方法包括后面要说到的 afterCompletion 方法都只能是在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 时才能被调用。

postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用。所以,我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。

postHandle 方法被调用的方向跟 preHandle 是相反的。也就是说,先声明的 Interceptor 的 postHandle 方法反而会后执行。这和 Struts2 里面的 Interceptor 的执行过程有点类似。Struts2 里面的 Interceptor 的执行过程也是链式的,只是在 Struts2 里面需要手动调用 ActionInvocation 的 invoke 方法来触发对下一个 Interceptor 或者是 Action 的调用,然后每一个 Interceptor 中在 invoke 方法调用之前的内容都是按照声明顺序执行的,而 invoke 方法之后的内容就是反向的。

afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法

该方法也是需要当前对应的 Interceptor 的p reHandle 方法的返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{
    private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);
    //before the actual handler will be executed
    public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler)
        throws Exception {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        return true;
    }

    //after the handler is executed
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
        throws Exception {
        long startTime = (Long)request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        //统计耗时
        long executeTime = endTime - startTime;
        //modified the exisitng modelAndView
        modelAndView.addObject("executeTime",executeTime);

        //log it
        if(logger.isDebugEnabled()){
           logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");
        }
    }
}

2.1.1 非 SpringBoot 项目实现方式

使用 mvc:interceptors 标签来声明需要加入到 SpringMVC 拦截器链中的拦截器。


<mvc:interceptors>  
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->  
<bean class="com.company.app.web.interceptor.AllInterceptor"/>  
    <mvc:interceptor>  
         <mvc:mapping path="/**"/>  
         <mvc:exclude-mapping path="/parent/**"/>  
         <bean class="com.company.authorization.interceptor.SecurityInterceptor" />  
    </mvc:interceptor>  
    <mvc:interceptor>  
         <mvc:mapping path="/parent/**"/>  
         <bean class="com.company.authorization.interceptor.SecuritySystemInterceptor" />  
    </mvc:interceptor>  
</mvc:interceptors>

可以利用 mvc:interceptors 标签声明一系列的拦截器,然后它们就可以形成一个拦截器链。拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的 preHandle 方法会先执行,然而它的 postHandle 方法和 afterCompletion 方法却会后执行。

在 mvc:interceptors 标签下声明 interceptor 主要有两种方式:

  • 直接定义一个 Interceptor 实现类的 bean 对象。使用这种方式声明的 Interceptor
    拦截器将会对所有的请求进行拦截;
  • 使用 mvc:interceptor 标签进行声明。使用这种方式进行声明的 Interceptor 可以通过 mvc:mapping
    子标签来定义需要进行拦截的请求路径。

经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。

2.1.2 Spring Boot 项目

配置拦截器


@Configuration
//@Configurationpublic
public class WebAppConfigurer implements WebMvcConfigurer {

    /**
     * 配置拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        registry.addInterceptor(new ExecuteTimeInterceptor()).addPathPatterns("/**");

        //API限流拦截
        registry.addInterceptor(accessLimitAjaxInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**","/login.html");
        registry.addInterceptor(accessInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**","/login.html");
    }
}

2.2 拦截器(interceptor)使用

  1. 请求到达 DispatcherServlet;

  2. DispatcherServlet 发送至 Interceptor,执行 preHandler;

  3. 请求到达 Controller;

  4. 请求结束后,执行 postHandler。

3 过滤器(Filter)与 拦截器(Interceptor)的区别

Spring 的 Interceptor(拦截器)与 Servlet 的 Filter 有相似之处,比如二者都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。

不同之处总结如下:

在这里插入图片描述

3.1 执行顺序

用户请求 -> 过滤前 -> 拦截前 -> Action处理 -> 拦截后 -> 过滤后 -> 响应
在这里插入图片描述

4 过滤器(Filter)与 拦截器(Interceptor)常见用途

  • Authentication Filters

  • Logging and Auditing Filtersx

  • Image conversion Filters

  • Data compression Filters

  • Encryption Filters

  • Tokenizing Filters

  • Filters that trigger resource access events

  • XSL/T filters

  • Mime-type chain Filter

Request Filters 可以实现:

  • 执行安全检查

  • 格式化请求头和主体

  • 审查或者记录日志

  • 根据请求内容授权或者限制用户访问

  • 根据请求频率限制用户访问

Response Filters 可以实现:

  • 压缩响应内容:比如让下载的内容更小

  • 追加或者修改响应

  • 创建或者整体修改响应

  • 根据地方不同修改响应内容

5 总结

5.1 过滤器

所谓过滤器顾名思义是用来过滤的。在 Java Web中,传入的 request、response 提前过滤掉一些信息,或者提前设置一些参数;然后再传入 Servlet 或者 Struts 的 action 进行业务逻辑。比如,过滤掉非法 URL(不是 login.do 的地址请求,如果用户没有登陆都过滤掉),或者在传入 Servlet 或者 Struts 的 action 前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。

Filter 流程是线性的, URL 传来之后,检查之后,可保持原来的流程继续向下执行,被下一个 filter、servlet 接收等。

5.2 Java 的拦截器

主要是用在插件上,扩展件上比如 Hibernate Spring Struts2等 有点类似面向切片的技术,在用之前先要在配置文件即 XML 文件里进行对应的声明。

拦截器(Interceptor)是基于 Java 的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter 能做的事情,拦截器都能做,而且可以在请求前、请求后执行,比较灵活。Filter 主要是针对 URL 地址做一个编码的事情、过滤掉没用的参数、安全校验(比如登录不登录之类),太细的话,还是建议用拦截器。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot配置跨域问题

近期自己搭建项目时&#xff0c;遇到一个跨域问题。我们以前项目解决跨域是在controller上加一个跨域注解CrossOrigin(allowCredentials "true")&#xff0c;很方便。但是在我自己搭建的项目中&#xff0c;启动时竟然报错了&#xff0c;错误如下&#xff1a; When …

图的传递闭包

给定一个有向图,对于给定图中的所有顶点对(i, j),找出一个顶点j是否可从另一个顶点i到达。这里的可达性是指从顶点i到j有一条路径。可达性矩阵称为图的传递闭包。 例如,考虑下面的图表 上述图的传递闭包为 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 该图以邻接矩阵的形式给出,…

抛弃 TCP 和 QUIC 的 HTTP

下班路上发了一则朋友圈&#xff1a; 周四听了斯坦福老教授 John Ousterhout 关于 Homa 的分享&#xff0c;基本重复了此前那篇 It’s Time To Rep… 的格调&#xff0c;花了一多半时间喷 TCP… Ousterhout 关于 Homa 和 TCP 之间的论争和论证&#xff0c;诸多反复回执&…

DAY15|102.二叉树的层序遍历。。。。等层序遍历的十道题

102.二叉树的层序遍历 代码随想录中的这题java和c不太一样 class Solution {public List<List<Integer>> resList new ArrayList<List<Integer>>();public List<List<Integer>> levelOrder(TreeNode root) {checkFun01(root,0);return …

NVIDIA- cuSPARSE(四)

cuSPARSE logging 日志记录机制&#xff0c; 可以通过在启动目标应用程序之前设置一下环境变量来启动cuSPARSE日志记录机制&#xff1a; CUSPARSE_LOG_LEVEL<level> level的取值&#xff1a; 0 Off 日志记录关闭1 Error只有报错会被记录2Trace启动CUDA内核的API调用将记…

网络应用程序设计(idea版)——实验四:会话管理

目录 实验预习报告 一、实验目的 二、实验原理 三、实验预习内容 实验报告 一、实验目的 二、实验要求 三、实验内容与步骤 实验预习报告 一、实验目的 1. 了解Web服务器对客户会话跟踪的各种方法&#xff1b; 2. 重点掌握使用HttpSession对象跟踪会话的方法&#…

OCAF——数据结构机制 Sample2

Email:dev_as@163.com Another example is the application for designing table lamps. The first label is allocated to the lamp unit. The tree definition of Lamp The root label cannot have brother labels. :[Root : (0)],根节点没有兄弟节点 Consequently, var…

ch5_4程序查询方式_程序中断方式_DMA方式

程序查询方式的流程 程序查询方式的接口电路 1. 程序查询方式 程序查询方式&#xff0c;需要通过cpu中的寄存器&#xff0c;完成数据从io设备到内存之间的传输。 1.1 程序查询方式流程 保存寄存器的内容&#xff1a; 如果寄存器中的数据是有用的&#xff0c;需要对寄存器中…

剑指offer:关于二叉树的汇总(c++)

1、重建二叉树&#xff1a; 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建二叉树并返回。 2、树的…

可以顺畅使用不输Chatgpt的AI

一前言 虽然chatgpt不错&#xff0c;但是如果在咱们国家&#xff0c;想使用起来还是有一定的门槛的&#xff0c;又要科学上网&#xff0c;又要申请账号&#xff0c;申请账号还要申请虚拟手机号接收验证码&#xff0c;难道就没有适合普通人使用的AI了吗&#xff0c;直到我发现了…

数字化时代,企业如何做好数字营销

在数字化的影响下&#xff0c;市场竞争愈发激烈&#xff0c;产品和服务的研发生产也加快了节奏&#xff0c;各行业之间的边界也日渐模糊&#xff0c;跨领域、跨赛道也成为数字化转型企业的常态&#xff0c;就像那句话&#xff0c;打败你的不一定是对手&#xff0c;这就是数字化…

AI 时代,提示词便是生产力

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…

AIGC技术周报|图灵测试不是AGI的智力标准;SegGPT:在上下文中分割一切;ChatGPT能玩好文字游戏吗?

AIGC通过借鉴现有的、人类创造的内容来快速完成内容创作。ChatGPT、Bard等AI聊天机器人以及DallE 2、Stable Diffusion等文生图模型都属于AIGC的典型案例。「AIGC技术周报」将为你带来最新的paper、博客等前瞻性研究。 牙科的未来&#xff1a;从多模态大型语言模型窥探 ChatGP…

Java基础教程之Object类是怎么回事?

前言 在前面的文章中&#xff0c;壹哥跟大家说过&#xff0c;Java是面向对象的编程语言&#xff0c;而在面向对象中&#xff0c;所有的Java类都有一个共同的祖先类&#xff0c;这就是Object。那么Object都有哪些特性呢&#xff1f;今天壹哥就简单跟大家分析一下。 -----------…

刷题记录|Day55● 392.判断子序列 ● 115.不同的子序列

● 392.判断子序列 题目描述 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"…

pure-admin九州权限系统地址简单读

分成页面权限(ex:权限管理page) & 标签节点权限(ex:下载按钮) 【九州地址娜娜手机&#x1d54d;找看看kwk3589提供】以下是范例&#xff1a; /*** admin &#xff1a; 管理员角色* common &#xff1a; 普通角色*/const permissionRouter {path: "/permission"…

C++之入门之缺省参数函数重载引用

文章目录前言一、缺省参数1.缺省参数的概念2.缺省函数的分类&#xff08;1&#xff09;全缺省参数&#xff08;2&#xff09;半缺省参数3.使用注意二、函数重载1.函数重载的概念3.函数重载的原理--名字修饰(name Mangling)三、引用1.引用的概念2.引用特性3.引用的使用前言 重新…

工地人员工装穿戴识别系统 opencv

工地人员工装穿戴识别系统通过pythonopencv网络模型AI视频智能分析技术&#xff0c;工地人员工装穿戴识别算法模型可对施工现场人员是否佩戴合规穿戴进行自动识别预警。OpenCV的全称是Open Source Computer Vision Library&#xff0c;是一个跨平台的计算机视觉处理开源软件库&…

堆来咯!!!

堆是什么&#xff1f; 是土堆吗&#xff1f; 那当然不是啦~ 堆是一种被看作完全二叉树的数组。 那么什么是完全二叉树呢&#xff1f; 如果二叉树中除去最后一层节点为满二叉树&#xff0c;且最后一层的结点依次从左到右分布&#xff0c;则此二叉树被称为完全二叉树。 堆的特…

开源自动化测试框架有哪些?怎么选择适合自己的

目录 前言 一、Selenium 二、Appium 三、Robot Framework 四、Cypress 五、TestCafe 六、Nightwatch.js 七、JUnit 八、Pytest 总结&#xff1a; 前言 开源自动化测试框架是现代软件开发和测试领域中不可或缺的一部分。它们使得测试人员能够快速、准确地执行测试用例…