Servlet - Filtering (过滤器))

news/2024/4/29 14:22:35/文章来源:https://blog.csdn.net/qq_34377273/article/details/127244223

@[TOC](Servlet - Filtering (过滤器) )

1. What

1.1 什么是Filter

Servlet过滤器Filter是一个小型的web组件,它们通过拦截请求和响应,以便查看、提取或以某种方式操作客户端和服务器之间交换的数据,实现“过滤”的功能。Filter通常封装了一些功能的web组件,过滤器提供了一种面向对象的模块化机制,将任务封装到一个可插入的组件中, Filter组件通过配置文件来声明,并动态的代理。

1.2 Filter与Interceptor的区别

  • 作用域不同
    过滤器依赖于servlet容器,只能在 servlet容器,web环境下使用
    拦截器依赖于spring容器,可以在spring容器中调用,不管此时spring处于什么环境
  • 细粒度的不同
    过滤器的控制比较粗,只能在请求进来时进行处理,对请求和响应进行包装
    拦截器提供更精细的控制,可以在controller对请求处理之前或之后被调用,也可以在渲染视图呈现给用户之后调用
  • 中断链执行的难易程度不同
    拦截器可以 preHandle方法内返回 false 进行中断
    过滤器就比较复杂,需要处理请求和响应对象来引发中断,需要额外的动作,比如将用户重定向到错误页面

简单总结一下,拦截器相比过滤器有更细粒度的控制,依赖于spring容器,可以在请求之前或之后启动,过滤器主要依赖于servlet,过滤器能做的,拦截器基本上都能做

2. Why

2.1 Filter的作用

它的主要作用就是将请求进行过滤处理然后将过滤后的请求交给下一个资源。其本质是Web应用的一个组成部件,承担了Web应用安全的部分功能,阻止不合法的请求和非法的访问。

2.2 Filter的适用场合

  • 将请求的参数写入日志文件
  • 对于资源的访问进行统一的授权与验证
  • 在请求到达实际Servlet之前格式化请求内容或请求头
  • 压缩返回数据后发送给客户端
  • 修改返回内容,增加一些cookie、header等信息

3. How

3.1 Interface of Filter

public interface Filter {default void init(FilterConfig paramFilterConfig) throws ServletException;void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) throws IOException, ServletException;default void destroy();
}

过滤器是一个实现了javax.servlet.Filter接口的Java类。javax.servlet.Filter接口定义了三个方法:

  • public void init(FilterConfig filterConfig) — web应用程序启动时,web服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,-
    init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
  • public void doFilter (ServletRequest, ServletResponse, FilterChain) — 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
  • public void destroy() — Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

3.2 Filter的工作原理与执行顺序

在这里插入图片描述
Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:

  1. 调用目标资源之前,让一段代码执行;
  2. 是否调用目标资源(即是否让用户访问web资源);
  3. 调用目标资源之后,让一段代码执行。

web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

3.3 Filter的责任链设计

责任链定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

每个Filter过滤器实现javax.servlet.Filter接口,其中包含一个doFilter()方法,该方法接受一个request,resonse以及filterChain作为参数输入,filterChain实现javax.servlet.FilterChain接口(由servlet容器提供),当请求到来时,它将会管理与该请求相关的一系列过滤器的执行,当过滤器执行完毕,doFilter接下来就会调用servlet的service()方法。

责任链模式解决的问题

  • 请求者和接受者松散耦合 — 在责任链模式中,请求者并不知道接受者是谁,也不知道具体如何处理。请求者只负责向责任链发出请求就可以了,该模式下可以有多个接受者处理对象,每个接受者只负责处理自己的部分,其他的就交给其他的接受者去处理。请求在链中传递,接受者处理该请求,或者传递给链中下一个接受者。请求者不再和特定接受者紧密耦合。
  • 通过改变链内成员的或者调整它们的次序,允许你动态地新增或删除责任。

4. Samples

4.1 权限控制

public class AdminFilter implements Filter {private final String[] excludedPathArray = new String[]{"/static/*", "*.html", "*.js", "*.ico", "*.jpg", "*.png", "*.css"};/*** doFilter Dedicated to intercepting requests. Can do permission checking*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;if (!isFilterExcludeRequest(httpServletRequest)) {HttpSession session = httpServletRequest.getSession();Object user = session.getAttribute("user");// If it is equal to null, it means that you are not logged in yetif (user == null) {// TODO do business logic} else {// Let the program continue down to access the user's target resourcefilterChain.doFilter(servletRequest, servletResponse);}}}/*** Determine if the request is directly released by the filter (mainly used for static resource release)** @param request HTTP request* @return boolean*/private boolean isFilterExcludeRequest(HttpServletRequest request) {if (excludedPathArray.length > 0) {String url = request.getRequestURI();for (String excludedUrl : excludedPathArray) {if (excludedUrl.startsWith("*.")) {if (url.endsWith(excludedUrl.substring(1))) {return true;}} else if (excludedUrl.endsWith("/*")) {if (!excludedUrl.startsWith("/")) {excludedUrl = "/" + excludedUrl;}String prefixStr = request.getContextPath() +excludedUrl.substring(0, excludedUrl.length() - 1);if (url.startsWith(prefixStr)) {return true;}} else {if (!excludedUrl.startsWith("/")) {excludedUrl = "/" + excludedUrl;}String targetUrl = request.getContextPath() + excludedUrl;if (url.equals(targetUrl)) {return true;}}}}return false;} 
}

4.2 XM:config Filter by XML

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"><display-name>ServletFilterExample</display-name><filter><filter-name>adminFilter</filter-name><filter-class>com.xxx.AdminFilter</filter-class></filter><filter-mapping><filter-name>adminFilter</filter-name><!--        the rule of filter URL--><url-pattern>/*</url-pattern></filter-mapping></web-app>

4.3 onfig Filter by Java config

@Configuration
@ConditionalOnClass(name = {"org.springframework.web.servlet.config.annotation.WebMvcConfigurer","org.springframework.boot.web.servlet.FilterRegistrationBean"
})
public class FilterConfiguration {@Beanpublic FilterRegistrationBean<Filter> traceableFilter() {FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();registration.setFilter(new AdminFilter());// 设定优先值为最优先registration.setOrder(Integer.MIN_VALUE);return registration;}}

4.4 使用Filter对Token进行拦截验证

对于一些敏感数据,在用户每次请求时,都需要对用户的身份进行验证。这里我们使用JWT的token进行身份认证。

  1. 新定义一个拦截器
public class TokenVerifyFilter extends OncePerRequestFilter
OncePerRequestFilter是由Spring.web提供的一个拦截器,它内部定义了一些列框架需要的数据验证流程。
public abstract class OncePerRequestFilter extends GenericFilterBean {
...@Overridepublic final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws ServletException, IOException {...// Do invoke this filter...request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);try {doFilterInternal(httpRequest, httpResponse, filterChain);} finally {// Remove the "already filtered" request attribute for this request.request.removeAttribute(alreadyFilteredAttributeName);}....}
...
}
  1. 上述代码中,方法doFilterInternal是一个抽象方法,我们需要在自己定义的TokenVerifyFilter实现这个方法。在实现的代码里,添加对token验证的逻辑
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {
...// get token from the requestString tokenString = request.getHeader(Constants.ACCESS_TOKEN);// If the token does not exist, continue to execute the doFilter method in OncePerRequestFilterif (!StringUtils.hasText(tokenString)) {filterChain.doFilter(request, response);return;}...// Execute token verification logictry {varifyToken(tokenString);} catch (Exception e) {... // Other operations: logging, assembly of error message objects returned to the caller, etc.return;}// After the token verification is passed, continue to execute the doFilter method in OncePerRequestFilterfilterChain.doFilter(wrapperRequest, response);
...
}

4.5 使用Filter对marketCode和languageCode进行拦截验证

  1. Define a Filter called MarketCodeAndLanguageCodeFilter
@WebFilter(urlPatterns = "/api/*")
@RequiredArgsConstructor
public class MarketCodeAndLanguageCodeFilter extends OncePerRequestFilter {...
}

@WebFilter(urlPatterns = "/api/") 表示,此拦截器只处理符合正则 /api/ 的 url
@WebFilter(urlPatterns = "/api/") means that this blocker only processes urls that match the regular /api/

  1. 实现 doFilterInternal 方法
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {// Check that marketCode is not empty, otherwise return an error message directlyString marketCode = request.getHeader(MARKET_CODE);if (!MARKET_CODE_LIST.contains(marketCode)) {resolveException(HttpStatus.BAD_REQUEST.value(), MARKET_CODE_INVALID.getStatusCode(),response);return;}// The same logic handles languageCode...// store the marketCode and languageCode to the ContextUtil(it's a thread-local)contextUtil.put(MARKET_CODE, marketCode);contextUtil.put(LANGUAGE_CODE, languageCode);try {// Continue with subsequent operationsfilterChain.doFilter(request, response);} finally {// When the entire request is complete, empty the ContextUtilcontextUtil.clear();}
}

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

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

相关文章

深度神经网络的优化算法,进化算法优化神经网络

有哪些手段可以提升深度神经网络的泛化性能 人工神经网络以其智能性见长&#xff0c;那么神经网络能真的学到一个映射的本质吗&#xff1f;也就是说&#xff0c;对一个映射给出一定的必要的训练样本训练后&#xff0c;网络能否对样本以外的样本给出较为准确的预测。 泛化能力…

概率论与数理统计学习:随机向量(三)——知识总结与C语言实现案例

hello&#xff0c;大家好 这里是第八期概率论与数理统计的学习&#xff0c;我将用这篇博客去总结这期的知识点以及实现用C语言去做题的过程。 本期知识点&#xff1a; 条件分布 条件分布的概念离散型随机变量的条件概率分布连续型随机变量的条件概率密度 随机变量的独立性 那…

ROS学习笔记三(TF的类)

1.数据类型 数据类型定义在tf/transform_datatypes.h.里 1.1 基本数据类型(Quaternion, Vector, Point, Pose, Transform) TypetfQuaterniontf::QuaternionVectortf::Vector3Pointtf::PointPosetf::PoseTransformtf::Transform 1.2 tf::Stamped tf::Stamped在上面的数据类型…

RocketMQ 5.0:无状态代理模式的探索与实践

本文作者&#xff1a;金吉祥&#xff0c; Apache RocketMQ PMC Member&#xff0c;阿里云智能高级技术专家 背景 首先&#xff0c;让我们来看下是遇到了哪些痛点问题&#xff0c;促使我们去探索一种无状态代理的RocketMQ新架构的&#xff1b; RocketMQ 拥有一套极简的架构&am…

安卓投屏 QtScrcpy

一、电脑安装adb 版本大于1.0.40以上 40不行 adb 1.0.41下载链接 链接&#xff1a;https://pan.baidu.com/s/1WIPI-p7a4ErTLFYHaTC2kw?pwdadbt 提取码&#xff1a;adbt 安装参考 https://blog.csdn.net/M7_xbc/article/details/122957311 二、打开无线调试并且配对 手机打…

驱动开发(10/10-林雪阵)

终端输入1--->LED1点亮 终端输入2--->LED2点亮 终端输入3--->LED3点亮 终端输入0--->LED熄灭 chdev.c (底层驱动代码&#xff09; #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h>…

【webrtc】rtp 扩展头的ID

ietf 文档地址扩展头的uri 是固定的,因此识别扩展是通过uri地址,而非ID。rtp 扩展头是有个ID的 文档的说法 : 是本地的id,15保留,只可以小于15 本地标识符值 15 保留用于将来的扩展和 不得用作标识符。如果 ID 值 15 是 遇到,它的长度字段应该被忽略,处理 整个扩展应在该…

redis之AOF和RDB持久化

写在前面 因为redis数据是基于内存的&#xff0c;为了避免服务器重启或者是宕机导致数据全部丢失&#xff0c;提供了数据持久化机制&#xff0c;即AOF(Append Only File)日志和RDB快照&#xff0c;接下来我们分别看下。 1&#xff1a;AOF 1.1&#xff1a;AOF日志的实现 首先…

(附源码)计算机毕业设计SSM政府项目管理平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

回顾——PCB绘制

目录 一、原理图库原理图 二、PCB库 三、PCB 一、原理图库原理图 新建工程&#xff1a;文件——New——Project——Name&#xff08;这里复制一下&#xff09;自己选择保存路径 添加文件&#xff1a; 保存工程&#xff1a;(粘贴) 绘制原理图库、原理图 侧边栏消失&…

虚拟社会、区块链和元宇宙

1986年&#xff0c;早期的互联网供应商Quantum Link和娱乐公司Lucasfilm Games发布了第一款MMO游戏名为&#xff1a;《Habitat》基于虚拟角色的社交世界&#xff0c;玩家可以通过300波特的调制解调器(每分钟0.08美元)和用户的Commodore 64(595美元&#xff0c;按今天的价格约为…

Vue 动态换肤

效果如图&#xff1a; 源代码&#xff1a; <template><div :class"[son${temp}]" class"demo3">这是四点零八分的北京<br/>一片手的海浪翻动<br/>这是四点零八分的北京<br/>一声雄伟的汽笛长鸣<br/>北京车站高大的建…

Kafka监控EFAK(Kafka-eagle)部署与踩坑详细记录

环境 阿里云服务器centoskafka 2.4.1 &#xff08;1.1以上版本都能支持&#xff0c;低版本不太清楚了&#xff09;efak 3.0.1 当前时间官网下载的最新版&#xff08;原名叫kafka-eagle&#xff09;efak官网&#xff1a;http://www.kafka-eagle.org/jdk8 部署好的UI 部署流程 …

kafka系列——安装部署,相关命令,配置文件,底层存储结构,log和index文件

点击上方“罗晓胜”&#xff0c;马上关注&#xff0c;您的支持对我帮助很大 / 前言 / Kafka是最初由Linkedin公司开发&#xff0c;用scala语言编写的&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的&#xff08;replica&#xff09;&…

时光机特效在哪里?推荐这三个实用软件给你

现如今有一款时光穿梭机的特效软件非常热门&#xff0c;它具有让照片中的人变年轻或者变老的功能&#xff0c;能让我们看到过去以及未来自己的样子&#xff0c;也能给我们枯燥的生活增添一点趣味感。那么大家是不是已经迫不及待地想知道时光穿梭机特效滤镜在哪了呢&#xff1f;…

Linux学习 -- docker的commit命令和本地镜像到云端

commit命令本地镜像到云端 一、commit命令 我们在使用镜像新建容器后&#xff0c;容器只是具有简易的Linux的功能&#xff0c;不具备一些常用的功能&#xff0c;如vim功能&#xff0c;因此我们需要给容器加上一些我们需要的功能。 使用如下命令&#xff1a; docker commit提交容…

不使用第三方库怎么实现【前端引导页】功能?

前言 随着应用功能越来越多&#xff0c;繁多而详细的功能使用和说明文档&#xff0c;已经不能满足时代追求 快速 的需求&#xff0c;而 引导页&#xff08;或分步引导&#xff09; 本质就是 化繁为简&#xff0c;将核心功能以更简单、简短、明了的文字指引用户去使用对应的功能…

Oracle数据库 | SQL语句解析

个人主页&#xff1a;&#x1f497;wei_shuo的个人主页 &#x1f3c0; Hello World &#xff01;&#x1f3c0; 文章目录一.Oracle启动及登录1.1 服务手启动即关闭1.2 SQL* PLUS命令二. 表的创建和维护2.1 创建表2.2 修改表2.3 重命名表2.4 截断表2.5 删除表三. 数据完整性与约…

【C++学习】类与对象(中)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 类与对象&#xff08;中&#xff09;&#x1f638;构造函数&#x1f639;概念&#x1f639;特性&…

常见数据结构-散列表(上)理论

一&#xff0c;散列表理解 散列表的英文叫“Hash Table”&#xff0c;我们平时也叫它“哈希表”或者“Hash 表”&#xff0c;散列表用的是数组支持按照下标随机访问数据的特性&#xff0c;所以散列表其实就是数组的一种扩展&#xff0c;基于数组演化而来。 散列表是通过散列函…