SpringBoot Interceptor

Interceptor 介紹

攔截器 (Interceptor) 同 Filter 過濾器一樣,它們都是面向切面編程——AOP 的具體實現

可以使用 Interceptor 來執行某些任務,例如在 Controller 處理請求之前編寫日誌,添加或更新配置等。

在 Spring 中,當請求發送到 Controller 時,在被 Controller 處理之前,必須經過 Interceptors

過濾器和攔截器的區別

  • 過濾器(Filter):當有一堆東西的時候,只希望選擇符合你要求的某一些東西。定義這些要求的工具,就是過濾器。
  • 攔截器(Interceptor):在一個流程正在進行的時候,希望干預它的進展,甚至終止它進行,這是攔截器做的事情。

自定義 Interceptor

自定義 Interceptor 需要實現 org.springframework.web.servlet.HandlerInterceptor 接口或繼承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter 類,並且需要重寫下面3個方法:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

注意: preHandle 方法返回 **true **或 false。如果返回 true,則意味着請求將繼續到達 Controller 被處理。

Interceptor示意圖

每個請求可能會通過多個攔截器。

示例

LogInterceptor 用於過濾所有請求:

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

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

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());
        // You can add attributes in the modelAndView
        // and use that in the view page
    }

    @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是一個攔截器,如果用戶輸入已經被廢棄的鏈接“/admin/oldLogin”,它將重定向到新的 “/admin/login”:

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

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

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 {
        // This code will never be run.
        System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // This code will never be run.
        System.out.println("\n-------- QueryStringInterceptor.afterCompletion --- ");
    }
}

img

img

AdminInterceptor

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

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

public class AdminInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("\n-------- AdminInterceptor.preHandle --- ");
        return true;
    }

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

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

配置攔截器

import github.javaguide.springbootfilter.interceptor.AdminInterceptor;
import github.javaguide.springbootfilter.interceptor.LogInterceptor;
import github.javaguide.springbootfilter.interceptor.OldLoginInterceptor;
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) {
        // LogInterceptor apply to all URLs.
        registry.addInterceptor(new LogInterceptor());

        // Old Login url, no longer use.
        // Use OldURLInterceptor to redirect to a new URL.
        registry.addInterceptor(new OldLoginInterceptor())
                .addPathPatterns("/admin/oldLogin");

        // This interceptor apply to URL like /admin/*
        // Exclude /admin/oldLogin
        registry.addInterceptor(new AdminInterceptor())
                .addPathPatterns("/admin/*")
                .excludePathPatterns("/admin/oldLogin");
    }
}

自定義 Controller 驗證攔截器

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class InterceptorTestController {

    @RequestMapping(value = { "/", "/test" })
    public String test(Model model) {
        System.out.println("\n-------- MainController.test --- ");
        System.out.println(" ** You are in Controller ** ");
        return "test";
    }

    // This path is no longer used.
    // It will be redirected by OldLoginInterceptor
    @Deprecated
    @RequestMapping(value = { "/admin/oldLogin" })
    public String oldLogin(Model model) {
        // Code here never run.
        return "oldLogin";
    }

    @RequestMapping(value = { "/admin/login" })
    public String login(Model model) {
        System.out.println("\n-------- MainController.login --- ");
        System.out.println(" ** You are in Controller ** ");
        return "login";
    }

}

thymeleaf 模板引擎

test.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
   <head>
      <meta charset="UTF-8" />
      <title>Spring Boot Mvc Interceptor example</title>
   </head>
   <body>
      <div style="border: 1px solid #ccc;padding: 5px;margin-bottom:10px;">
         <a th:href="@{/}">Home</a>
         &nbsp;&nbsp; | &nbsp;&nbsp;
         <a th:href="@{/admin/oldLogin}">/admin/oldLogin (OLD URL)</a>  
      </div>
      <h3>Spring Boot Mvc Interceptor</h3>
      <span style="color:blue;">Testing LogInterceptor</span>
      <br/><br/>
      See Log in Console..
   </body>
</html>

login.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
   <head>
      <meta charset="UTF-8" />
      <title>Spring Boot Mvc Interceptor example</title>
   </head>
   <body>
      <div style="border: 1px solid #ccc;padding: 5px;margin-bottom:10px;">
         <a th:href="@{/}">Home</a>
         &nbsp;&nbsp; | &nbsp;&nbsp;
         <a th:href="@{/admin/oldLogin}">/admin/oldLogin (OLD URL)</a>  
      </div>
      <h3>This is Login Page</h3>
      <span style="color:blue">Testing OldLoginInterceptor &amp; AdminInterceptor</span>
      <br/><br/>
      See more info in the Console.
   </body>
</html>

測試結果

測試用戶訪問 http://localhost:8080/ 的時候, LogInterceptor 記錄相關信息(頁面地址,訪問時間),並計算 Web服務器處理請求的時間。另外,頁面會被渲染成 test.html

當用戶訪問 http://localhost:8080/admin/oldLogin 也就是舊的登錄頁面(不再使用)時, OldLoginInterceptor 將請求重定向 http://localhost:8080/admin/login 頁面會被渲染成正常的登錄頁面 login.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章