詳解Spring 攔截器流程及多個攔截器的執行順序

       攔截器是 Spring MVC 中的組件,它可以在進入請求方法前做一些操作,也可以在請求方法後和渲染視圖後做一些事情。

攔截器的定義

       SpringMVC 的攔截器隻需要實現 HandlerInterceptor 接口,並進行配置即可。HandlerInterceptor 接口的定義如下:

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

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

       在 HandlerInterceptor 中共有三個方法,每個方法的含義如下:

preHandler:進入請求方法之前執行;

postHandler:請求方法執行完成之後執行;

afterCompletion:視圖渲染後執行。

攔截器的執行流程

        在 preHandle 方法中,它的返回值是 boolean 類型的,它的返回值影響著請求方法,以及 postHandle 和 afterCompletion 的執行。具體如下。

        也就是說,在 preHandle 中如果返回 false,那麼後續的流程將不被執行,這可能也是攔截器命名的由來。

測試攔截器

       寫一個簡單攔截器,代碼如下:

@Slf4j
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandler");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandler");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

        創建瞭一個 TestInterceptor 的監聽器類,它實現瞭 HandlerInterceptor 的所有接口。寫完 TestInterceptor 還需要進行註冊。代碼如下:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor());
    }

        再來寫一個簡單的請求方法,代碼如下:

@GetMapping("test")
public String test()
{
    return "test";
}

       來啟動我們的項目,並進行訪問,控制臺的輸出如下:

2021-05-05 16:02:08.110  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : afterCompletion

多個攔截器的執行順序

        我們來寫多個相同的監聽器,分別是 TestInterceptor、TestInterceptor2 和 TestInterceptor3。然後我們進行註冊,註冊代碼如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor3());
}

        請求我們的方法,輸出如下:

2021-05-05 16:09:57.735  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : preHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : postHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : postHandler2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : afterCompletion3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : afterCompletion2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

        註意觀察輸出的順序,preHandle 方法是按註冊順序進行執行的,而 postHandle 和 afterCompletion 跟註冊順序是相反的。

讓 preHandle 進行攔截

        我們讓 TestInterceptor2 的 preHandle 返回值為 false,然後查看一下輸出內容。

2021-05-05 16:14:00.997  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

        可以看到,TestInterceptor2 的 preHandle 的返回值為 false 以後,相當於在 TestInterceptor2 的 preHandle 後續流程則不再繼續執行瞭。

        我們調整一下註冊的順序,代碼如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor3());
}

       修改順序後的輸出如下:

2021-05-05 16:17:23.956  INFO 88589 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2

       可以看到它後面的流程都被攔截瞭,沒有機會執行瞭。

總結

        攔截器是使用一個 List 進行保存,我們可以在項目中添加多個攔截器來完成不同的功能,比如可以進行 Token 的驗證,權限的獲取等。我們可以放到不同的攔截器中來進行相關的操作。

以上就是詳解Spring 攔截器流程及多個攔截器的執行順序的詳細內容,更多關於Spring 攔截器的資料請關註WalkonNet其它相關文章!

推薦閱讀: