J.J. Huang   2019-04-27   Spring Boot   瀏覽次數:次  

SpringBoot - 第三十八章 | 過濾器,監聽器,攔截器

📑 目錄
  1. 過濾器(Filter)
    1. @WebFilter
    2. 建立 CustomFilter
    3. 修改 Chapter38Application
    4. 測試結果
    5. FilterRegistrationBean方式
    6. 修改 CustomFilter
    7. 修改 Chapter38Application
    8. 測試結果
  2. 監聽器(Listeeshi)
    1. 建立 Customlister
    2. 修改 Chapter38Application
    3. 測試結果
  3. 攔截器(Interceptor)
    1. 建立 CustomHandlerInterceptor
    2. 建立 WebMvcConfig
    3. 測試結果
  4. 請求鏈路說明
  5. 攔截器與過濾器的區別

在開發過程中,總存在著這樣的場景,比如攔截請求的ip地址,或者在所有的請求都返回相同的資料,如果每一個方法都寫出相同資料固然可以實現,但是隨著項目的變大,重複的代碼會越來越多,所以在這種情況我們可以用過濾器、監聽器、攔截器來實現以上功能。


過濾器(Filter)

過濾器Filter,是Servlet的的一個實用技術了。可通過過濾器,對請求進行攔截,比如讀取session判斷用戶是否登錄、判斷訪問的請求URL是否有訪問權限(黑白名單)等。主要還是可對請求進行預處理。接下來介紹下,在springboot如何實現過濾器功能。

@WebFilter

@WebFilter時Servlet3.0新增的註解,原先實現過濾器,需要在web.xml中進行配置,而現在通過此註解,啟動啟動時會自動掃描自動註冊。​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

建立 CustomFilter

修改 Chapter38Application

加入@ServletComponentScan註解

測試結果

1
2
3
4
5
6
7
8
9
10
11
2019-04-27 19:41:43.526  INFO 683 --- [           main] c.j.l.s.chapter38.Chapter38Application   : Starting Chapter38Application on localhost with PID 683 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38)
2019-04-27 19:41:43.530 INFO 683 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default
2019-04-27 19:41:44.589 INFO 683 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-27 19:41:44.619 INFO 683 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-27 19:41:44.619 INFO 683 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-27 19:41:44.732 INFO 683 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-27 19:41:44.732 INFO 683 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1142 ms
2019-04-27 19:41:44.801 INFO 683 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化
2019-04-27 19:41:45.035 INFO 683 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-27 19:41:45.266 INFO 683 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-27 19:41:45.270 INFO 683 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.072 seconds (JVM running for 2.443)

過濾器已經生效了。但當註冊多個過濾器時,無法指定執行順序的,原本使用web。 xml配置過濾器時,是可指定執行順序的,但使用@WebFilter時,沒有這個配置屬性的(需要配合@Order進行),所以接下來介紹下通過FilterRegistrationBean進行過濾器的註冊。
通過過濾器的java類名稱,進行順序的約定,比如LogFilter和AuthFilter,此時AuthFilter就會比LogFilter先執行,因為首字母A比L前面。《關於@webFilter使用@Order無效問題》

FilterRegistrationBean方式

FilterRegistrationBean是springboot提供的,此類提供setOrder方法,可以為filter設置排序值,讓spring在註冊web filter之前排序後再依次註冊。​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

修改 CustomFilter

註解掉@WebFilter

1
\\ @WebFilter(filterName = "customFilter", urlPatterns = {"/*"})

修改 Chapter38Application

啟動類中利用@bean註冊FilterRegistrationBean

測試結果

1
2
3
4
5
6
7
8
9
10
11
2019-04-27 20:12:49.425  INFO 772 --- [           main] c.j.l.s.chapter38.Chapter38Application   : Starting Chapter38Application on localhost with PID 772 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38)
2019-04-27 20:12:49.428 INFO 772 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default
2019-04-27 20:12:50.615 INFO 772 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-27 20:12:50.646 INFO 772 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-27 20:12:50.646 INFO 772 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-27 20:12:50.754 INFO 772 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-27 20:12:50.754 INFO 772 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1251 ms
2019-04-27 20:12:50.816 INFO 772 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化
2019-04-27 20:12:51.040 INFO 772 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-27 20:12:51.289 INFO 772 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-27 20:12:51.293 INFO 772 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.293 seconds (JVM running for 2.78)

監聽器(Listeeshi)

Listeeshi是servlet規範中定義的一種特殊類。用於監聽servletContext、HttpSession和servletRequest等域對象的建立和銷毀事件。監聽域對象的屬性發生修改的事件。用於在事件發生前、發生後做一些必要的處理。一般是獲取在線人數等業務需求。​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

建立 Customlister

修改 Chapter38Application

加入@ServletComponentScan註解,進行自動註冊即可。

測試結果

啟動應用,http://localhost:8080

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2019-04-27 20:20:46.638  INFO 784 --- [           main] c.j.l.s.chapter38.Chapter38Application   : Starting Chapter38Application on localhost with PID 784 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38)
2019-04-27 20:20:46.641 INFO 784 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default
2019-04-27 20:20:47.837 INFO 784 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-27 20:20:47.870 INFO 784 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-27 20:20:47.870 INFO 784 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-27 20:20:47.986 INFO 784 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-27 20:20:47.986 INFO 784 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1254 ms
2019-04-27 20:20:48.056 INFO 784 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化
2019-04-27 20:20:48.287 INFO 784 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-27 20:20:48.531 INFO 784 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-27 20:20:48.535 INFO 784 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.316 seconds (JVM running for 2.742)
2019-04-27 20:28:18.445 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化
2019-04-27 20:28:18.445 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化
2019-04-27 20:28:18.450 INFO 784 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-27 20:28:18.450 INFO 784 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-04-27 20:28:18.455 INFO 784 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
2019-04-27 20:28:18.463 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理
2019-04-27 20:28:18.463 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理
2019-04-27 20:28:18.506 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀
2019-04-27 20:28:18.561 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀
2019-04-27 20:28:18.743 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化
2019-04-27 20:28:18.744 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理
2019-04-27 20:28:18.764 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀

攔截器(Interceptor)

以上的過濾器、監聽器都屬於Servlet的api,我們在開發中處理利用以上的進行過濾web請求時,還可以使用Spring提供的攔截器(HandlerInterceptor)進行更加精細的控制。​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

建立 CustomHandlerInterceptor

建立 WebMvcConfig

(注意spring boot 1.x 和 2.x使用方式略有不同)

測試結果

啟動應用,http://localhost:8080

SpringBoot - 第三十八章 - 圖 1 (01)​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2019-04-27 20:54:57.318  INFO 895 --- [           main] c.j.l.s.chapter38.Chapter38Application   : Starting Chapter38Application on localhost with PID 895 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38)
2019-04-27 20:54:57.323 INFO 895 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default
2019-04-27 20:54:58.395 INFO 895 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-27 20:54:58.427 INFO 895 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-27 20:54:58.427 INFO 895 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-27 20:54:58.542 INFO 895 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-27 20:54:58.542 INFO 895 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1154 ms
2019-04-27 20:54:58.614 INFO 895 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化
2019-04-27 20:54:58.858 INFO 895 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-27 20:54:59.115 INFO 895 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-27 20:54:59.118 INFO 895 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.092 seconds (JVM running for 2.457)
2019-04-27 20:55:01.684 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化
2019-04-27 20:55:01.690 INFO 895 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-27 20:55:01.691 INFO 895 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-04-27 20:55:01.698 INFO 895 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
2019-04-27 20:55:01.709 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理
2019-04-27 20:55:01.729 INFO 895 --- [nio-8080-exec-1] c.j.l.s.c.c.CustomHandlerInterceptor : 開始攔截登錄請求....
2019-04-27 20:55:01.732 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀

請求鏈路說明

SpringBoot - 第三十八章 - 圖 2 (02)

攔截器與過濾器的區別

攔截器是AOP( Aspect-Oriented Programming)的一種實現,底層通過動態代理模式完成。

(1)攔截器是基於java的反射機制的,而過濾器是基於函數回調。
(2)攔截器不依賴於servlet容器,而過濾器依賴於servlet容器。
(3)攔截器只能對Controller請求起作用,而過濾器則可以對幾乎所有的請求起作用。
(4)在Controller的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌​‌‌​‌​​‌‌​​‌​​​‌‌​​​​​​‌‌​​​‌​​‌‌‌​​‌​​‌‌​​​​​​‌‌​‌​​​​‌‌​​‌​​​‌‌​‌‌‌​​‌​‌‌​‌​‌‌‌​​‌‌​‌‌‌​​​​​‌‌‌​​‌​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​‌‌​​​‌​​‌‌​‌‌‌‌​‌‌​‌‌‌‌​‌‌‌​‌​​​​‌‌​​‌‌​​‌‌‌​​​

過濾器應用場景:設置編碼字符、過濾銘感字符
攔截器應用場景:攔截未登陸用戶、審計日誌

註:以上參考了
servlet/filter/listener/interceptor区别与联系
(十九)SpringBoot2.0整合拦截器
SpringBoot拦截器
oKongSpringBoot | 第七章:过滤器、监听器、拦截器 文章。