拦截器和过滤器(理论+实操)

拦截器和过滤器

本文旨在夯实基础以及实战加深理解,目的是更深的理解以便掌握,希望能跟着动手敲一遍,绝对受益匪浅

在本文,我会先给出两者的区别(理论知识),随后是两者各自的实操实现

文章目录

什么是过滤器和拦截器?

1.过滤器

首先说下什么是过滤器?

  1. Java Servlet规范中定义的标准 ,是Servlet一部分,
  2. 配置也是非常简单 ,直接实现javax.servlet.Filter接口就可以,
  3. 也可以用注解 @WebFilter对特定的URL拦截

2.拦截器

那拦截器又是什么东东?

  1. Spring框架自身 提供的组件,也就是说必须依赖SpringMvc框架才能使用,是位于Spring上下文之中
  2. AOP的一种实现,支持链式调用 ,通过类HandlerInterceptor实现多个拦截
  3. 说白了:就是切面编程 典型实现,允许程序猿在一些核心业务 操作执行的前后 插入自定义的逻辑代码,如日志记录,权限认证等,而无需修改核心代码的本身

执行整体流程

我们首先看下过滤器和拦截器在整个流程中的执行顺序
请求进入 preHandle 调用Controller 返回ModelAndView postHandle/afterCompletion 返回响应 响应返回 HTTP Request Tomcat 容器 Filter 链 DispatcherServlet Interceptor 链 Controller HTTP Response

解释说明:(结合上图)

  1. Filter 开始HTTP 请求进入 Tomcat 容器。
  2. Filter 链处理 :请求会经过所有配置的 FilterdoFilter() 方法。
  3. 进入 Spring MVC :请求到达 DispatcherServlet(Spring MVC 的核心控制器)。
  4. Interceptor 开始DispatcherServlet 分发请求前,会先执行拦截器链的 preHandle 方法。
  5. Controller 执行 :如果 preHandle 返回 true,请求被分发到对应的 Controller 方法执行。
  6. Interceptor 后处理
    • Controller 执行完毕后,返回 ModelAndView,然后执行拦截器链的 postHandle 方法。
    • 视图渲染完毕后(或请求处理完成后),执行拦截器链的 afterCompletion 方法。
  7. Filter 结束 :响应最终再次经过 Filter 链的 doFilter() 方法(反向),返回给客户端。

拦截器和过滤器的区别

特性 过滤器 (Filter) 拦截器 (Interceptor)
归属与依赖 Servlet 规范,不依赖 Spring Spring 框架 的组件
作用范围 作用于所有进入容器的请求(包括静态资源,如 /css/, /js/ 只作用于 Spring MVC 处理的请求(即 Controller 的请求,通常不会拦截静态资源)
实现原理 基于 函数回调 (doFilter()) 基于 Java 反射和动态代理
使用方式 web.xml 中配置或使用 @WebFilter 注解 在 Spring MVC 配置中注册 (WebMvcConfigurer)
获取 IOC 容器 无法 直接获取 Spring 的 IOC 容器和其中的 Bean 可以 ,因为它本身就是 Spring 管理的,可以轻松使用 @Autowired 注入其他 Bean
执行时机/位置 最早 。 1. 在请求进入 Tomcat 等容器 之后 2. 在进入 Servlet 之前 3. 在 Servlet 处理完之后,返回给客户端之前 较晚 。 1. 在请求进入 DispatcherServlet 之后 2. 在进入 Controller 之前 (preHandle ) 3. 在 Controller 执行之后,视图渲染之前 (postHandle ) 4. 在整个请求结束之后 (afterCompletion)
功能侧重 更底层,关注的是请求本身(Request/Response),功能强大。 例如:字符编码设置、权限校验(粗粒度)、日志记录、性能监控、解压/gzip压缩。 更上层,关注的是 Controller 的方法执行,与业务结合更紧密。 例如:更精细的权限校验(判断Token、角色)、日志记录(记录Controller方法、参数)、参数预处理、Controller 执行时间计算。

实操:

1.过滤器

案例:Springboot中实现日志记录过滤器

1.定义日志记录过滤器类LogFilter

主要的三大核心 方法:(可以结合上面的整体执行流程图来看)

  • init() :该方法在容器启动初始化 过滤器时被调用 ,在 Filter 的整个生命周期只会被调用一次注意 :这个方法必须执行成功,否则过滤器不生效,没有作用。
  • doFilter() :容器中的每一次请求 都会调用该方法, FilterChain 用来调用下一个 过滤器 Filter
  • destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次
java 复制代码
package com.zhengqian.test01aop.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 日志过滤器: 
 * @author zhengqian
 * @since 2025年09月04日 14:56
 */
@WebFilter(urlPatterns = "/*")//过滤所有的请求
@Slf4j
public class LogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        //初始化执行
        log.info("***^^^日志过滤器初始化完成");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //记录请求的开始时间
        long startTime = System.currentTimeMillis();
        //转换为HttpServletRequest获取更多信息
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        //获取基本信息
        String requestURI = httpServletRequest.getRequestURI();
        String method = httpServletRequest.getMethod();
        String remoteAddr = httpServletRequest.getRemoteAddr();
        //
        log.info("请求开始=> 方法:{} 路径: {}} IP:{}",method,requestURI,remoteAddr);

        try {
            filterChain.doFilter(servletRequest,servletResponse);
        } finally {
            //计算处理耗时
            long duration = System.currentTimeMillis() - startTime;
            //响应日志
            log.info("请求结束 ==> 路径: {} 耗时:{}",requestURI,duration);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
        log.info("日志过滤器销毁");
    }
}
2.在主启动类上添加注解 @ServletComponentScan

OK!这个时候你启动就可以看到此过滤器成功!

你可能会问?这么简单?对的,就是这么简单!前提你要跟着做!哈哈哈!

2.拦截器

1.创建拦截器

核心方法解释:

  • preHandle()
    • 此方法在请求处理之前进行调用。
    • 注意 :如果该方法的返回值为false ,将视为当前请求结束 ,不仅自身拦截器 会失效,还会导致其他的拦截器也不再执行
  • postHandle()
    • 只有在 preHandle() 方法返回值为true才会执行
    • 会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。
  • afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束 之后, DispatcherServlet 渲染了对应的视图之后执行。
java 复制代码
package com.zhengqian.test01aop.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 自定义拦截器的实现
 * @author zhengqian
 * @since 2025年09月04日 15:13
 */
@Slf4j
public class CustomInterceptor implements HandlerInterceptor {



    /**
     * 请求处理前被调用
     * @param request 请求
     * @param response 响应
     * @param handler 处理器
     * @return  aa
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //添加校验权限
        log.info("开始出发拦截器校验前的处理------------->");
        return true;
    }

    /**
     * **其中**:`postHandle()` 方法被调用的顺序跟 `preHandle()` 是**相反**的,先声明的拦截器  `preHandle()` 方法先执行,而`postHandle()`方法反而会后执行。
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("只有在 preHandle() 方法返回值为true 时才会执行");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("整个请求结束之后被调用");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }


}
2.注册拦截器

addPathPatterns:需要拦截的路径

excludePathPatterns: 不需要拦截的路径

java 复制代码
package com.zhengqian.test01aop.config;

import com.zhengqian.test01aop.interceptor.CustomInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author zhengqian
 * @since 2025年09月04日 15:19
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器并设置拦截路径
        registry.addInterceptor(new CustomInterceptor())
            	//拦截所有
                .addPathPatterns("/**")
            	//排除*/login的登录路径
                .excludePathPatterns("/aop/login");
    }
}
测试

我们建一个测试类,来进行上面的拦截测试

java 复制代码
package com.zhengqian.test01aop.controller;

import com.zhengqian.test01aop.service.TestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author zhengqian
 * @date 2025年07月21日 16:40
 */
@RestController
@RequestMapping("/aop")
public class TestController {
    @Resource
    TestService testService;

    @GetMapping("/test")
    public  String test(){
        testService.test();
        return "测试成功!----";
    }

    @GetMapping("/login")
    public  String login(){
        testService.test();
        return "测试成功!----";
    }
}

打印日志:

1.走拦截器


好了,你学会没?

相关推荐
半夏陌离4 小时前
SQL 入门指南:排序与分页查询(ORDER BY 多字段排序、LIMIT 分页实战)
java·前端·数据库
CUIYD_19894 小时前
Eclipse 常用搜索功能汇总
java·ide·eclipse
野犬寒鸦5 小时前
力扣hot100:相交链表与反转链表详细思路讲解(160,206)
java·数据结构·后端·算法·leetcode
ytadpole6 小时前
揭秘设计模式:工厂模式的五级进化之路
java·设计模式
计算机毕业设计木哥6 小时前
计算机毕设选题:基于Python+Django的B站数据分析系统的设计与实现【源码+文档+调试】
java·开发语言·后端·python·spark·django·课程设计
失散136 小时前
分布式专题——1.2 Redis7核心数据结构
java·数据结构·redis·分布式·架构
用户3721574261356 小时前
Python 实现 HTML 转 Word 和 PDF
java
a587696 小时前
Java核心概念精讲:TCP与UDP的区别、Java NIO的几个核心组件与HTTP和HTTPS的区别等(46-50)
java·面试·nio
渣哥7 小时前
ConcurrentHashMap 的 get 要不要加锁?一次“多此一举”的心路历程
java