likes
comments
collection
share

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

作者站长头像
站长
· 阅读数 7

在上一篇的文章中,我们讲到了javaweb的servlet,Servlet在最早的JAVA网页应用发过程中占据着很重要的地位。但是在这个体系中,还存在着两个极其相似的亲兄弟。今天我们就来介绍一下这两个很相似的功能。

过滤器和拦截器都是用于在 Web 应用程序中处理请求和响应的组件,但它们在实现和使用上有一些不同之处。

过滤器(Filter)是 Servlet 规范中的一部分,它可以在请求到达 Servlet 之前对请求进行预处理,也可以在响应返回给客户端之前对响应进行后处理。过滤器可以用于实现诸如日志记录、字符编码转换、安全控制等功能。过滤器的配置是在 web.xml 文件中进行的。

拦截器(Interceptor)通常是在框架层面上使用的,比如在 Spring 框架中。拦截器也可以在请求处理前后进行处理,但它们更多地用于实现横切关注点(cross-cutting concerns)的功能,比如事务管理、日志记录、性能监控等。拦截器的配置通常是在框架的配置文件中进行的。

总的来说,过滤器是 Servlet 规范中的一部分,用于处理 Web 应用程序的请求和响应,而拦截器通常是在框架层面上使用,用于实现横切关注点的功能。

搭建过滤器

第一步,我们新建一个spring boot项目

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

pom文件的内容如下,大家可以根据自己本地jdk的版本选择合适的spring boot版本,这里博主演示的是spring boot 3.2.0的版本。JDK的版本是17。因为到这篇文章发布的时候,官方的Spring boot脚手架最低支持的jdk版本是17。这意味着jdk17这个版本将会是以后的主流版本,所以我们也顺应时代的潮流。使用jdk17版本。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.masiyi</groupId>
    <artifactId>filter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>filter</name>
    <description>filter</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

第二步,新建controller层接口

package com.masiyi.filter.test;
 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/filter")
public class MyController {
 
	@RequestMapping("/test")
	public String test1(String a) {
		System.out.println("_Controller_test1:" + a);
		return "test1";
	}
	
}

这个类的作用就是为了我们能通过HTTP的方式去调用到我们服务里面的方法,相信大家都有一定的基础了解这个类的作用,这里就不在赘述了。

第三步,新建filter过滤器

package com.masiyi.filter.test;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @Author masiyi
 * @Date 2023/12/6
 * @PackageName:com.masiyi.filter
 * @ClassName: MyFilter
 * @Description: TODO
 * @Version 1.0
 */

@WebFilter(urlPatterns = "/myFilter/*")
public class MyFilter implements Filter {
    /**
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 在这里编写过滤器的逻辑
        // 可以对请求进行处理,然后调用 chain.doFilter(request, response) 继续执行过滤链
        chain.doFilter(request, response);
    }
    /**
     *
     */
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

通过 @WebFilter(urlPatterns = "/myFilter/*") 注解,指定了该过滤器的 URL 匹配模式为 "/myFilter/",即对以 "/myFilter/" 开头的 URL 进行过滤。在 doFilter 方法中,可以编写过滤器的逻辑,对请求进行处理,然后调用 chain.doFilter(request, response) 继续执行过滤链,以便其他过滤器或 Servlet 对请求进行处理。init 方法用于初始化过滤器,在这里可以进行一些初始化操作。destroy 方法在过滤器被销毁时调用,可以在这里进行一些资源释放等清理操作。

这里值得注意的一点就是如果说我们jdk版本足够的高,那么我们就不能用javax里面的包。而是应该使用jakarta这个里面的包。否则就会出现过滤器不生效的情况。

第四步,启用断点调试功能

init方法

我们在init方法里面打一个断点,然后启动我们的主启动类。我们就能发现服务在进行启动的过程中,首先进入到我们init方法里面。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

doFilter方法

我们首先在这个方法里面打一个断点。之后执行我们的请求。但是这个时候大家就会发现一个奇怪的地方。发现doFilter方法方法根本没有进来。这其实也是在意料之中的事情。因为我们的配置路径里面没有包含这个filter/test这个路径。他并没有匹配到我们的表达式,所以说他其实并没有进入到我们的doFilter方法方法。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

这个时候我们把我们的请求改为这样myFilter/test就会发现他已经成功进入到我们的doFilter方法方法。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

destroy方法

为了验证我们的这个方法,我们可以在方法体里面打印一段文本,之后我们把这个程序关闭的时候就会发现控制台已经成功把这个销毁打出来了。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

过滤器通常用于以下场景:

  1. 身份验证和授权:过滤器可以用于验证用户的身份并控制其访问权限,例如检查用户是否已登录或是否具有特定的角色或权限。例如在doFilter方法里面直接return出去,他就不会调用我们的服务里面的信息。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

  1. 日志记录和性能监控:过滤器可以记录请求和响应的信息,用于监控应用程序的性能和行为。我们同样可以在doFilter的方法里面记录日志。

  2. 数据转换和格式化:过滤器可以对请求或响应的数据进行转换、格式化或加工,例如压缩响应数据或解析请求参数。在doFilter的方法里面,我们可以拿到request跟response。这样的话,我们就能对他们进行一些编辑。

介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器

  1. 异常处理:过滤器可以捕获请求处理过程中的异常,并进行相应的处理或记录。

  2. 安全防护:过滤器可以用于防范常见的安全威胁,如 XSS(跨站脚本攻击)和 CSRF(跨站请求伪造)。

过滤器通过实现 javax.servlet.Filter 接口来定义(高版本的换成了我上面说过的jar包),它可以拦截请求和响应,并在执行特定任务后将请求传递给下一个过滤器或目标 Servlet。这使得过滤器成为实现横切关注点的理想选择。至此我们已经学会了如何使用过滤器来实现请求的过滤,下一篇文章我们来学习一下拦截器,看一下这两者的差距到底在哪。