在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>
我感覺經過這樣一整理后,就會發現起始監聽器寫起來還是非常easy的。於是便模擬簡單的實現了在線用戶統計和應用訪問量,基本代碼例如以下:
首先是實現了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);
}
}
這里的代碼都非常easy。我想應該沒有太多必要解釋,須要說明的是。我這里把lineCount存放在servletContext對象中並非唯一的方式,有興趣的朋友能夠嘗試其它的方式。比如使用類屬性。
這里的演示樣例也已打包上傳。須要的朋友能夠自行下載執行。
鏈接:http://pan.baidu.com/s/1bZ2vx0
password:ekb9