【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法

本文主要是介绍【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《Spring 狂野之旅:底层原理高级进阶》 🚀

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net/

老样子 先用一个生动的例子 来讲解 今天的主角 拦截器的作用

一天,我们的主角坤坤打算开一家篮球店,他兴致勃勃地准备了一切,从篮球装备到装修风格,都精心设计。他决定给自己的篮球店起名叫"坤坤篮球店",希望能够吸引更多的篮球爱好者。

坤坤开业的第一天,篮球店迎来了很多顾客。他兴奋地迎接每个人,向他们介绍店里的产品和服务。然而,坤坤很快发现,有一些顾客可能并不是真正的篮球爱好者,而是想趁机捣乱或者做一些不合法的事情,也就是人们常说的“小黑子”

这时,他决定在篮球店的入口处设置三个聪明又可爱的坤家卫 人称“三只鸡脚”,它是坤坤的得力助手。这个鸡脚像个守门员,聪明地分辨出哪些人是真爱粉,哪些人只是小黑子,并义正言辞的嘲讽那些虚假的粉丝 并给予礼貌的问候“你最好是”。


每当有人进入篮球店,坤家卫会迅速判断他们的目的。如果是真正的篮球爱好者,拦截器会热情地引导他们到合适的偶像练习生区域,给予他们服务。在他们进行愉快的热舞之前,需要将舞台和背景板渲染成他们喜欢的模样。而对于那些可疑的人,拦截器会立即拦截他们,阻止他们进一步的行动。

最后在激情的热舞过后 会有剩余的坤家卫 打扫战场,作后续操作与资源清理

上面那个故事我们可以预见 坤坤篮球店的兴起  这离不开三位坤家卫的协作  既然如此 那么我们也走进SpringMVC的拦截器当中 深入了解其原理与机制

正片

目录

老样子 先用一个生动的例子 来讲解 今天的主角 拦截器的作用

上面那个故事我们可以预见 坤坤篮球店的兴起  这离不开三位坤家卫的协作  既然如此 那么我们也走进SpringMVC的拦截器当中 深入了解其原理与机制

正片

介绍

具体实现:

那么,我们也可以创建一个自己的拦截器 来为业务服务:

在上述示例中,我们通过addInterceptors方法向InterceptorRegistry注册了CustomInterceptor,并使用addPathPatterns方法指定了拦截的URL模式,这里使用"/**"表示拦截所有请求。

拦截器在实际项目中有多种应用场景,除了身份验证之外还有以下常见用途,以及我做过在业务中的具体实现:

一些拦截器的注意事项和最佳实践包括:


介绍

拦截器在 Spring MVC 中扮演着重要的角色,用于拦截请求和响应的处理过程,并允许开发人员在请求进入控制器之前或离开控制器之后执行自定义的逻辑。它提供了一种在请求的不同生命周期阶段插入自定义代码的机制。

与过滤器相比,拦截器更加专注于处理控制器级别的逻辑,它们与控制器紧密耦合,并且可以访问和修改控制器方法的参数和返回值。拦截器通常用于实现一些通用的横切关注点,如身份验证、权限检查、日志记录、性能监测等。

在 Spring MVC 中,拦截器通过实现 HandlerInterceptor 接口来定义。HandlerInterceptor 接口包含了三个核心方法:

  1. preHandle:在请求到达控制器之前被调用。可以用于进行一些前置处理,如身份验证、权限检查等。根据返回结果决定是否继续处理请求。

  2. postHandle:在控制器方法执行完成后,视图渲染之前被调用。可以对模型数据进行进一步的处理或修改

  3. afterCompletion:在整个请求处理完成后被调用。用于进行一些资源清理操作或记录请求处理结果等。

这些方法在拦截器链中按照特定的顺序被调用。在多个拦截器存在的情况下,它们的执行顺序由拦截器的配置顺序决定。拦截器链的执行顺序是先进后出的,即先配置的拦截器最后执行。

通过编写自定义的 HandlerInterceptor 实现类,并将其配置到 Spring MVC 中,开发人员可以灵活地控制请求处理过程中的逻辑。拦截器提供了一种可插拔的机制,使得代码的复用性和可维护性得到提高,并且可以有效地实现横切关注点的功能。

具体实现:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在请求到达控制器之前被调用// 可以进行一些前置处理,如身份验证、权限检查等// 返回false将阻止继续处理请求,返回true将允许继续处理请求String token = request.getHeader("Authorization");if (token == null || !isValidToken(token)) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在控制器方法执行完成后,视图渲染之前被调用// 可以对模型数据进行进一步的处理或修改if (modelAndView != null) {modelAndView.addObject("customData", "Additional data");}}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在整个请求处理完成后被调用// 可以进行一些资源清理操作或记录请求处理结果等logRequestCompletion(request, response.getStatus());}private boolean isValidToken(String token) {// 验证token的逻辑// 返回true表示token有效,返回false表示token无效// 这里只是一个示例,实际业务逻辑需要根据具体需求实现return true;}private void logRequestCompletion(HttpServletRequest request, int status) {// 记录请求处理结果的逻辑// 这里只是一个示例,实际业务逻辑需要根据具体需求实现System.out.println("Request completed - URI: " + request.getRequestURI() + ", Status: " + status);}
}

那么,我们也可以创建一个自己的拦截器 来为业务服务:

  1. 创建一个Java类,实现HandlerInterceptor接口。例如,我们可以创建一个名为CustomInterceptor的类:
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class CustomInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 实现preHandle方法,在请求到达控制器之前进行拦截和处理// 在这里可以实现需要的业务逻辑,例如身份验证、权限检查等// 返回true表示继续处理请求,返回false将阻止继续处理请求return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 实现postHandle方法,在控制器方法执行完成后进行拦截和处理// 在这里可以对模型数据进行进一步的处理或修改}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 实现afterCompletion方法,在整个请求处理完成后进行拦截和处理// 在这里可以进行一些资源清理操作或记录请求处理结果等}
    }

  2. 在CustomInterceptor类中,您可以根据需要实现preHandle、postHandle和afterCompletion方法来编写具体的业务逻辑。

  3. 注册拦截器到Spring MVC配置中。在Spring MVC的配置文件(如XML配置文件或Java配置类)中,通过配置InterceptorRegistry来注册自定义拦截器。以下是一个示例,假设您正在使用Java配置类:

    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 AppConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册自定义拦截器registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/**");}
    }

    在上述示例中,我们通过addInterceptors方法向InterceptorRegistry注册了CustomInterceptor,并使用addPathPatterns方法指定了拦截的URL模式,这里使用"/**"表示拦截所有请求。

拦截器在实际项目中有多种应用场景,除了身份验证之外还有以下常见用途,以及我做过在业务中的具体实现:

  1. 日志记录:拦截器可以用于记录请求和响应的日志信息,包括请求的URL、参数、处理时间等。这对于跟踪和排查问题、性能优化以及统计分析非常有用。

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class LoggingInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 记录请求的URL和参数String url = request.getRequestURL().toString();String queryString = request.getQueryString();System.out.println("Request URL: " + url);System.out.println("Request Parameters: " + queryString);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 {// 在这里可以记录请求处理时间等信息}
    }

  2. 缓存管理:拦截器可以用于缓存管理,例如在请求到达控制器之前检查缓存中是否存在响应数据,如果存在则直接返回缓存数据,避免重复计算或查询数据库。

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class CacheInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 检查缓存中是否存在响应数据String cacheKey = generateCacheKey(request);Object cachedData = getFromCache(cacheKey);if (cachedData != null) {// 直接返回缓存数据writeResponseData(response, cachedData);return false; // 终止请求继续处理}return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在这里可以将响应数据缓存起来String cacheKey = generateCacheKey(request);Object responseData = extractResponseData(response);storeInCache(cacheKey, responseData);}private String generateCacheKey(HttpServletRequest request) {// 根据请求的URL、参数等生成唯一的缓存键// ...}private Object getFromCache(String cacheKey) {// 从缓存中获取数据// ...}private void writeResponseData(HttpServletResponse response, Object data) {// 将数据写入响应// ...}private Object extractResponseData(HttpServletResponse response) {// 从响应中提取数据// ...}private void storeInCache(String cacheKey, Object data) {// 将数据存入缓存// ...}
    }

  3. 权限控制:除了身份验证,拦截器可以用于实现细粒度的权限控制。在preHandle方法中,可以检查当前用户是否具有访问某个资源或执行某个操作的权限,如果没有权限,则可以返回相应的错误信息或重定向到其他页面。

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class AuthorizationInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 检查用户权限if (!hasPermission(request)) {// 没有权限,返回错误信息或重定向到其他页面response.sendRedirect("/error/unauthorized");return false; // 终止请求继续处理}return true;}private boolean hasPermission(HttpServletRequest request) {// 检查当前用户是否具有访问资源的权限// ...}
    }

  4. 请求参数解析和预处理:拦截器可以用于解析请求参数,并进行一些预处理操作,例如数据格式转换、参数校验等。这有助于减轻控制器方法的负担,使其更专注于业务逻辑的处理。

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class RequestProcessingInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 参数解析和预处理String param1 = request.getParameter("param1");String param2 = request.getParameter("param2");// 对参数进行处理或校验// ...return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在这里可以对模型数据进行进一步处理或修改}
    }

  5. 错误处理:拦截器可以用于全局的错误处理,捕获和处理异常。在afterCompletion方法中,可以对异常进行统一的处理,例如记录日志、发送通知等。

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;public class ErrorHandlingInterceptor implements HandlerInterceptor {@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在这里对异常进行统一处理if (ex != null) {// 记录日志或发送通知System.out.println("Exception occurred: " + ex.getMessage());}}
    }

    一些拦截器的注意事项和最佳实践包括:

    1. 尽量保持拦截器的逻辑简单和高效,避免过多的复杂业务处理。过多的业务逻辑应该放在控制器或服务层中处理。

    2. 注意拦截器的执行顺序,特别是在多个拦截器同时工作的情况下。可以使用@Order注解或实现Ordered接口来指定拦截器的执行顺序。

    3. 注意拦截器的性能影响。拦截器是链式调用的,每个拦截器都会对请求进行处理,因此需要谨慎处理拦截器的性能,避免不必要的操作和重复计算。

    4. 异常处理:拦截器应该对异常进行适当的处理和封装,以便能够正确地返回错误信息给客户端或进行统一的异常处理。

 

这篇关于【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/723065

相关文章

springboot健康检查监控全过程

《springboot健康检查监控全过程》文章介绍了SpringBoot如何使用Actuator和Micrometer进行健康检查和监控,通过配置和自定义健康指示器,开发者可以实时监控应用组件的状态,... 目录1. 引言重要性2. 配置Spring Boot ActuatorSpring Boot Act

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧