当前位置: 首页 > news >正文

Spring MVC 拦截器 (HandlerInterceptor) 是什么? 它与 Servlet Filter 有什么区别?

Spring MVC 拦截器 (HandlerInterceptor) 是 Spring Web MVC 框架提供的一种机制,在请求处理的特定阶段插入自定义逻辑。它主要用于预处理和后处理 Controller (Handler) 的请求。

Spring MVC 拦截器 (HandlerInterceptor) 是什么?

HandlerInterceptor 是一个接口,它定义了三个主要的回调方法,在请求生命周期的不同点进行干预:

  1. preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):

    • 调用时机: 在 Controller 方法 (Handler) 执行之前调用。
    • 返回值:
      • true: 请求会继续向下执行,传递给下一个拦截器或最终的 Handler。
      • false: 请求处理流程被中断,不会执行后续的拦截器和 Handler。此时,需要自己负责生成响应 (例如,通过 response.getWriter().write(...))。
    • 用途: 权限校验、日志记录、参数预处理、请求合法性检查等。
  2. postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):

    • 调用时机: 在 Controller 方法 (Handler) 执行之后,但在 DispatcherServlet 渲染视图之前调用。
    • 参数 modelAndView 包含了 Handler 返回的模型数据和视图信息。我们可以在这里修改 ModelAndView
    • 注意: 如果 Handler 方法执行过程中抛出异常,则此方法不会被调用。
    • 用途: 修改模型数据、添加公共数据到模型、修改视图名称、记录操作日志(此时可以获取到Handler处理结果的一些信息)。
  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):

    • 调用时机: 在整个请求处理完成之后,即 DispatcherServlet 渲染视图之后调用。通常在视图渲染完毕后执行,用于资源清理。
    • 参数 ex 如果 Handler 执行过程中或视图渲染过程中抛出了异常,ex 会包含该异常对象,否则为 null
    • 注意: 无论 Handler 方法是否成功执行或是否抛出异常,此方法总是会被调用 (前提是 preHandle 返回 true)。
    • 用途: 资源清理、异常日志记录、性能监控(记录整个请求处理时间)。

HandlerInterceptor 与 Servlet Filter 的区别:

特性Servlet Filter (javax.servlet.Filter)Spring MVC HandlerInterceptor (org.springframework.web.servlet.HandlerInterceptor)
作用范围基于 Servlet 规范,作用于 Servlet 容器级别。可以拦截所有进入 Servlet 的请求,不限于 Spring MVC。仅作用于 Spring MVC 的 DispatcherServlet 处理的请求。它位于 DispatcherServlet 内部的请求处理链中。
依赖依赖 Servlet API。依赖 Spring MVC 框架。
调用时机DispatcherServlet 之前(或之后,取决于 Filter Chain 的配置顺序)。DispatcherServlet 接收到请求后,但在调用具体的 Controller (Handler) 之前、之后和完成时。
可获取信息只能获取到原始的 HttpServletRequestHttpServletResponse可以获取到 Spring MVC 上下文中的信息,例如将要执行的 Handler (Controller 方法)、ModelAndView 等。
控制粒度相对粗粒度,通常用于全局性的任务,如编码转换、安全过滤。更加细粒度,可以针对特定的 Handler 或 URL 模式进行拦截,能更深入地参与到 Spring MVC 的请求处理流程中。
异常处理Filter 的 doFilter 方法需要自己处理异常,或向上抛出。postHandle 不会在 Handler 抛异常时调用,但 afterCompletion 始终会被调用,并可以获取到异常信息。
与Spring集成可以通过 FilterRegistrationBean 在 Spring Boot 中注册,但本质上仍是 Servlet 规范的一部分。是 Spring MVC 的核心组件,与 Spring IoC 容器紧密集成,可以方便地注入其他 Spring Bean。

简单来说:

  • Filter 更底层,更通用,作用范围更广,适合做一些与具体框架无关的通用处理。
  • Interceptor 更贴近 Spring MVC,更精细,能访问到更多 Spring MVC 的内部信息,适合做与 Spring MVC 请求处理流程相关的特定逻辑。

如何定义和注册拦截器?

  1. 定义拦截器 (实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter (已废弃,推荐直接实现接口)):

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;@Component // 将拦截器注册为一个Bean,如果需要在拦截器中注入其他Bean
    public class MyCustomInterceptor implements HandlerInterceptor {private static final Logger logger = LoggerFactory.getLogger(MyCustomInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {logger.info("MyCustomInterceptor: PreHandle - URL: {}", request.getRequestURI());// 示例:简单的权限校验String token = request.getHeader("Authorization");if (token == null || !isValidToken(token)) {logger.warn("MyCustomInterceptor: PreHandle - Unauthorized access to {}", request.getRequestURI());response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("Unauthorized - Invalid or missing token.");return false; // 中断请求}return true; // 继续执行}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {logger.info("MyCustomInterceptor: PostHandle - Handler: {}", handler.getClass().getSimpleName());if (modelAndView != null) {modelAndView.addObject("interceptorMessage", "Message added by interceptor!");logger.info("MyCustomInterceptor: PostHandle - Added data to ModelAndView for view: {}", modelAndView.getViewName());}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {logger.info("MyCustomInterceptor: AfterCompletion - Request completed.");if (ex != null) {logger.error("MyCustomInterceptor: AfterCompletion - Exception occurred: ", ex);}}private boolean isValidToken(String token) {// 实际的token校验逻辑return token.startsWith("Bearer valid-");}
    }
    
  2. 注册拦截器 (通过实现 WebMvcConfigurer 接口):

    这是在 Spring Boot 和现代 Spring MVC Java 配置中最常见的方式。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
    public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate MyCustomInterceptor myCustomInterceptor; // 注入自定义拦截器Bean// 如果你的拦截器没有被@Component注解,或者你想在这里new一个实例,也可以:// private final MyCustomInterceptor myCustomInterceptor = new MyCustomInterceptor();@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myCustomInterceptor).addPathPatterns("/api/**", "/secure-area/**") // 指定拦截的URL模式 (Ant-style).excludePathPatterns("/api/public/**", "/login", "/error") // 指定排除的URL模式.order(1); // 可选,指定拦截器的执行顺序,数字越小优先级越高// 可以注册多个拦截器// registry.addInterceptor(new AnotherInterceptor())//         .addPathPatterns("/admin/**")//         .order(0);}
    }
    

    注意:

    • addPathPatterns("/**"): 拦截所有请求。
    • excludePathPatterns(...): 排除某些路径不被拦截。
    • order(int order): 如果有多个拦截器,可以通过 order 来指定它们的执行顺序。preHandle 会按顺序执行,postHandleafterCompletion 会按相反的顺序执行。

拦截器可以用来做什么?

拦截器因其能够在请求处理的关键点介入,具有广泛的应用场景:

  1. 权限认证与授权:

    • preHandle 中检查用户是否登录,是否有访问特定资源的权限。如果无权限,则返回 false 并设置相应的响应状态码或重定向到登录页面。
  2. 日志记录:

    • preHandle: 记录请求的URL、参数、来源IP等。
    • postHandle: 记录Handler处理结果、返回的视图等。
    • afterCompletion: 记录整个请求的处理耗时、异常信息等。
  3. 性能监控:

    • preHandle 中记录开始时间,在 afterCompletion 中计算总耗时。
  4. 统一添加数据到模型:

    • postHandle 中向 ModelAndView 添加所有页面都需要用到的公共数据,如网站名称、当前用户信息等。
  5. 国际化与本地化:

    • 根据请求参数或Session信息,在 preHandle 中设置当前的 Locale
  6. 防止重复提交:

    • preHandle 中生成并校验Token,防止用户重复提交表单。
  7. 请求参数预处理或校验:

    • preHandle 中对请求参数进行一些预处理或基础校验。
  8. 请求上下文设置/清理:

    • 使用 ThreadLocalpreHandle 中设置一些请求相关的上下文信息,在 afterCompletion 中清理。
  9. API版本控制:

    • 根据请求头或路径信息,在 preHandle 中将请求路由到不同版本的API处理器。

Spring MVC 拦截器提供了灵活的方式来对Web请求进行横切点的处理,使得Controller可以更专注于核心业务逻辑。

相关文章:

  • Python模块化编程
  • 检测按键抖动的时间
  • groovy 如何遍历 postgresql 所有的用户表 ?
  • pytest框架 - 第二集 allure报告
  • 关于xammp数据库打开不了,但是日志没错误的问题解决以及其数据库的备份
  • 广度和深度优先搜索(BFS和DFS)
  • 国产芯片LH001-91为什么可以代替TI的ADS1291?
  • 【沉浸式求职学习day40】【java面试题精选2】
  • 哈夫曼树完全解析:从原理到应用
  • 如何使用易路iBuilder智能体平台快速安全深入实现AI HR【实用帖】
  • 设置WDA_EXCLUDEFROMCAPTURE 无效的原因
  • doris节点数量规划
  • 无人机屏蔽与滤波技术模块运行方式概述!
  • Kind方式部署k8s单节点集群并创建nginx服务对外访问
  • 代码随想录算法训练营第四十一天
  • vite运行只能访问localhost解决办法
  • [Harmony]封装一个可视化的数据持久化工具
  • 蓝桥杯12届国B 123
  • 数据结构——例题2
  • [数据结构]8. 树-Tree
  • 降水较常年同期少五成,安徽四大水利工程调水超11亿方应对旱情
  • 因存在安全隐患,福特公司召回约27.4万辆SUV
  • 广东早熟荔枝“抢滩”上海,向长三角消费者喊话:包甜,管够
  • 美国三大指数全线高开:纳指涨逾4%,大型科技股、中概股大涨
  • 甘肃:今年6月前,由县级党委、政府制定农村彩礼倡导性标准
  • 来伊份深夜回应“粽子中吃出疑似创可贴”:拿到实物后会查明原因