【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

相关文章

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

基于Redis自动过期的流处理暂停机制

《基于Redis自动过期的流处理暂停机制》基于Redis自动过期的流处理暂停机制是一种高效、可靠且易于实现的解决方案,防止延时过大的数据影响实时处理自动恢复处理,以避免积压的数据影响实时性,下面就来详... 目录核心思路代码实现1. 初始化Redis连接和键前缀2. 接收数据时检查暂停状态3. 检测到延时过

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键