锋盈数科-知识库 Logo
首页
软件开发
计算机基础
Hello Halo
新手必读
关于本知识库
登录 →
锋盈数科-知识库 Logo
首页 软件开发 计算机基础 Hello Halo 新手必读 关于本知识库
登录
  1. 首页
  2. 软件开发
  3. spring MVC 拦截器

spring MVC 拦截器

0
  • 软件开发
  • 发布于 2024-09-20
  • 0 次阅读
黄健
黄健

一、Spring MVC拦截器的作用

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

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

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

  • 拦截器核心实现 :通过实现 HandlerInterceptor 接口定义拦截器的三大核心方法(preHandle、postHandle、afterCompletion),实现请求拦截的核心逻辑。
  • 拦截器注册配置 :通过实现 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 参数就会包含这个异常信息;如果没有异常,ex 为 null。

常见参数使用:

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

下面我将详细解释如何在 Spring Boot 或 Spring 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() 中设置响应头,允许跨域请求。

原文链接: https://blog.csdn.net/m0_73837751/article/details/142025661

标签: #SpringMVC 58 #软件开发 1171
相关文章

万字:支付“核心系统”详解 2024-11-02 15:33

专栏作者:隐墨星辰 \| 主编:陈天宇宙 这篇文章也尝试化繁为简,探寻支付系统的本质,讲清楚在线支付系统最核心的一些概念和设计理念。 虽然支付行业已经过了风头最劲的时光,但跨境支付仍然在蓬勃发展,每年依然有很多新人进入这个行业,这篇文章尝试为这些刚入行的新人提供一点帮助。 文章只介绍一些支付行业十几

资深支付架构师视角:实战从问题定义到代码落地的完整套路 2024-11-02 15:33

前言 今天从一个实际案例入手,介绍站在架构师的角度,如何识别并定义问题,提炼需求,技术方案选型,再到详细设计,最后利用AI的能力协助写出核心的代码,验证与调优。 解决问题存在一定的模式,也可以称之为框架,总结出自己的思考和解题框架,以后再碰到同类型的问题就可以如庖丁解牛一样容易。 很多年前,我写代码

Spring 实现 3 种异步接口 2024-10-18 09:07

大家好,我是苏三~ 如何处理比较耗时的接口? 这题我熟,直接上异步接口,使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性,处理结果仅返回单个值。在某些场景下,如果需要接口异步处理的同时,还持续不断地

重学SpringBoot3-集成Redis(五)之布隆过滤器 2024-10-08 11:24

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(五)之布隆过滤器 1. 什么是布隆过滤器? * 基本概念 适用场景 2. 使用 Redis 实现布隆过滤器 * 项目依赖 Redis 配置

设计模式第16讲——迭代器模式(Iterator) 2024-10-08 11:24

一、什么是迭代器模式 迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。 二、角色组成 抽象迭代器(Iterator):定义了遍历聚合对象所需的方法

vue2路由和vue3路由区别及原理 2024-10-08 11:24

一、Vue2 与 Vue3 路由的区别 1. 创建路由实例方式的不同 Vue 2 中,通过 Vue.use() 注册路由插件,并通过 new VueRouter() 来创建路由实例。 import Vue from 'vue';import VueRouter from 'vue-router';i

目录

IT 外包服务商

  • 意见投递
  • zyf6619

软件开发应用

主菜单

  • 首页
  • 软件开发
  • 计算机基础
  • Hello Halo
  • 新手必读
  • 关于本知识库
Copyright © 2024 your company All Rights Reserved. Powered by Halo.