02-SpringBoot整合Servlet\過濾器\監聽器
可以看官網
http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/
28、開發Web應用程式
一、SpringBoot整合Servlet
新建一個專案springboot_web
新建包controller, 新建MyController檔案
MyController.java
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestControllerpublic class MyController { @RequestMapping("hello") public String hello(){ return "hello, springboot"; } }
執行程式,瀏覽器訪問:
這就是我們之前搭建web專案最簡單的一種方式, 可以整合servlet
1、Servlet、Filter與Listener
可以看文件中
28.4、內嵌Servlet容器支援
Spring Boot 包含了對內嵌Tomcat、Jetty和Undertow伺服器的支援
使用servlet可以配置Servlet、Filter、Listener
- Servlet業務邏輯類
- Filter 過濾器
- Listener 監聽器
使用內嵌 servlet 容器時,您可以使用 Spring bean 或者掃描方式來註冊 Servlet 規範中的 Servlet、Filter 和所有監聽器(比如HttpSessionListener
)。
任何Servlet
、Filter
或*Listener
的 Spring bean 例項都將被註冊到內嵌容器中。如果您想引用application.properties
中的某個值,這可能會特別方便。
預設情況下,如果上下文只包含單個 Servlet,它將對映到/
。在多個 Servlet bean 的情況下,bean 的名稱將用作路徑的字首。Filter 將對映到/*
如果基於約定配置的對映不夠靈活,您可以使用ServletRegistrationBean
、FilterRegistrationBean
和ServletListenerRegistrationBean
類來完全控制
Spring Boot 附帶了許多可以定義 Filter bean 的自動配置。以下是部分過濾器及其執行順序的(順序值越低,優先順序越高):
Servlet Filter | 順序 |
---|---|
OrderedCharacterEncodingFilter |
Ordered.HIGHEST_PRECEDENCE |
WebMvcMetricsFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
ErrorPageFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
HttpTraceFilter |
Ordered.LOWEST_PRECEDENCE - 10 |
通常 Filter bean 無序放置也是安全的。
如果需要指定順序,則應避免在Ordered.HIGHEST_PRECEDENCE
順序點配置讀取請求體的過濾器,因為它的字元編碼可能與應用程式的字元編碼配置不一致。
如果一個 Servlet 過濾器包裝了請求,則應使用小於或等於OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的順序點對其進行配置。
2、Servlet上下文初始化
我們一般剛接觸web開發的時候第一個接觸的都是servlet, 下面我們來使用springboot來整合servlet
- 編寫servlet類
- 新建包servlet
- 新建MyServlet檔案
-
package xyz.kxq.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "myServlet", urlPatterns = "/srv") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("111"); super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
- 在啟動類上新增如下配置
-
@ServletComponentScan, @SpringBootApplication點進去會有一個@ComponentScan
- 會有一個自動掃描的過程
- 需要把Servlet註冊為當前SpringBoot容器裡面的一個bean
-
package xyz.kxq; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import xyz.kxq.servlet.MyServlet; @SpringBootApplication @ServletComponentScan public class SpringbootWebApplication { public static void main(String[] args) { SpringApplication.run(SpringbootWebApplication.class, args); } @Bean public ServletRegistrationBean<MyServlet> getServletRegistrationBean(){ ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(new MyServlet(), "/s2"); bean.setLoadOnStartup(1); return bean; }
getServletRegistrationBean: 獲取servlet註冊的一個Bean物件,可以加路由(/s2),當配置了urlmappings之後,servlet自己的配置就不會生效了
bean.setLoadOnStartup: 設定servlet什麼時候啟動,配置當前類,設定為1了
-
- 啟動服務
- 訪問http://localhost:8080/myServlet/
- 列印結果為
111 111
- 列印結果為
- 所以說可以自己寫一個servlet類,然後把servlet類注入到springboot裡面就ok了。
二、過濾器
包下新建filter目錄,新建MyFilter檔案
package xyz.kxq.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "MyFilter", urlPatterns = "/filter") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("filter"); chain.doFilter(request, response); } }
重啟服務會發現init執行了
2021-10-21 15:41:40.665 INFO 118196 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 725 ms 2021-10-21 15:41:40.700 INFO 118196 --- [ main] o.s.boot.web.servlet.RegistrationBean : Servlet myServlet was not registered (possibly already registered?) init 2021-10-21 15:41:40.929 INFO 118196 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-10-21 15:41:40.936 INFO 118196 --- [ main] xyz.kxq.SpringbootWebApplication : Started SpringbootWebApplication in 1.34 seconds (JVM running for 2.217)
當訪問http://localhost:8080/filter, 發現filter執行了
2021-10-21 15:44:47.008 INFO 118196 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-10-21 15:44:47.008 INFO 118196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-10-21 15:44:47.009 INFO 118196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
filter
如果所有的請求都需要過濾,urlPatterns="/*"
如果用FilterRegistratronBran設定對應註冊的類,類似於上面servlet,向裡面 new 物件就可以
官網
28.4.1.1、將 Servlet、Filter 和 Listener 註冊為 Spring Bean
三、監聽器
listener是servlet規範定義的一種特殊類,用於監聽servletContext,HttpSession和ServletRequest等域物件的建立和銷燬事件。監聽域物件的屬性發生修改的事件,
用於在事件發生前、發生後做一些必要的處理。可用於一下方面
/* 1、統計線上人數和線上使用者 2、系統啟動時載入初始化資訊 3、統計網站訪問量 4、記錄使用者訪問路徑 */
新建listener目錄,新建MyHttpSessionListener檔案
package xyz.kxq.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { public static int online = 0; @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("建立session"); online++; } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("銷燬session"); } }
需要建立session物件,程式碼中也沒有註解,此時可以在SpringbootWebApplication檔案加入Bean
重新執行,會看到列印listener
2021-10-22 10:26:49.921 INFO 151208 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-10-22 10:26:49.921 INFO 151208 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 747 ms listener
新增控制層程式碼
MyController
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import xyz.kxq.listener.MyHttpSessionListener; @RestController public class MyController { @RequestMapping("hello") public String hello(){ return "hello, springboot"; } @RequestMapping("online") public String online(){ return "當前線上人數: " + MyHttpSessionListener.online + "人"; } }
瀏覽器訪問
重新整理一直是0;
原因:
監聽器中建立session物件後才online++
傳送的請求沒有任何session物件的請求,所以不會++
在MyController
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import xyz.kxq.listener.MyHttpSessionListener; import javax.servlet.http.HttpSession; @RestController public class MyController { @RequestMapping("hello") public String hello(HttpSession session){ session.setAttribute("aa", "aa"); return "hello, springboot"; } @RequestMapping("online") public String online(){ return "當前線上人數: " + MyHttpSessionListener.online + "人"; } }
在瀏覽器訪問