IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Boot拦截器(Interceptor)详解 -> 正文阅读

[Java知识库]Spring Boot拦截器(Interceptor)详解

Interceptor 介绍

**拦截器(Interceptor)**同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置……

Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个)。

Spring Interceptor是一个非常类似于Servlet Filter 的概念 。

Interceptor 作用

  1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等;
  2. 权限检查:如登录检测,进入处理器检测是否登录;
  3. 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录)
  4. 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。

自定义 Interceptor

如果你需要自定义 Interceptor 的话必须实现 org.springframework.web.servlet.HandlerInterceptor接口或继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter类,并且需要重写下面下面 3 个方法:

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

	/**
	 * This implementation always returns {@code true}.
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}

	/**
	 * This implementation is empty.
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

	/**
	 * This implementation is empty.
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

	/**
	 * This implementation is empty.
	 */
	@Override
	public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
	}

}
  1. preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是 Boolean 类型,当它返回 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当它返回为 true 时会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。

  2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是 Controller 方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。

  3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。

接下来结合实际代码进行学习。

LogInterceptor 类:

public class LogInterceptor extends HandlerInterceptorAdapter {    

@Override    
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {      
     long startTime = System.currentTimeMillis();       
     System.out.println("\n-------- LogInterception.preHandle --- ");        
     System.out.println("Request URL: " + request.getRequestURL());        
     System.out.println("Start Time: " + System.currentTimeMillis());        
     request.setAttribute("startTime", startTime);       
      return true;    
}    

@Override   
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
      System.out.println("\n-------- LogInterception.postHandle --- ");        
      System.out.println("Request URL: " + request.getRequestURL());    
}    

@Override   
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {        
   System.out.println("\n-------- LogInterception.afterCompletion --- ");        
   long startTime = (Long) request.getAttribute("startTime");        
   long endTime = System.currentTimeMillis();        
   System.out.println("Request URL: " + request.getRequestURL());        
   System.out.println("End Time: " + endTime);        
   System.out.println("Time Taken: " + (endTime - startTime));   
    }
}

OldLoginInterceptor 类:

public class OldLoginInterceptor extends HandlerInterceptorAdapter {
@Override    
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {       
	    System.out.println("\n-------- OldLoginInterceptor.preHandle --- ");       
	    System.out.println("Request URL: " + request.getRequestURL());      
	    System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login");        	   response.sendRedirect(request.getContextPath()+ "/admin/login");      
	    return false;   
}

@Override    
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {        
	System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");    
}   

@Override    
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {        
	System.out.println("\n-------- OldLoginInterceptor.afterCompletion --- ");    
	}

}

配置拦截器 :

@Configurationpublic 
class WebConfig implements WebMvcConfigurer {    
@Override    
public void addInterceptors(InterceptorRegistry registry) {        
	registry.addInterceptor(new LogInterceptor());      
	registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin"); 
	registry.addInterceptor(new	AdminInterceptor()).addPathPatterns("/admin/*").excludePathPatterns("/admin/oldLogin");   
	 }
}

LogInterceptor 拦截器用于拦截所有请求; OldLoginInterceptor 用来拦截链接 “ / admin / oldLogin”,它将重定向到新的 “ / admin / login”。;AdminInterceptor用来拦截链接 “/admin/*”,除了链接 “ / admin/oldLogin”。

自定义 Controller 验证拦截器

@Controllerpublic 
class LoginController {    
	@RequestMapping("/index")    
	public String index(Model model){        
		return "index";   
	 }   
	  
	@RequestMapping(value = "/admin/login")    
	public String login(Model model){        
		return "login";   
	 }
}

拦截器顺序

spring中拦截器执行顺序:

多个拦截器顺序:

  1. 默认的注册顺序
  2. InterceptorRegistry#order(int)方法指定顺序,值越小优先级越高

拦截器1

public class PathInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("PathInterceptor 执行");
        System.out.println("第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("PathInterceptor afterCompletion 完成");
    }
}

拦截器2

public class TestInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("TestInterceptor 执行");
      System.out.println("第二个执行的拦截器。巴拉巴拉、、、、");
      return true;
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      System.out.println("TestInterceptor  afterCompletion 完成");
  }
}

默认情况下,拦截器按照注册的顺序执行:

    @Bean
    public TestInterceptor testInterceptor() {
        return new TestInterceptor();
    }

    @Bean
    public PathInterceptor pathInterceptor() {
        return new PathInterceptor();
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(pathInterceptor()).addPathPatterns("/**");
    }

输出:

 TestInterceptor 执行
 第二个执行的拦截器。巴拉巴拉、、、、
 PathInterceptor 执行
 第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、
 PathInterceptor afterCompletion 完成
 TestInterceptor  afterCompletion 完成

通过面向百度编程发现

  • 可以使用 @Order 注解定义顺序
  • 实现Ordered接口
    测试发现都不生效,注解无论放到拦截器类上还是放到@Bean注解的位置都无效

解决方法

注册拦截器时,使用 InterceptorRegistry#order(int) 方法指定顺序,值越小优先级越高。

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor()).addPathPatterns("/**").order(2);
        registry.addInterceptor(pathInterceptor()).addPathPatterns("/**").order(1);
    }

输出:

PathInterceptor 执行
第一个执行的拦截器,进行权限校验。巴拉巴拉、、、、
TestInterceptor 执行
第二个执行的拦截器。巴拉巴拉、、、、
TestInterceptor  afterCompletion 完成
PathInterceptor afterCompletion 完成
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 17:28:59  更:2022-05-18 17:30:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:37:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码