【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

相关文章

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

pytorch自动求梯度autograd的实现

《pytorch自动求梯度autograd的实现》autograd是一个自动微分引擎,它可以自动计算张量的梯度,本文主要介绍了pytorch自动求梯度autograd的实现,具有一定的参考价值,感兴趣... autograd是pytorch构建神经网络的核心。在 PyTorch 中,结合以下代码例子,当你

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

python3 gunicorn配置文件的用法解读

《python3gunicorn配置文件的用法解读》:本文主要介绍python3gunicorn配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python3 gunicorn配置文件配置文件服务启动、重启、关闭启动重启关闭总结python3 gun

SpringMVC获取请求参数的方法

《SpringMVC获取请求参数的方法》:本文主要介绍SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下... 目录1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、@RequestParam4、@

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(