Spring Boot 2.X(九):Spring MVC - 攔截器(Interceptor)

攔截器

1.簡介

Spring MVC 中的攔截器(Interceptor)類似於 Servlet 開發中的過濾器 Filter,它主要用於攔截用戶請求並作相應的處理,它也是 AOP 編程思想的體現,底層通過動態代理模式完成。

2.定義實現類

攔截器有兩種實現方式:
1.實現 HandlerInterceptor 接口
2.繼承 HandlerInterceptorAdapter 抽象類(看源碼最底層也是通過 HandlerInterceptor 接口 實現)

3.HandlerInterceptor方法介紹

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        
        //進行邏輯判斷,如果ok就返回true,不行就返回false,返回false就不會處理請求
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }

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

preHandle:在業務處理器處理請求之前被調用。預處理,可以進行編碼、安全控制、權限校驗等處理;
postHandle:在業務處理器處理請求執行完成後,生成視圖之前執行。
afterCompletion:在 DispatcherServlet 完全處理完請求後被調用,可用於清理資源等。

4.應用場景

1.日誌記錄:記錄請求信息的日誌,以便進行信息監控、信息統計、計算PV(Page View)等;
2.登錄鑑權:如登錄檢測,進入處理器檢測檢測是否登錄;
3.性能監控:檢測方法的執行時間;
4.其他通用行爲。

5.與 Filter 過濾器的區別

1.攔截器是基於java的反射機制的,而過濾器是基於函數回調。
2.攔截器不依賴於servlet容器,而過濾器依賴於servlet容器。
3.攔截器只能對Controller請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4.攔截器可以訪問action上下文、值棧裏的對象,而過濾器不能訪問。
5.在Controller的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
6.攔截器可以獲取IOC容器中的各個bean,而過濾器不行。這點很重要,在攔截器裏注入一個service,可以調用業務邏輯。

具體實現

單個攔截器

1.新建攔截器

    public class Test1Interceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("執行preHandle方法-->01");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("執行postHandle方法-->02");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("執行afterCompletion方法-->03");
    }
}

2.配置攔截器

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /*
     * 攔截器配置
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 註冊自定義攔截器,添加攔截路徑和排除攔截路徑
        registry.addInterceptor(new Test1Interceptor()) // 添加攔截器
                .addPathPatterns("/**") // 添加攔截路徑
                .excludePathPatterns(// 添加排除攔截路徑
                        "/hello").order(0);//執行順序
        super.addInterceptors(registry);
    }

}

3.測試攔截器

@RestController
public class TestController {

    @RequestMapping("/hello")
    public String getHello() {
        System.out.println("這裏是Hello");
        return "hello world";
    }
    
    
    @RequestMapping("/test1")
    public String getTest1() {
        System.out.println("這裏是Test1");
        return "test1 content";
    }
    
    @RequestMapping("/test2")
    public String getTest2() {
        System.out.println("這裏是Test2");
        return "test2 content";
    }
}

4.單個攔截器的執行流程

通過瀏覽器測試:
http://127.0.0.1:8080/hello
結果:

這裏是Hello

http://127.0.0.1:8080/test1 、http://127.0.0.1:8080/test2
結果:

執行preHandle方法-->01
這裏是Test1
執行postHandle方法-->02
執行afterCompletion方法-->03

多個攔截器

1.新建兩個攔截器

Test1Interceptor

public class Test1Interceptor implements HandlerInterceptor{
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("執行Test1Interceptor preHandle方法-->01");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("執行Test1Interceptor postHandle方法-->02");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("執行Test1Interceptor afterCompletion方法-->03");
    }
}

Test2Interceptor

public class Test2Interceptor extends HandlerInterceptorAdapter{


    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("執行Test2Interceptor preHandle方法-->01");
        return true;
    }
    
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("執行Test2Interceptor postHandle方法-->02");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("執行Test2Interceptor afterCompletion方法-->03");
    }
}

2.配置攔截器

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /*
     * 攔截器配置
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 註冊自定義攔截器,添加攔截路徑和排除攔截路徑
        registry.addInterceptor(new Test1Interceptor()) // 添加攔截器1
                .addPathPatterns("/**") // 添加攔截路徑
                .excludePathPatterns(// 添加排除攔截路徑
                        "/hello")
                .order(0);
        registry.addInterceptor(new Test2Interceptor()) // 添加攔截器2
                .addPathPatterns("/**") // 添加攔截路徑
                .excludePathPatterns(// 添加排除攔截路徑
                        "/test1")
                .order(1);
        super.addInterceptors(registry);
    }

}

3.測試攔截器

@RestController
public class TestController {

    @RequestMapping("/hello")
    public String getHello() {
        System.out.println("這裏是Hello");
        return "hello world";
    }
    
    
    @RequestMapping("/test1")
    public String getTest1() {
        System.out.println("這裏是Test1");
        return "test1 content";
    }
    
    @RequestMapping("/test2")
    public String getTest2() {
        System.out.println("這裏是Test2");
        return "test2 content";
    }
}

4.多個攔截器的執行流程

通過瀏覽器測試:
http://127.0.0.1:8080/test2
結果:

執行Test1Interceptor preHandle方法-->01
執行Test2Interceptor preHandle方法-->01
這裏是Test2
執行Test2Interceptor postHandle方法-->02
執行Test1Interceptor postHandle方法-->02
執行Test2Interceptor afterCompletion方法-->03
執行Test1Interceptor afterCompletion方法-->03

通過示例,簡單的說多個攔截器執行流程就是先進後出

簡單的 token 判斷示例

1.攔截器

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("執行Test1Interceptor preHandle方法-->01");
        
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)) {           
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println("token不存在");
            return false;
        }
        return true;
    }

2.測試及結果

未傳token:

執行Test1Interceptor preHandle方法-->01

傳token:

執行Test1Interceptor preHandle方法-->01
頁碼:1
頁碼大小:10
執行Test1Interceptor postHandle方法-->02
執行Test1Interceptor afterCompletion方法-->03

示例代碼

github

碼雲

非特殊說明,本文版權歸 朝霧輕寒 所有,轉載請註明出處.

原文標題:Spring Boot 2.X(九):Spring MVC - 攔截器(Interceptor)

原文地址:https://www.zwqh.top/article/info/18

如果文章對您有幫助,請掃碼關注下我的公衆號,文章持續更新中...

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