SpringBoot HandlerInterceptorAdapter 攔截器


SpringBoot之HandlerInterceptorAdapter

 

在SpringBoot中我們可以使用HandlerInterceptorAdapter這個適配器來實現自己的攔截器。這樣就可以攔截所有的請求並做相應的處理。

應用場景

  • 日志記錄,可以記錄請求信息的日志,以便進行信息監控、信息統計等。
  • 權限檢查:如登陸檢測,進入處理器檢測是否登陸,如果沒有直接返回到登陸頁面。
  • 性能監控:典型的是慢日志。

在HandlerInterceptorAdapter中主要提供了以下的方法:
preHandle:在方法被調用前執行。在該方法中可以做類似校驗的功能。如果返回true,則繼續調用下一個攔截器。如果返回false,則中斷執行,也就是說我們想調用的方法 不會被執行,但是你可以修改response為你想要的響應。
postHandle:在方法執行后調用。
afterCompletion:在整個請求處理完畢后進行回調,也就是說視圖渲染完畢或者調用方已經拿到響應。

在HandlerInterceptorAdapter中主要提供了以下的方法:

  • preHandle:在方法被調用前執行。在該方法中可以做類似校驗的功能。如果返回true,則繼續調用下一個攔截器。如果返回false,則中斷執行,也就是說我們想調用的方法 不會被執行,但是你可以修改response為你想要的響應。
  • postHandle:在方法執行后調用。
  • afterCompletion:在整個請求處理完畢后進行回調,也就是說視圖渲染完畢或者調用方已經拿到響應。

HandlerInterceptor

攔截器適配器HandlerInterceptorAdapter

復制代碼
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 {
   }

}
復制代碼

有時候我們可能只需要實現三個回調方法中的某一個,如果實現HandlerInterceptor接口的話,三個方法必須實現,不管你需不需要,此時spring提供了一個HandlerInterceptorAdapter適配器(種適配器設計模式的實現),允許我們只實現需要的回調方法。
這樣在我們業務中比如要記錄系統日志,日志肯定是在afterCompletion之后記錄的,否則中途失敗了,也記錄了,那就扯淡了。一定是程序正常跑完后,我們記錄下那些對數據庫做個增刪改的操作日志進數據庫。所以我們只需要繼承HandlerInterceptorAdapter,並重寫afterCompletion一個方法即可,因為preHandle默認是true。

運行流程總結如下:

  1. 攔截器執行順序是按照Spring配置文件中定義的順序而定的。
  2. 會先按照順序執行所有攔截器的preHandle方法,一直遇到return false為止,比如第二個preHandle方法是return false,則第三個以及以后所有攔截器都不會執行。若都是return true,則按順序加載完preHandle方法。
  3. 然后執行主方法(自己的controller接口),若中間拋出異常,則跟return false效果一致,不會繼續執行postHandle,只會倒序執行afterCompletion方法。
  4. 在主方法執行完業務邏輯(頁面還未渲染數據)時,按倒序執行postHandle方法。若第三個攔截器的preHandle方法return false,則會執行第二個和第一個的postHandle方法和afterCompletion(postHandle都執行完才會執行這個,也就是頁面渲染完數據后,執行after進行清理工作)方法。(postHandle和afterCompletion都是倒序執行)

下面用一個demo來演示執行流程


定義一個類繼承HandlerInterceptorAdapter,並重寫方法


快捷鍵ctrl+o打開可以重寫的方法面板選擇

復制代碼
package com.example.demo.config;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

public class LogInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.err.println("================================== preHandle1 ===========================================");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.err.println("================================== postHandle1 ===========================================");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.err.println("================================== afterCompletion1 ===========================================");
    }

}
復制代碼

WebMvcConfigurerAdapter 抽象類是對WebMvcConfigurer接口的簡單抽象(增加了一些默認實現),但在在SpringBoot2.0及Spring5.0中WebMvcConfigurerAdapter已被廢棄 。官方推薦直接實現WebMvcConfigurer或者直接繼承WebMvcConfigurationSupport

實現WebMvcConfigurer配置攔截器

復制代碼
package com.example.demo.config;

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 WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor());
    }
}
復制代碼

在控制器中寫一個方法並訪問

@ApiOperation(value = "test mybatis", notes = "")
@RequestMapping(value = "getuser", method = RequestMethod.GET)
public User getUser() {
    return userService.getUser();
}

會在控制台輸出

此時在加入一個攔截器,會按照配置的順序執行,配置如下

復制代碼
package com.example.demo.config;

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 WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor());
        registry.addInterceptor(new LogInterceptor2());
    }
}
復制代碼

控制的輸出反映了配置多個攔截器的執行流程:

如果controller出現異常,則不會繼續執行postHandle,只會倒序執行afterCompletion方法

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM