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

spring MVC 拦截器

一、Spring MVC拦截器的作用

拦截器是Spring MVC框架中处理 HTTP请求 的一种机制,通常用于在请求到达 控制器(Controller) 之前或从控制器返回结果之后进行额外的逻辑处理。可以用于以下场景:

  • 日志记录:记录每次请求的开始时间、结束时间、请求的参数、响应的结果等。
  • 认证和授权:在请求处理之前,检查用户的身份和权限。
  • 统一异常处理:捕获请求处理中的异常,并返回统一的错误响应。
  • 性能监控:记录请求处理的时间。
  • 请求修改:在请求被控制器处理之前,修改请求数据。

拦截器的定义要分为两个部分:

  • 拦截器核心实现:通过实现 HandlerInterceptor 接口定义拦截器的三大核心方法(preHandlepostHandleafterCompletion),实现请求拦截的核心逻辑。
  • 拦截器注册配置:通过实现 WebMvcConfigurer 接口的 addInterceptors() 方法,将拦截器注册到应用中,并指定拦截规则(路径、排除路径等)

二、拦截器核心实现

通过实现 HandlerInterceptor 接口,定义具体的拦截逻辑,包括请求预处理、方法后处理以及请求完成后的清理操作。对应的三个方法是:

  1. preHandle():在请求进入控制器方法之前执行。如果返回 false,则请求不会继续执行控制器方法;如果返回 true,则请求继续执行。
  2. postHandle():在控制器方法执行之后,但在视图渲染之前执行。可以对返回的数据进行修改。
  3. afterCompletion():在整个请求结束(即视图渲染完成)之后执行,通常用于资源清理等操作。

以上三个方法的重写都在实现HandlerInterceptor 接口的类中进行重写,如下面例子中的MyInterceptor类。

示例代码 

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 请求预处理逻辑
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 请求后处理逻辑
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成后的清理操作
    }
}

1. preHandle() 方法

方法签名

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

参数说明

  • HttpServletRequest request:表示当前的HTTP请求对象,通过这个对象可以获取请求的各种信息,如请求的URL、请求头、请求参数、请求体等。
  • HttpServletResponse response:表示当前的HTTP响应对象,可以通过这个对象设置响应的状态码、响应头或直接写出响应数据。
  • Object handler:表示当前要执行的处理器(通常是一个 Controller 方法)。通过这个参数你可以获取到处理这个请求的目标方法和类。

常见参数使用

  • request.getMethod():获取请求方法(GET、POST等)。
  • request.getRequestURI():获取请求的URI,通常用于判断请求路径。
  • response.setStatus():设置HTTP响应状态码,比如 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED) 设置为未授权状态码。
  • handler.getClass():通过 handler 对象获取处理当前请求的控制器类。

preHandle() 示例

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 获取请求的URI
    String uri = request.getRequestURI();
    System.out.println("Request URI: " + uri);

    // 检查用户是否已登录
    String token = request.getHeader("Authorization");
    if (token == null || !isValidToken(token)) {
        // 如果未登录,返回401未授权状态,并中止请求
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }

    // 如果用户已登录,允许继续处理请求
    return true;
}

private boolean isValidToken(String token) {
    // 模拟Token验证逻辑
    return "valid_token".equals(token);
}
  • request.getRequestURI():获取请求的URL路径,用于日志记录或路径匹配。
  • response.setStatus(HttpServletResponse.SC_UNAUTHORIZED):设置未授权响应状态码,当Token无效时直接返回,不继续执行控制器。
  • return true:表示请求可以继续执行,控制器方法将被调用。如果返回 false,请求不会进入控制器。

2. postHandle() 方法

方法签名

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;

参数说明

  • HttpServletRequest request:与 preHandle() 中的请求对象相同,允许你访问请求中的数据(如参数、头部信息等)。
  • HttpServletResponse response:与 preHandle() 中的响应对象相同,允许你在控制器方法执行完后修改响应(如设置响应头)。
  • Object handler:与 preHandle() 中的 handler 相同,表示处理请求的控制器方法。
  • ModelAndView modelAndView:表示控制器方法返回的视图和数据模型。在视图渲染之前,允许你修改返回的数据或视图。如果控制器方法返回 null,表示没有返回视图。

常见参数使用

  • modelAndView.addObject():可以向返回的模型中添加额外的数据。
  • response.addHeader():可以在响应中添加自定义的头部信息。
  • handler.getClass():获取控制器类的信息,用于日志记录等操作。

postHandle() 示例

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    // 检查是否有ModelAndView对象
    if (modelAndView != null) {
        // 在模型中添加一个全局信息
        modelAndView.addObject("globalMessage", "This is a global message for all views");
    }

    // 添加自定义响应头
    response.addHeader("X-Custom-Header", "PostHandleExample");

    // 记录处理器的类名和方法
    System.out.println("Handler class: " + handler.getClass().getSimpleName());
}
  • modelAndView.addObject():向返回的视图模型中添加一个全局变量,所有视图中都可以使用这个变量。
  • response.addHeader():在响应中添加一个自定义头部信息。
  • handler.getClass().getSimpleName():获取处理当前请求的控制器类名,用于日志记录或调试。

3. afterCompletion() 方法

方法签名

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;

参数说明

  • HttpServletRequest request:与 preHandle()postHandle() 中的请求对象相同,允许你在请求完成后访问请求信息。
  • HttpServletResponse response:与 preHandle()postHandle() 中的响应对象相同,允许你在请求完成后对响应做最后的处理。
  • Object handler:与 preHandle()postHandle() 中的 handler 相同,表示处理当前请求的控制器方法。
  • Exception ex:表示请求处理过程中可能抛出的异常。如果控制器方法或其他部分抛出了异常,ex 参数就会包含这个异常信息;如果没有异常,exnull

常见参数使用

  • request.getAttribute():从请求对象中获取之前设置的属性,比如在 preHandle() 中设置的时间戳,用于计算请求处理时间。
  • ex != null:检查是否有异常,如果有异常则记录异常信息或进行相应处理。
  • response.getStatus():获取响应的状态码,比如检查是否返回了500或其他错误状态码。

afterCompletion() 示例

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    // 获取请求处理时间
    Long startTime = (Long) request.getAttribute("startTime");
    long endTime = System.currentTimeMillis();
    long executionTime = endTime - startTime;

    // 记录请求的处理时间
    System.out.println("Request URI: " + request.getRequestURI());
    System.out.println("Execution Time: " + executionTime + "ms");

    // 检查是否有异常
    if (ex != null) {
        System.out.println("Request raised exception: " + ex.getMessage());
    }

    // 可以在此处清理资源或执行其他必要操作
}
  • request.getAttribute("startTime"):从请求对象中获取 preHandle() 中设置的开始时间属性,用来计算整个请求的处理时间。
  • ex != null:检查是否有异常,如果请求过程中抛出了异常,记录异常信息。
  • response.getStatus():可以获取HTTP响应的状态码,检查是否返回了错误状态码(如500,404等)。

4.三个方法的执行流程

  1. preHandle():请求进入控制器之前执行。如果返回 false,请求将被终止,不会继续执行控制器方法;如果返回 true,则继续执行控制器方法。
  2. 控制器方法执行:如果 preHandle() 返回 true,则会执行控制器方法。
  3. postHandle():在控制器方法执行完之后,但在视图渲染之前执行。可以在此处修改返回的 ModelAndView 或响应对象。
  4. 视图渲染:将控制器方法返回的 ModelAndView 渲染为HTML或JSON响应。
  5. afterCompletion():请求处理完成(包括视图渲染)之后执行。用于资源清理、日志记录或处理异常。

Spring BootSpring MVC 中,使用拦截器(Interceptor)是一种常见的方式来在 HTTP请求处理流程 的不同阶段执行额外的逻辑。要在Spring中注册拦截器,我们需要通过 Java配置,实现 WebMvcConfigurer 接口的 addInterceptors() 方法。

下面我将详细解释如何在 Spring BootSpring MVC 项目中通过实现 WebMvcConfigurer 接口来注册拦截器,并通过 addInterceptors() 方法来配置拦截器的路径规则。

三、拦截器注册配置

接下来,我们需要将拦截器注册到Spring MVC中。要做到这一点,我们需要创建一个Java配置类,并实现 WebMvcConfigurer 接口。然后在 addInterceptors() 方法中注册我们自定义的拦截器,定义拦截的 URL 路径或排除的路径。

我们需要创建一个带有 @Configuration 注解的配置类,它会在Spring启动时自动加载。

示例:Java配置类

package com.example.config;

import com.example.interceptor.MyInterceptor;
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 WebConfig implements WebMvcConfigurer {

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 将自定义拦截器注册到Spring MVC
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")  // 拦截所有请求
                .excludePathPatterns("/login", "/register");  // 排除不需要拦截的路径
    }
}

解释

  • @Configuration:注解表示这是一个Spring配置类,Spring在启动时会自动加载此类。
  • addInterceptors():重写此方法以注册拦截器。
  • InterceptorRegistry:这是一个注册拦截器的帮助类。通过 addInterceptor() 方法将自定义拦截器添加到注册表中。
  • addPathPatterns("/**"):拦截所有路径。
  • excludePathPatterns("/login", "/register"):排除登录和注册页面,这样这些页面不会被拦截。

拦截路径规则

  • addPathPatterns("/**"):表示拦截所有请求,/** 是一个通配符,表示所有的URL。
  • excludePathPatterns("/login", "/register"):排除某些路径,比如 /login/register 路径,这样用户访问这些路径时不会经过拦截器。

可以根据业务需求自定义要拦截的路径和排除的路径。

Spring Boot项目中的拦截器注册

Spring Boot 项目中,配置拦截器的步骤与上述步骤相同。Spring Boot在启动时会自动扫描带有 @Configuration 注解的类并加载配置。因此,在Spring Boot项目中,只需要定义拦截器并通过 WebMvcConfigurer 注册拦截器,Spring Boot就会自动应用这些配置。

测试拦截器

假设我们在Spring Boot应用程序中启动服务,并访问以下路径:

  • 访问 http://localhost:8080/home

    • 进入拦截器的 preHandle() 方法,输出 Request URL is http://localhost:8080/home,控制器方法执行完毕后进入 postHandle()afterCompletion() 方法。
  • 访问 http://localhost:8080/login

    • 因为 login 路径在 excludePathPatterns() 中排除,因此此请求不会进入拦截器。

多拦截器注册

在实际开发中,我们可能需要使用多个拦截器。可以在 addInterceptors() 方法中依次添加多个拦截器,Spring会按注册顺序依次调用 preHandle(),而 postHandle()afterCompletion() 方法按相反顺序执行。

示例:注册多个拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册第一个拦截器
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/admin/**", "/user/**");

        // 注册第二个拦截器
        registry.addInterceptor(new LogInterceptor())
                .addPathPatterns("/**");  // 拦截所有请求
    }
}

在这个例子中:

  • AuthInterceptor 负责处理权限认证,只拦截 /admin/**/user/** 的请求。
  • LogInterceptor 负责记录日志,拦截所有请求。

拦截器执行顺序

Spring MVC支持多个拦截器,如果你注册了多个拦截器,它们会按照注册的顺序执行。执行顺序如下:

  1. preHandle():按注册顺序执行。
  2. postHandle():按注册顺序的反向顺序执行。
  3. afterCompletion():按注册顺序的反向顺序执行。

四、常见拦截器的应用场景

  • 权限验证拦截器:在 preHandle() 中检查用户是否具有访问某些资源的权限,若无权限则直接中断请求,返回错误信息。
  • 日志拦截器:记录请求的相关信息,比如请求的URL、请求的参数、响应时间等。
  • 性能监控拦截器:在 preHandle() 中记录开始时间,在 afterCompletion() 中记录结束时间,并计算整个请求的处理时间。
  • 统一处理跨域问题的拦截器:在 preHandle() 中设置响应头,允许跨域请求。

http://www.kler.cn/a/312514.html

相关文章:

  • Matlab自学笔记四十一:介绍日期时间型的显示格式:年‘y‘ 月‘M‘ 日‘d‘ 周‘e‘ 时‘h‘ 分‘m‘ 秒‘s‘
  • 管家婆财贸ERP BB045.销售批量收款
  • XML Schema 字符串数据类型
  • Redis - String 字符串
  • 【Python特征工程系列】利用SHAP进行特征重要性分析-XGB模型为例(案例+源码)
  • 11.11比赛总结
  • 本地git仓库配置远程仓库的地址
  • el-table的树形结构结合多选框使用,实现单选父子联动,全选,反选功能
  • SpringBoot结合Mybatis-plus项目直接执行sql语句
  • Vue学习记录之五(组件/生命周期)
  • IO流体系(FiletOutputStream)
  • Go Testify学习与使用
  • Linux环境变量进程地址空间
  • 毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
  • MySQL从入门到精通二
  • Java企业面试题3
  • MySQL_图形管理工具简介、下载及安装(超详细)
  • 对ViT 中Patch Embedding理解
  • 用友U8二次开发工具KK-FULL-*****-EFWeb使用方法
  • Vue 依赖注入组件通信:provide / inject 使用详解
  • QUIC 和 HTTP/3:提升网络性能的关键技术
  • Spring Cloud Config 动态刷新原理分析
  • 视频单目标跟踪研究
  • 鸿蒙next web组件和h5 交互实战来了
  • 零基础到项目实战:Node.js版Selenium WebDriver教程
  • Gitee Pipeline 从入门到实战【详细步骤】