1. 程式人生 > 其它 >02-SpringBoot整合Servlet\過濾器\監聽器

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;

@RestController
public class MyController { @RequestMapping("hello") public String hello(){ return "hello, springboot"; } }

執行程式,瀏覽器訪問:

這就是我們之前搭建web專案最簡單的一種方式, 可以整合servlet

1、Servlet、Filter與Listener

可以看文件中

28.4、內嵌Servlet容器支援

Spring Boot 包含了對內嵌TomcatJettyUndertow伺服器的支援

使用servlet可以配置Servlet、Filter、Listener

  • Servlet業務邏輯類
  • Filter 過濾器
  • Listener 監聽器

使用內嵌 servlet 容器時,您可以使用 Spring bean 或者掃描方式來註冊 Servlet 規範中的 Servlet、Filter 和所有監聽器(比如HttpSessionListener)。

任何ServletFilter*Listener的 Spring bean 例項都將被註冊到內嵌容器中。如果您想引用application.properties中的某個值,這可能會特別方便。

預設情況下,如果上下文只包含單個 Servlet,它將對映到/。在多個 Servlet bean 的情況下,bean 的名稱將用作路徑的字首。Filter 將對映到/*

如果基於約定配置的對映不夠靈活,您可以使用ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean類來完全控制

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

  1. 編寫servlet類
    1. 新建包servlet
    2. 新建MyServlet檔案
    3. 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);
          }
          
      }
  2. 在啟動類上新增如下配置
    1. @ServletComponentScan, @SpringBootApplication點進去會有一個@ComponentScan
    2. 會有一個自動掃描的過程
    3. 需要把Servlet註冊為當前SpringBoot容器裡面的一個bean
    4. 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了
  3. 啟動服務
  4. 訪問http://localhost:8080/myServlet/
    1. 列印結果為
      111
      111
  5. 所以說可以自己寫一個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 物件就可以

官網

http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/pages/spring-boot-features.html#boot-features-embedded-container-servlets-filters-listeners

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 + "人";
    }
}

在瀏覽器訪問