SpringBoot 拦截器妙用你真的了解吗


Posted in Java/Android onJuly 01, 2021

HandlerInterceptor 详解

HandlerInterceptor 允许定制 handler 处理器执行链的工作流接口。我们可以自定义拦截器用于拦截 handlers 处理器(你可以理解为 controller 层的接口),从而可以添加一些共同的重复性的处理行为(例如接口鉴权,接口日志记录,性能监控等),而不用修改每一个 handler 的实现。

注意,此基于 SpringBoot 2.3.12.RELEASE 版本讲解。

HandlerInterceptor 接口只有三个默认空实现方法,在低版本中这三个方法不是默认方法,而是抽象方法。

public interface HandlerInterceptor {

	default boolean preHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler) throws Exception {
		return true;
	}

	default void postHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler, @Nullable ModelAndView modelAndView) throws Exception {
	}

	default void afterCompletion(HttpServletRequest request, HttpServletResponse response,             Object handler, @Nullable Exception ex) throws Exception {
	}
}

这三个方法的执行顺序图如下:

SpringBoot 拦截器妙用你真的了解吗

preHandle

preHandle 前置处理,拦截一个处理器(handler)的执行,preHandle 方法会在 HandlerMapping 确定一个适当的处理器对象之后,但在 HandlerAdapter 调用处理器之前被调用。可以简单理解为 controller 接口被调用之前执行。

Intercepter 是链式的,就是一个接着一个执行。如果此方法返回 true,则会执行下一个拦截器或者直接执行处理器。如果此方法返回 false 或者抛出异常则终止执行链,也不再调用处理器。

注意,此方法如果不返回 true,那么 postHandleafterCompletion 不会被执行。

那这个方法有什么用呢?其实可以做一些接口被调用前的预处理,例如用户权限校验。

package com.chenpi;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * @Description 用户权限验证拦截
 * @Author 陈皮
 * @Date 2021/6/27
 * @Version 1.0
 */
@Component
public class UserPermissionInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) {

        if (handler instanceof HandlerMethod) {

            HandlerMethod handlerMethod = (HandlerMethod) handler;

            // 获取用户权限校验注解
            UserAuthenticate userAuthenticate =
                    handlerMethod.getMethod().getAnnotation(UserAuthenticate.class);
            if (null == userAuthenticate) {
                userAuthenticate = handlerMethod.getMethod().getDeclaringClass()
                        .getAnnotation(UserAuthenticate.class);
            }
            if (userAuthenticate != null && userAuthenticate.permission()) {
                // 验证用户信息
                UserContext userContext = userContextManager.getUserContext(request);
                if (null == userContext) {
                    return false;
                }
            }
        }
        return true;
    }
}

postHandle

postHandle 后置处理,会在 HandlerAdapter 调用处理器之后,但在 DispatcherServlet 渲染视图之前被调用。可以在此对 ModelAndView 做一些额外的处理。可以简单理解为 controller 接口被调用之后执行。

注意,此方法在执行链中的执行顺序是倒着执行的,即先声明的拦截器后执行。

afterCompletion

afterCompletion 完成之后,在请求处理完之后被执行,也就是渲染完视图之后。一般用于做一些资源的清理工作,配合 preHandle 计算接口执行时间等。

注意,和 postHandle 一样,此方法在执行链中的执行顺序也是倒着执行的,即先声明的拦截器后执行。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                            Object handler, @Nullable Exception ex) {
    // 请求完后,清除当前线程的用户信息
    UserContextHolder.removeUserContext();
}

注册拦截器

注意,我们自定义的拦截器要通过 WebMvcConfigurer 的实现类进行注册,才能生效。

package com.yzj.ehr.common.config;

import com.yzj.ehr.common.context.UserContextResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.yzj.ehr.common.interceptor.UserPermissionInterceptor;

/**
 * @Description 注册拦截器
 * @Author 陈皮
 * @Date 2021/6/27
 * @Version 1.0
 */
@Component
public class WebAppConfigurer implements WebMvcConfigurer {

    private UserPermissionInterceptor userPermissionInterceptor;

    public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) {
        this.userPermissionInterceptor = userPermissionInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 匹配所有接口,排除/base/test接口
        registry.addInterceptor(userPermissionInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/base/test");
    }
}

到此这篇关于SpringBoot 拦截器妙用你真的了解吗的文章就介绍到这了,更多相关SpringBoot 拦截器内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
利用Java设置Word文本框中的文字旋转方向的实现方法
Jun 28 Java/Android
一篇文章带你复习java知识点
Jun 28 Java/Android
解决Jenkins集成SonarQube遇到的报错问题
Jul 15 Java/Android
Java实现给Word文件添加文字水印
Feb 15 Java/Android
InterProcessMutex实现zookeeper分布式锁原理
Mar 21 Java/Android
Spring Security使用单点登录的权限功能
Apr 03 Java/Android
SpringBoot整合minio快速入门教程(代码示例)
Apr 03 Java/Android
springboot入门 之profile设置方式
Apr 04 Java/Android
Java 通过手写分布式雪花SnowFlake生成ID方法详解
Apr 07 Java/Android
Java Spring Boot 正确读取配置文件中的属性的值
Apr 20 Java/Android
MyBatis核心源码深度剖析SQL语句执行过程
May 20 Java/Android
使用Postman测试需要授权的接口问题
Jun 21 Java/Android
解决SpringBoot文件上传临时目录找不到的问题
java实现对Hadoop的操作
Jul 01 #Java/Android
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
Jul 01 #Java/Android
Java中多线程下载图片并压缩能提高效率吗
分析ZooKeeper分布式锁的实现
Java并发编程必备之Future机制
详解Spring Boot使用系统参数表提升系统的灵活性
Jun 30 #Java/Android
You might like
php递归实现无限分类生成下拉列表的函数
2010/08/08 PHP
PHP 观察者模式的实现代码
2013/05/10 PHP
PHP使用strtotime计算两个给定日期之间天数的方法
2015/03/18 PHP
PHP 加密 Password Hashing API基础知识点
2020/03/02 PHP
使用JQuery和s3captche实现一个水果名字的验证
2009/08/14 Javascript
Js中使用hasOwnProperty方法检索ajax响应对象的例子
2014/12/08 Javascript
jquery渐隐渐显的图片幻灯闪烁切换实现方法
2015/02/26 Javascript
Javascript实现div层渐隐效果的方法
2015/05/30 Javascript
JavaScript事件类型中焦点、鼠标和滚轮事件详解
2016/01/25 Javascript
jQuery获取父元素节点、子元素节点及兄弟元素节点的方法
2016/04/14 Javascript
微信小程序 生命周期函数详解
2017/05/24 Javascript
Vue中如何实现轮播图的示例代码
2017/07/27 Javascript
AngularJS select设置默认值的实现方法
2017/08/25 Javascript
vue better scroll 无法滚动的解决方法
2018/06/07 Javascript
BootStrap modal实现拖拽功能
2018/12/01 Javascript
Vue自定义属性实例分析
2019/02/23 Javascript
基于JS开发微信网页录音功能的实例代码
2019/04/30 Javascript
Vue.js实现tab切换效果
2019/07/24 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
json_decode 索引为数字时自动排序问题解决方法
2020/03/28 Javascript
Laravel 如何在blade文件中使用Vue组件的示例代码
2020/06/28 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
python中利用xml.dom模块解析xml的方法教程
2017/05/24 Python
python爬取哈尔滨天气信息
2018/07/14 Python
Python3.6简单的操作Mysql数据库的三个实例
2018/10/17 Python
Python django框架开发发布会签到系统(web开发)
2020/02/12 Python
Python中的X[:,0]、X[:,1]、X[:,:,0]、X[:,:,1]、X[:,m:n]和X[:,:,m:n]
2020/02/13 Python
pycharm全局搜索的具体步骤
2020/07/28 Python
Pycharm安装第三方库失败解决方案
2020/11/17 Python
HTML5新增属性data-*和js/jquery之间的交互及注意事项
2017/08/08 HTML / CSS
localStorage的过期时间设置的方法详解
2018/11/26 HTML / CSS
超市优秀员工获奖感言
2014/08/15 职场文书
2014年民政局关于保密工作整改措施
2014/09/19 职场文书
2014年民警工作总结
2014/11/25 职场文书
《倍数和因数》教学反思
2016/02/23 职场文书
【海涛教你打dota】体验一超神发条:咱是抢盾专业户
2022/04/01 DOTA