day25-Listener監聽器

2022-11-27 21:00:39

Listener監聽器

1.Listener監聽器介紹

  1. Listener監聽器是JavaWeb三大元件之一。JavaWeb三大元件分別是:Servlet程式,Listener監聽器,Filter過濾器。
  2. Listener是JavaEE的規範,即介面。
  3. 監聽器的作用是,監聽某種變化(一般就是物件的建立/銷燬,屬性變化),觸發物件方法完成相應的任務。
  4. JavaWeb中的監聽器共八個,目前最常用的是ServletContextListener,ServletContextAttributeListener,HttpSessionListener和ServletRequestListener

2.JavaWeb的監聽器

2.1ServletContextListener監聽器

  1. 作用:監聽ServletContext建立或者銷燬(當我們web應用啟動時,Tomcat就會建立ServletContext物件),即生命週期監聽
  2. 應用場景:
    • 載入初始化的組態檔;比如spring的組態檔
    • 任務排程(配合定時器Timer/TimerTask)
  3. 相關方法:
    • void contextInitialized(ServletContextEvent sce):建立ServletContext物件時觸發
    • void contextDestroyed(ServletContextEven sce):銷燬ServletContext物件時觸發

應用範例

  1. 首先建立一個專案,新增web支援,因為listener監聽器是Servlet規範,要使用就要引入Servlet.jar包

    image-20221127165358783
  2. 建立一個普通類,如果該類實現了某個監聽介面,那麼此類就是一個監聽器。該類可以監聽的事件由該類實現的監聽介面決定:

    package com.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    /**
     * 1.當一個類實現了 ServletContextListener 介面時
     * 2.該類就是一個監聽器
     * 3.該類可以監聽的事件由該類實現的監聽介面決定 ,比如實現ServletContextListener介面,
     * 那麼該類就可以監聽ServletContext物件的建立和銷燬,以此類推
     * 4.下面的MyServletContextListener就是一個監聽者
     * 5.當web應用啟動時,就會產生ServletContextEvent事件,會呼叫監聽器的對應事件處理方法
     * 如:contextInitialized(),同時會傳遞 事件物件
     * 6.程式設計師可以通過 ServletContextEvent 事件物件,來獲取需要的資訊,然後再進行業務處理
     * 7.Tomcat怎麼知道這個監聽器存在呢? 因為我們需要在web.xml檔案中進行設定,
     * 一旦設定後,tomcat啟動後就會反射範例化該監聽器,放到容器裡面去管理
     */
    public class MyServletContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            ServletContext servletContext = servletContextEvent.getServletContext();
            System.out.println("MyServletContextListener監聽到=" +
                    servletContext + "被建立...");
            //如果我們獲取到ServletContext物件..可以進行業務處理
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
            ServletContext servletContext = servletContextEvent.getServletContext();
            System.out.println("MyServletContextListener監聽到=" +
                    servletContext + "被銷燬...");
            //比如可以對ServletContext 資料進行處理,或者紀錄檔的管理...
            System.out.println("進行處理工作...");
        }
    }
    
  3. 設定web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
             version="4.0">
        <!--設定監聽器-->
        <listener>
            <listener-class>com.listener.MyServletContextListener</listener-class>
        </listener>
    </web-app>
    
  4. 設定Tomcat

  5. 點選啟動tomcat時,我們可以看到監聽器被觸發了:

    image-20221127172929861
  6. 點選停止tomcat時,可以看到監聽器再一次被觸發:

    image-20221127172702514

2.2ServletContextAttributeListener監聽器

  1. 作用:監聽ServletContext屬性的變化
  2. 相關方法:
    • void attributeAdded(ServletContextAttributeEvent event):新增屬性時呼叫
    • void attributeReplaced(ServletContextAttributeEvent event):替換屬性時呼叫
    • void attributeRemoved(ServletContextAttributeEvent event):移除屬性時呼叫

應用範例

  1. 建立監聽器:MyServletContextAttributeListener
package com.listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;

public class MyServletContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("MyServletContextAttributeListener 監聽到新增屬性.." +
                servletContextAttributeEvent.getName() + "=" +
                servletContextAttributeEvent.getValue());
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("MyServletContextAttributeListener 監聽到刪除屬性.." +
                servletContextAttributeEvent.getName() + "=" +
                servletContextAttributeEvent.getValue());
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("MyServletContextAttributeListener 監聽到修改屬性.." +
                servletContextAttributeEvent.getName() + "=" +
                servletContextAttributeEvent.getValue());
    }
}
  1. 建立servlet:HiServlet
package com.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class HiServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //給ServletContext物件操作屬性
        ServletContext servletContext = getServletContext();
        //新增屬性
        servletContext.setAttribute("name", "傑克");
        //修改屬性
        servletContext.setAttribute("name", "托馬斯");
        //刪除屬性
        servletContext.removeAttribute("name");

        System.out.println("HiServlet 處理完畢...");
    }
}
  1. web.xml:設定監聽器和servlet
<!--設定監聽器-->
<listener>
    <listener-class>com.listener.MyServletContextAttributeListener</listener-class>
</listener>
<!--設定HiServlet-->
<servlet>
    <servlet-name>HiServlet</servlet-name>
    <servlet-class>com.HiServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HiServlet</servlet-name>
    <url-pattern>/hiServlet</url-pattern>
</servlet-mapping>
  1. 重新發布tomcat,在瀏覽器中存取servlet,後臺輸出如下:

    image-20221127175211190

2.3HttpSessionListener監聽器

  1. 作用:監聽Session建立或銷燬,即生命週期監聽
  2. 相關方法:
    • void sessionCreated(HttpSessionEvent se):建立session時呼叫
    • void sessionDestroyed(HttpSessionEvent se):銷燬session時呼叫
  3. 使用方法和前面一樣,可以用於監聽使用者上線,離線

應用範例

  1. 建立監聽器:MyHttpSessionListener
package com.listener;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyHttpSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        //當session被建立時,設定一個生命週期10s
        session.setMaxInactiveInterval(10);
        System.out.println("MyHttpSessionListener 監聽到session建立= " + session.getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        System.out.println("MyHttpSessionListener 監聽到session銷燬= " + session.getId());
    }
}
  1. 修改HiServlet程式碼:
package com.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class HiServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取session物件
        request.getSession();
        System.out.println("HiServlet 處理完畢...");
    }
}
  1. 設定監聽器:
<listener>
    <listener-class>com.listener.MyHttpSessionListener</listener-class>
</listener>
  1. 現在我們重啟Tomcat,可以看到還沒有存取HiServlet,就已經建立了兩個session。這是因為啟動Tomcat時,會預設存取專案首頁面,tomcat會自動建立兩個session,這裡忽略即可。

    image-20221127181720060
  2. 在瀏覽器存取HiServlet,可以看到後臺首先建立了一個session,在設定的生命週期內不存取該session,顯示該session被銷燬。

    image-20221127182810302

HttpSessionListener監聽器可以用於監聽使用者上線離線

注意:這裡的session不是瀏覽器一關閉就銷燬,session的銷燬是伺服器端去輪詢決定的,因此如果想要使用者瀏覽器一關閉就銷燬session,可以通過前端在使用者瀏覽器關閉之前,向伺服器傳送一個通知,伺服器收到通知後銷燬該session即可。

2.4HttpSessionAttributeListener監聽器

  1. 作用:監聽Session屬性的變化
  2. 相關方法:
    • void attributeAdded(ServletRequestAttributeEvent event):新增屬性時呼叫
    • void attributeReplaced(ServletRequestAttributeEvent event):替換屬性時呼叫
    • void attributeRemoved(ServletRequestAttributeEvent event):移除屬性時呼叫
  3. 使用少,使用方法和前面一樣。

應用範例

  1. 建立監聽器:MyHttpSessionAttributeListener
package com.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("MyHttpSessionAttributeListener 監聽到 session新增屬性= "
                + httpSessionBindingEvent.getName() + "=" + httpSessionBindingEvent.getValue());
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("MyHttpSessionAttributeListener 監聽到 session刪除屬性= "
                + httpSessionBindingEvent.getName() + "=" + httpSessionBindingEvent.getValue());
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("MyHttpSessionAttributeListener 監聽到 session修改屬性= "
                + httpSessionBindingEvent.getName() + "=" + httpSessionBindingEvent.getValue());
    }
}
  1. 修改HiServlet
package com.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class HiServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取session物件
        HttpSession session = request.getSession();
        //新增屬性
        session.setAttribute("age", 888);
        //修改屬性
        session.setAttribute("age", 999);
        //刪除屬性
        session.removeAttribute("age");
        System.out.println("HiServlet 處理完畢...");
    }
}
  1. 設定監聽器
<listener>
    <listener-class>com.listener.MyHttpSessionAttributeListener</listener-class>
</listener>
  1. redeployTomcat,在瀏覽器存取hiServlet,後臺輸出如下:

    image-20221127185403369

2.5ServletRequestListener監聽器

  1. 作用:監聽Request建立或者銷燬,即Request物件的生命週期監聽
  2. 相關方法:
    • void requestInitialized(ServletRequestEvent sre):建立request物件時觸發
    • void requestDestroyed(ServletRequestEvent sre):銷燬request物件時觸發
  3. 可以用來監控某個IP存取我們網站的頻率,做紀錄檔記錄,或者存取資源的情況等。

應用範例

  1. 建立監聽器:MyServletRequestListener
package com.listener;

import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;

public class MyServletRequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("MyServletRequestListener 監聽到request物件被建立 ");
        ServletRequest servletRequest = servletRequestEvent.getServletRequest();
        System.out.println("記錄存取紀錄檔...");
        System.out.println("存取IP= " + servletRequest.getRemoteAddr());
        System.out.println("存取的資源= " + ((HttpServletRequest) servletRequest).getRequestURL());

    }

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("MyServletRequestListener 監聽到request物件被銷燬...");
    }
}
  1. hiServlet不做修改

  2. 設定監聽器:

<listener>
    <listener-class>com.listener.MyServletRequestListener</listener-class>
</listener>
  1. redeployTomcat,在瀏覽器存取hiServlet,後臺輸出如下:

    (中間的session監聽可忽略)

    image-20221127191733329
  2. 存取專案首頁面,後臺輸出如下:

    image-20221127192003350

2.6ServletRequestAttributeListener監聽器

  1. 作用:監聽Request屬性變化
  2. 相關方法
    • void attributeAdded(ServletRequestAttributeEvent srae):新增屬性時呼叫
    • void attributeReplaced(ServletRequestAttributeEvent srae):替換屬性時呼叫
    • void attributeRemoved(ServletRequestAttributeEvent srae):移除屬性時呼叫
  3. 使用方法和前面類似

2.7HttpSessionBindingListener感知監聽器

該監聽器是用來繫結資料的。如果一個物件實現了HttpSessionBindingListener介面,當這個物件被繫結到Session中或者從session中被刪除時,Servlet容器會通知這個物件,而這個物件在接收到通知後,可以做一些初始化或清除狀態的操作。

2.8HttpSessionActivationListener感知監聽器

HttpSessionActivationListener用於監控實現類本身,當實現類物件被新增到session屬性中後,session物件序列化(鈍化)前和反序列化(活化)後都會被執行

相應的方法:

  • sessionWillPassivate(HttpSessionEvent se): session鈍化前執行(session從記憶體到硬碟)
  • sessionDidActivate(HttpSessionEvent se):session活化後執行(session從硬碟到記憶體)