Springboot 拦截器总结

拦截器大体分为两类 : handlerInterceptor 和 methodInterceptor

而methodInterceptor 又有XML 配置方法 和AspectJ配置方法

1. handlerInterceptor用法

handlerInterceptor 主要用于拦截有url映射的方法(即controller中与url有关联的方法)

[1] 先创建一个拦截器

package com.grady.interceptordemo.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 自定义拦截器 - 给予 springmvc
* @ClassName: CustomInterceptor
* @Description: springMVC项目中的拦截器,它拦截的目标是请求的地址,比MethodInterceptor先执行。
* 该拦截器只能过滤action请求(即有url映射的函数,其他的不行),
* spring允许有多个拦截器存在,由拦截器链管理
* 当preHandle return true时,执行下一个拦截器,直到所有拦截器执行完,再运行 被拦截的请求
* 当preHandle return false时, 不再执行 后续的拦截器链 及 被拦截的请求。
*/ @Slf4j
public class CustomInterceptor implements HandlerInterceptor {
/**
* 我未实现一个方法却没有报错,因为使用了Java8的语法,默认函数
*/ /**
* 进入对应的controller前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("CustomInterceptor : preHandle");
// 这里如果return false,不会执行后面的拦截器,也不会执行请求的方法了
//return false; return true;
} /**
* 执行完controller方法后,但在返回对应视图前(返回json就没有返回视图的过程了)
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("CustomInterceptor : postHandle");
} /**
* 整个请求调用结束后,视图返回后,做资源清理工作
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("CustomInterceptor : afterCompletion");
}
}

[2] 将拦截器添加到InterceptorRegistry配置中

package com.grady.interceptordemo.config;

import com.grady.interceptordemo.interceptor.CustomInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /**
* WebMvcConfigurerAdapter 实际被 Deprecated 所以就不用纠结去不去继承他了,直接实现WebMvcConfigurer
*/
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//这里配置了customInterceptor这个拦截器拦截所有url
registry.addInterceptor(customInterceptor()).addPathPatterns("/**");
} @Bean
public CustomInterceptor customInterceptor() {
CustomInterceptor customInterceptor = new CustomInterceptor();
return customInterceptor;
}
}

之后访问url接口,可以看到以下日志

c.g.i.interceptor.CustomInterceptor      : CustomInterceptor : preHandle
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : postHandle
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : afterCompletion

2. 使用 methodInterceptor

[1] 使用XML配置方法

​ XML 配置 先要创建自己的xxMethodInterceptor (实现MethodInterceptor)

@Slf4j
public class CustomMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
log.info("CustomMethodInterceptor ==> invoke method: process method name is {}", methodInvocation.getMethod().getName());
log.info("CustomMethodInterceptor ==> invoke method: process class name is {}", methodInvocation.getMethod().getDeclaringClass());
// 这里做自定义操作 return methodInvocation.proceed();
}
}

然后再xml中进行配置

spring-aop.xml (注释部分是打开对注解的支持,暂时未开)

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <bean id="customMethodInterceptor" class="com.grady.interceptordemo.interceptor.CustomMethodInterceptor"/> <aop:config proxy-target-class="false">
<!-- 方法拦截器,基于spring aop 实现配置 -->
<!-- 扫描使用了注解的方法进行拦截 -->
<!-- <aop:advisor pointcut="@annotation(com.grady.interceptordemo.annotation.CustomAnnotation)" advice-ref="customMethodInterceptor" />-->
<!-- 指定包路径下的方法 -->
<aop:advisor pointcut="execution(* com.grady.interceptordemo.controller.*.*(..))" advice-ref="customMethodInterceptor" />
</aop:config>
</beans>

在xxxApplication.java导入XML @ImportResource("classpath:spring-aop.xml")

日志

 c.g.i.interceptor.CustomInterceptor      : CustomInterceptor : preHandle
c.g.i.i.CustomMethodInterceptor : CustomMethodInterceptor ==> invoke method: process method name is hello
c.g.i.i.CustomMethodInterceptor : CustomMethodInterceptor ==> invoke method: process class name is class com.grady.interceptordemo.controller.HelloController
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : postHandle
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : afterCompletion

从这里也可以看出,handlerInterceptor 的prehandle方法先于methodInterceptor 的invoke方法执行,其他的方法再invoke 方法之后执行

再在spring-aop.xml中打开注解,看是否支持注解版本(这里注释掉了包扫描的拦截方式)

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <bean id="customMethodInterceptor" class="com.grady.interceptordemo.interceptor.CustomMethodInterceptor"/> <aop:config proxy-target-class="false">
<!-- 方法拦截器,基于spring aop 实现配置 -->
<!-- 扫描使用了注解的方法进行拦截 -->
<aop:advisor pointcut="@annotation(com.grady.interceptordemo.annotation.CustomAnnotation)" advice-ref="customMethodInterceptor" />
<!-- 指定包路径下的方法 -->
<!-- <aop:advisor pointcut="execution(* com.grady.interceptordemo.controller.*.*(..))" advice-ref="customMethodInterceptor" />-->
</aop:config>
</beans>

日志一致,说明是生效

c.g.i.interceptor.CustomInterceptor      : CustomInterceptor : preHandle
c.g.i.i.CustomMethodInterceptor : CustomMethodInterceptor ==> invoke method: process method name is hello
c.g.i.i.CustomMethodInterceptor : CustomMethodInterceptor ==> invoke method: process class name is class com.grady.interceptordemo.manager.impl.HelloManagerImpl
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : postHandle
c.g.i.interceptor.CustomInterceptor : CustomInterceptor : afterCompletion

[2] 再看AspectJ版本(推荐方式)

SpectJ 不需要XML 配置,比较方便

​ 直接声明切面切点就搞定问题了

@Component
@Slf4j
public class AspectJInterceptor { // 声明一个切点,表示从哪里切入增强,这里是切controller目录下的所有public 方法
@Pointcut("execution (* com.grady.interceptordemo.controller.*.*(..))")
public void logPoint() { } //声明切面的执行方式,这里是环绕切面,环绕切是有返回值的Object
@Around("logPoint()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long startTime = System.currentTimeMillis();
log.info("AspectJInterceptor around的函数为:" + point.getSignature());
log.info("AspectJInterceptor around 方法开始时间 : " + startTime);
Object obj = point.proceed();// ob 为方法的返回值
log.info("AspectJInterceptor around 耗时 : " + (System.currentTimeMillis() - startTime));
return obj;
}
}

这样就可以了

查看日志

AspectJInterceptor around的函数为:String com.grady.interceptordemo.controller.HelloController.hello()
c.g.i.interceptor.AspectJInterceptor : AspectJInterceptor around 方法开始时间 : 1567261903109
c.g.i.interceptor.AspectJInterceptor : AspectJInterceptor around 耗时 : 9

说明生效了

上面是根据表达式寻找函数切的;现在换基于注解切

修改代码

@Aspect
@Component
@Slf4j
public class AspectJInterceptor {
// 声明一个切点 基于注解
@Pointcut("@annotation(com.grady.interceptordemo.annotation.CustomAnnotation)")
public void logPoint2() { } @Around("logPoint2()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long startTime = System.currentTimeMillis();
log.info("AspectJInterceptor around的函数为:" + point.getSignature());
log.info("AspectJInterceptor around 方法开始时间 : " + startTime);
Object obj = point.proceed();// ob 为方法的返回值
log.info("AspectJInterceptor around 耗时 : " + (System.currentTimeMillis() - startTime));
return obj;
}
}

日志:

2019-08-31 22:45:52.275  INFO 4516 --- [nio-8080-exec-1] c.g.i.interceptor.AspectJInterceptor     : AspectJInterceptor around的函数为:String com.grady.interceptordemo.manager.impl.HelloManagerImpl.hello()
2019-08-31 22:45:52.276 INFO 4516 --- [nio-8080-exec-1] c.g.i.interceptor.AspectJInterceptor : AspectJInterceptor around 方法开始时间 : 1567262752274

可以看的是HelloManagerImpl.hello 方法上有注解,所以切面方法中打印的是这个方法;而之前的版本切的位置是controller包中的方法,所以打印的是HelloController.hello

PS:

可以在application.properties 中打开这个开关,开启CGlib ,(这个实验中不开是可以的,原因是当spring aop 无效时(比如没有实现接口的类controller),会自动使用CGLib尝试)

# 启用CGLib 来实现aop
# spring.aop.proxy-target-class=true

springboot拦截器总结的更多相关文章

  1. Java结合SpringBoot拦截器实现简单的登录认证模块

    Java结合SpringBoot拦截器实现简单的登录认证模块 之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章 ...

  2. SpringBoot拦截器中Bean无法注入(转)

    问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Be ...

  3. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  4. SpringBoot拦截器中无法注入bean的解决方法

    SpringBoot拦截器中无法注入bean的解决方法 在使用springboot的拦截器时,有时候希望在拦截器中注入bean方便使用 但是如果直接注入会发现无法注入而报空指针异常 解决方法: 在注册 ...

  5. Springboot拦截器未起作用

    之前遇到要使用springboot拦截器却始终未生效的状况,查了网上的博客,大抵都是@Component,@Configuration注解未加,或是使用@ComponentScan增加包扫描,但是尝试 ...

  6. SpringBoot拦截器中service或者redis注入为空的问题

    原文:https://my.oschina.net/u/1790105/blog/1490098 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于 ...

  7. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  8. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

  9. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现. 业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口. 实现功能:写一个拦 ...

  10. SpringBoot 拦截器获取http请求参数

    SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 目录 SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 获取http请求参数是一种刚需 定义拦截器获取请求 为 ...

随机推荐

  1. BPC 脚本

    // //税款计算(现金流) // //2018年5月11日修改,去除之前的送数逻辑,新增BADI计算相关科目 // *SELECT(%010804ZH%, "ID", " ...

  2. Linux系统安全配置

    1.物理安全 硬件服务器,关闭从CD/DVD等这些方面的软启动方式.同时也可以设置BIOS密码,并且要有限制访问的策略与各类流程管控. 还可以禁用USB设备来达到安全的目的: centos7x 安装d ...

  3. RPA应用场景-考勤审批

    场景概述 考勤审批 所涉系统名称 考勤系统,微信 人工操作(时间/次) 5分钟 所涉人工数量 43 操作频率 不定时 场景流程 1.客户领导长期出差,又不想对考勤系统做深度开发: 2.员工请假后,领导 ...

  4. Android高仿网易云音乐-启动界面实现和动态权限处理

    效果 实现分析 基本上没有什么难点,就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等. 布局 <?xml version="1.0" ...

  5. Tapdata肖贝贝:实时数据引擎系列(三) - 流处理引擎对比

      摘要:本文将选取市面上一些流计算框架包括 Flink .Spark .Hazelcast,从场景需求出发,在核心功能.资源与性能.用户体验.框架完整性.维护性等方面展开分析和测评,剖析实时数据框架 ...

  6. 常用Linux音译

    su:Swith user 切换用户,切换到root用户 cat: Concatenate 串联 uname: Unix name 系统名称 df: Disk free 空余硬盘 du: Disk u ...

  7. go grpc: connection reset by peer 的一种解决方案

    最近添哥一直反映,他手下的设备以grpc stream的方式向我服务端发送数据.偶然会收到错误.现象如下: 连接已经建立了一段时间,正常使用. 突然client.Send 返回 eof. 客户端有报错 ...

  8. MySQL语句与正则表达式

    正则表达式的作用是匹配文本,将一个模式(正则表达式)与一个文本串进行比较.MySQL用WHERE子句对正则表达式提供了初步的支持,允许你指定正则表达式,过滤SELECT检索出的数据. 1.元字符说明 ...

  9. 可落地的DDD(7)-战术设计上的一些误区

    背景 几年前我总结过DDD战术设计的一些落地经验可落地的DDD(5)-战术设计,和一次关于聚合根的激烈讨论最近两年有些新的落地体验,回过头来发现,当初对这些概念的理解还是没有深入,这篇文章重新阐述下. ...

  10. 如何在Excel/WPS表格中批量查询快递信息?

    如何在Excel/WPS表格中批量查询快递信息? 干电商的小伙伴们还在为如何批量查询快递物流信息发愁吗?别着急,这篇文章或许能够帮助到您. 首先给大家看一下查询的具体成果: 第一步:安装Excel网络 ...