【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

相关文章

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory