spring MVC 拦截器

embedded/2024/9/20 13:24:45/

一、Spring MVC拦截器的作用

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

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

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

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

二、拦截器核心实现

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

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

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

示例代码 

java">public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 请求预处理逻辑return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 请求后处理逻辑}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 请求完成后的清理操作}
}

1. preHandle() 方法

方法签名

java">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() 示例

java">@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取请求的URIString 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() 方法

方法签名

java">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() 示例

java">@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() 方法

方法签名

java">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() 示例

java">@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配置类

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 {// 注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 将自定义拦截器注册到Spring MVCregistry.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() 方法按相反顺序执行。

示例:注册多个拦截器

java">@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic 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.ppmy.cn/embedded/114176.html

相关文章

kafka的主要功能

Apache Kafka 是一个分布式流处理平台,它最初由 LinkedIn 开发,后来捐赠给了 Apache Software Foundation,并成为了 Apache 的顶级项目。Kafka 设计用于处理实时数据流,并且提供了高性能、可扩展性和持久性。下面是 Kafka 的主要功…

git分支合并时忽略指定文件

分支合并忽略特定文件步骤 1.在项目根目录下cmd窗口运行以下命令 git config merge.ours.driver true2.在项目根目录下新建文件.gitattributes然后文件中写入需要忽略的文件名 mergeours, 一个文件占一行 Dockerfile mergeours /nginx/default.conf mergeours

Java语言程序设计基础篇_编程练习题**18.31 (替换单词)

目录 题目:**18.31 (替换单词) 习题思路 代码示例 运行结果 替换前 替换后 题目:**18.31 (替换单词) 编写一个程序,递归地用一个新单词替换某个目录下的所有文件中出现的某个单词。从命令行如下传递参数: java Exercise18…

数据结构——串的定义及存储结构

串的定义 串(string)——零个或多个任意字符组成的有限序列串是内容受限的线性表 串的几个术语 子串:串中任意几个连续字符组成的子序列称为该串的子串(真子串是指不包含自身的所有子串)主串:包含子串的串…

MacOS Sonoma(14.x) 大写模式或中文输入法下的英文模式,光标下方永远会出现的CapsLock箭头Icon的去除办法

如图,MacOS Sonoma(14.x) 大写模式或中文输入法下的英文模式下,光标下方永远会出现一个CapsLock箭头Icon。此Icon挡住视野,还容易误触导致切换大小写状态,带来的收益远远小于带来的困扰。 解决办法 打开终端,输入以下…

阿里国际发布最新版多模态大模型Ovis,拿下开源第一

看一眼菜品图就知道怎么做、能给植物看病、能把手写英文准确翻译成中文、还能精准分析财报数据……多模态能力再次升级!阿里国际AI团队发布了一款多模态大模型Ovis,在图像理解任务上不断突破极限,多种具体的子类任务中均达到了SOTA&#xff0…

网络安全(黑客技术)2024年三个月自学计划

🤟 基于入门网络安全/黑客打造的:👉黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”…

电商安全新挑战:筑起数字防御长城,守护业务与数据安全

在当今这个数字化时代,电商行业正以前所未有的速度发展,大数据、人工智能等技术的融入不仅重塑了消费模式,更激发了行业新的增长点。然而,这片繁荣景象之下,隐藏着一个不容忽视的暗流——网络安全威胁。从数据泄露到恶…