1. 程式人生 > >java中servletContextListener、httpSessionListener和servletRequestListener使用整理

java中servletContextListener、httpSessionListener和servletRequestListener使用整理

在java web應用中,listener監聽器似乎是必不可少的,常常用來監聽servletContext、httpSession、servletRequest等域物件的建立、銷燬以及屬性的變化等等,可以在這些事件動作前後進行一定的邏輯處理。
比較常用的應用場景是利用監聽器來初始化一些資料、統計線上人數、統計web應用瀏覽量等等。
這裡所說的監聽器實際上是servlet規範中定義的一種特殊類,需要實現特定的介面。
而我暫時先說其中三個用來監聽域物件的,分別是servletContextListener、httpSessionListener、servletRequestListener。
這三個介面寫法上實際是差不多的,都有兩個分別代表了該域物件建立時呼叫和銷燬時呼叫的方法,據我的理解,這三個物件最大的區別應該就是作用域不一樣。
servletContext在整個應用啟動到結束中生效,啟動系統時建立這個物件,整個過程中這個物件是唯一的。
httpSession則是在一個session會話中生效,在一個session被建立直到失效的過程中都起作用,不過一個啟動的應用中httpSession物件可以有多個,比如同一臺電腦兩個瀏覽器訪問,就會建立兩個httpSession物件。
而servletRequest是在一個request請求被建立和銷燬的過程中生效,每發起一次請求就會建立一個新的servletRequest物件,比如重新整理瀏覽器頁面、點選應用的內鏈等等。
這三個監聽器的寫法基本如下虛擬碼所示:
首先建立一個監聽器類實現相應的介面及方法:

package packageName;
public class ListenerName implements *Listener {

    @Override
    public void 物件建立時被呼叫的方法(相應的事件 arg0) {

    }

    @Override
    public void 物件銷燬時被呼叫的方法(相應的事件 arg0) {

    }
}

然後在web.xml中註冊:

 <listener>
    <listener-class>packageName.ListenerName</listener-class
>
</listener>

到這裡,基本上這個監聽器在啟動web伺服器以後就可以正常跑了,只是有時候我們還會在註冊監聽器的時候配置一些其他的。
比如配置servletContextListener的時候,可能會加上context-param引數:

<context-param>
     <param-name>paramName</param-name>
     <param-value>paramValue</param-value>
</context-param>

配置httpSessionListener的時候,可能會加上session超時:

<session-config>
     <session-timeout>1</session-timeout>
</session-config>

我感覺經過這樣一整理後,就會發現起始監聽器寫起來還是很簡單的,於是便模擬簡單的實現了線上使用者統計和應用訪問量,基本程式碼如下:
首先是實現了servletContext

package webTest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Date;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ListenerTest1 implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {

        System.out.println("contextDestroyed" + "," + new Date());
        Object count = arg0.getServletContext().getAttribute("count");
        File file = new File("count.txt");
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write(count.toString());
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("contextInitialized" + "," + new Date());
        File file = new File("count.txt");
        if (file.exists()) {
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
                BufferedReader bReader = new BufferedReader(inputStreamReader);
                String count = bReader.readLine();
                System.out.println("歷史訪問次數:" + count);
                arg0.getServletContext().setAttribute("count", count);
                bReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

這裡我把訪問次數存在一個txt檔案中,以便於持久化儲存,當專案啟動的時候,也就是建立servletContext物件的時候呼叫載入方法,從txt檔案中讀取歷史訪問量,然後使用setAttribute方法把這個資料存入到記憶體中。
之後當應用被關閉,servletContext物件被銷燬的時候把記憶體中新的訪問量資料覆蓋寫入到txt檔案,以便於下次啟動應用後繼續讀取之前的訪問量。
然後使用servletRequestListener來實現web瀏覽量的變化,當然了,這裡只是簡單的實現,如果是要實現那種同一個使用者重新整理頁面不增加瀏覽量的功能,還需要做更多的處理。

package webTest;
import java.util.Date;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class ListenerTest3 implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent arg0) {
        System.out.println("requestDestroyed" + "," + new Date());
        System.out.println("當前訪問次數:" + arg0.getServletContext().getAttribute("count"));
    }

    @Override
    public void requestInitialized(ServletRequestEvent arg0) {
        System.out.println("requestInitialized" + "," + new Date());
        Object count = arg0.getServletContext().getAttribute("count");
        Integer cInteger = 0;
        if (count != null) {
            cInteger = Integer.valueOf(count.toString());
        }
        System.out.println("歷史訪問次數::" + count);
        cInteger++;
        arg0.getServletContext().setAttribute("count", cInteger);
    }

}

這裡同樣是兩個方法,在servletRequest物件被建立的時候呼叫初始化方法,從記憶體中讀取servletContext物件的count屬性,而後輸出歷史訪問量。
同時在此基礎上加一重新設定servletContext物件的count屬性的內容,當servletRequest物件被銷燬的時候呼叫銷燬時的方法打印出當前瀏覽量,這樣就簡單的實現了web瀏覽的量的累加計數。
然後就是利用httpSessionListener來實現線上人數的統計:

package webTest;
import java.util.Date;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class ListenerTest2 implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        System.out.println("sessionCreated" + "," + new Date());
        Object lineCount = arg0.getSession().getServletContext().getAttribute("lineCount");
        Integer count = 0;
        if (lineCount == null) {
            lineCount = "0";
        }
        count = Integer.valueOf(lineCount.toString());
        count++;
        System.out.println("新上線一人,歷史線上人數:" + lineCount + "個,當前線上人數有: " + count + " 個");
        arg0.getSession().getServletContext().setAttribute("lineCount", count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {
        System.out.println("sessionDestroyed" + "," + new Date());
        Object lineCount = arg0.getSession().getServletContext().getAttribute("lineCount");
        Integer count = Integer.valueOf(lineCount.toString());
        count--;
        System.out.println("一人下線,歷史線上人數:" + lineCount + "個,當前線上人數: " + count + " 個");
        arg0.getSession().getServletContext().setAttribute("lineCount", count);
    }

}

這裡的程式碼都很簡單,我想應該沒有太多必要解釋,需要說明的是,我這裡把lineCount存放在servletContext物件中並不是唯一的方式,有興趣的朋友可以嘗試其他的方式,例如使用類屬性。
這裡的示例也已打包上傳,需要的朋友可以自行下載執行。
連結:http://pan.baidu.com/s/1bZ2vx0
密碼:ekb9