概述:
Servlet監(jiān)聽器用于監(jiān)聽一些重要事件的發(fā)生,監(jiān)聽器對(duì)象可以在事情發(fā)生前、發(fā)生后可以做一些必要的處理。
接口:
目前Servlet2.4和JSP2.0總共有8個(gè)監(jiān)聽器接口和6個(gè)Event類,其中HttpSessionAttributeListener與
HttpSessionBindingListener 皆使用HttpSessionBindingEvent;HttpSessionListener和 HttpSessionActivationListener則都使用HttpSessionEvent;其余Listener對(duì)應(yīng)的Event如下所 示:
Listener接口
|
Event類
|
ServletContextListener
|
ServletContextEvent
|
ServletContextAttributeListener
|
ServletContextAttributeEvent
|
HttpSessionListener
|
HttpSessionEvent
|
HttpSessionActivationListener
|
HttpSessionAttributeListener
|
HttpSessionBindingEvent
|
HttpSessionBindingListener
|
ServletRequestListener
|
ServletRequestEvent
|
ServletRequestAttributeListener
|
ServletRequestAttributeEvent
|
分別介紹:
一 ServletContext相關(guān)監(jiān)聽接口
補(bǔ)充知識(shí):
通過ServletContext 的實(shí)例可以存取應(yīng)用程序的全局對(duì)象以及初始化階段的變量。
在JSP文件中,application 是 ServletContext 的實(shí)例,由JSP容器默認(rèn)創(chuàng)建。Servlet 中調(diào)用 getServletContext()方法得到 ServletContext 的實(shí)例。
注意:
全局對(duì)象即Application范圍對(duì)象,初始化階段的變量指在web.xml中,經(jīng)由<context-param>元素所設(shè)定的變量,它的范圍也是Application范圍,例如:
<context-param>
<param-name>Name</param-name>
<param-value>browser</param-value>
</context-param>
當(dāng)容器啟動(dòng)時(shí),會(huì)建立一個(gè)Application范圍的對(duì)象,若要在JSP網(wǎng)頁中取得此變量時(shí):
String name = (String)application.getInitParameter("Name");
或者使用EL時(shí):
${initPara.name}
若是在Servlet中,取得Name的值方法:
String name = (String)ServletContext.getInitParameter("Name");
1.ServletContextListener:
用于監(jiān)聽WEB 應(yīng)用啟動(dòng)和銷毀的事件,監(jiān)聽器類需要實(shí)現(xiàn)javax.servlet.ServletContextListener 接口。
ServletContextListener 是 ServletContext 的監(jiān)聽者,如果 ServletContext 發(fā)生變化,如服務(wù)器啟動(dòng)時(shí) ServletContext 被創(chuàng)建,服務(wù)器關(guān)閉時(shí) ServletContext 將要被銷毀。
ServletContextListener接口的方法:
void contextInitialized(ServletContextEvent sce)
通知正在接受的對(duì)象,應(yīng)用程序已經(jīng)被加載及初始化。
void contextDestroyed(ServletContextEvent sce)
通知正在接受的對(duì)象,應(yīng)用程序已經(jīng)被載出。
ServletContextEvent中的方法:
ServletContext getServletContext()
取得ServletContext對(duì)象
2.ServletContextAttributeListener:用于監(jiān)聽WEB應(yīng)用屬性改變的事件,包括:增加屬性、刪除屬性、修改屬性,監(jiān)聽器類需要實(shí)現(xiàn)javax.servlet.ServletContextAttributeListener接口。
ServletContextAttributeListener接口方法:
void attributeAdded(ServletContextAttributeEvent scab)
若有對(duì)象加入Application的范圍,通知正在收聽的對(duì)象
void attributeRemoved(ServletContextAttributeEvent scab)
若有對(duì)象從Application的范圍移除,通知正在收聽的對(duì)象
void attributeReplaced(ServletContextAttributeEvent scab)
若在Application的范圍中,有對(duì)象取代另一個(gè)對(duì)象時(shí),通知正在收聽的對(duì)象
ServletContextAttributeEvent中的方法:
java.lang.String getName()
回傳屬性的名稱
java.lang.Object getValue()
回傳屬性的值
二、HttpSession相關(guān)監(jiān)聽接口
1.HttpSessionBindingListener接口
注意:HttpSessionBindingListener接口是唯一不需要再web.xml中設(shè)定的Listener
當(dāng)我們的類實(shí)現(xiàn)了HttpSessionBindingListener接口后,只要對(duì)象加入Session范圍 (即調(diào)用HttpSession對(duì)象的setAttribute方法的時(shí)候)或從Session范圍中移出(即調(diào)用HttpSession對(duì)象的 removeAttribute方法的時(shí)候或Session Time out的時(shí)候)時(shí),容器分別會(huì)自動(dòng)調(diào)用下列兩個(gè)方法:
void valueBound(HttpSessionBindingEvent event)
void valueUnbound(HttpSessionBindingEvent event)
思考:如何實(shí)現(xiàn)記錄網(wǎng)站的客戶登錄日志, 統(tǒng)計(jì)在線人數(shù)?
2.HttpSessionAttributeListener接口
HttpSessionAttributeListener監(jiān)聽HttpSession中的屬性的操作。
當(dāng) 在Session增加一個(gè)屬性時(shí),激發(fā)attributeAdded(HttpSessionBindingEvent se) 方法;當(dāng)在Session刪除一個(gè)屬性時(shí),激發(fā)attributeRemoved(HttpSessionBindingEvent se)方法;當(dāng)在Session屬性被重新設(shè)置時(shí),激發(fā)attributeReplaced(HttpSessionBindingEvent se) 方法。這和ServletContextAttributeListener比較類似。
3.HttpSessionListener接口
HttpSessionListener監(jiān)聽 HttpSession的操作。當(dāng)創(chuàng)建一個(gè)Session時(shí),激發(fā)session Created(HttpSessionEvent se)方法;當(dāng)銷毀一個(gè)Session時(shí),激發(fā)sessionDestroyed (HttpSessionEvent se)方法。
4.HttpSessionActivationListener接口
主要用于同一個(gè)Session轉(zhuǎn)移至不同的JVM的情形。
請(qǐng)注意HttpSessionAttributeListener與HttpSessionBindingListener的區(qū)別:
1.前者是需要在web.xml中進(jìn)行描述的,后者不需要。
2.前者是在任何session的屬生變化時(shí)都會(huì)觸發(fā)執(zhí)行其方法中的代碼,而后者只是在實(shí)現(xiàn)它的對(duì)象被綁定到會(huì)話屬性或被從會(huì)話屬生中解除綁定時(shí),才會(huì)觸發(fā)執(zhí)行那個(gè)對(duì)象的valueBound和valueUnboundy這兩個(gè)方法的代碼。比如說有兩個(gè)對(duì)象A和B都實(shí)現(xiàn)了HttpSessionBindingListener接口,當(dāng)A被綁定到會(huì)話屬性中時(shí),只是A的valueBound()方法被觸發(fā)執(zhí)行。
三、ServletRequest監(jiān)聽接口
1.ServletRequestListener接口
和ServletContextListener接口類似的,這里由ServletContext改為ServletRequest
2.ServletRequestAttributeListener接口
和ServletContextListener接口類似的,這里由ServletContext改為ServletRequest
下面說明如何在web.xml中布署事件監(jiān)聽器以實(shí)現(xiàn)對(duì)事件的處理,格式如下:
<listener>
<listener-class>
fey.servlet.listener.CustomServletContextListener
</listener-class >
</listener>
其中fey.servlet.listener.CustomServletContextListener是實(shí)現(xiàn)上述各事件監(jiān)聽器接口的類名。當(dāng)然,你需要將這些類放入Web容器的Web應(yīng)用的classes或lib目錄下以讓W(xué)eb容器可以找到。
另外說明一點(diǎn),一個(gè)類可以一個(gè)或多個(gè)監(jiān)聽器接口。
有的listener可用于統(tǒng)計(jì)網(wǎng)站在線人數(shù)及訪問量。 如下:
服務(wù)器啟動(dòng)時(shí)(實(shí)現(xiàn)ServletContextListener監(jiān)聽器contextInitialized方法),讀取數(shù)據(jù)庫,并將其用一個(gè)計(jì)數(shù)變量保存在application范圍內(nèi)
session創(chuàng)建時(shí)(實(shí)現(xiàn)HttpSessionListener監(jiān)聽器sessionCreated方法),讀取計(jì)數(shù)變量加1并重新保存
服務(wù)器關(guān)閉時(shí)(實(shí)現(xiàn)ServletContextListener監(jiān)聽器contextDestroyed方法),更新數(shù)據(jù)庫
簡(jiǎn)例一
監(jiān)聽用戶上線與退出,顯示在線用戶
1、登陸頁面 Login.jsp
<%@page pageEncoding="gb2312" contentType="text/html; charset=gb2312" %>
<%
session=request.getSession(false);
if(session!=null)session.invalidate();
%>
<html>
<head><title></title></head>
<body>
<form action="isOnline.jsp" method="post">
用戶名:<input type="text" name="uName"/>
<input type="submit" value="上線">
</form>
</body>
</html>
2、控制頁面(只是為了說明監(jiān)聽器問題,所以簡(jiǎn)單了點(diǎn)...) isOnline.jsp
<%@page pageEncoding="gb2312" contentType="text/html; charset=gb2312" %>
<html>
<head><title></title></head>
<body>
<%
session=request.getSession();
session.setAttribute("userName",request.getParameter("uName"));
response.sendRedirect("showOnline.jsp");
%>
</body>
</html>
3、顯示頁面 showOnline.jsp
<%@page pageEncoding="gb2312" contentType="text/html; charset=gb2312" import="java.util.ArrayList" %>
<html>
<head><title></title></head>
<body>
<%
ArrayList showList=(ArrayList)(getServletContext().getAttribute("list"));
out.print("在線人數(shù) "+showList.size()+"<br>");
for(int i=0;i<showList.size();i++){
out.print(showList.get(i)+"在線"+"<br>");
}
%>
<br>
<a href="Login.jsp">退出</a>
</body>
</html>
4、配置頁面 web.xml
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<listener>
<listener-class>org.xiosu.listener.onlineListener</listener-class>
</listener>
</web-app>
5、監(jiān)聽器 onlineListener.java
package org.xiosu.listener;
import java.util.ArrayList;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class onlineListener implements HttpSessionListener,
HttpSessionAttributeListener {
// 參數(shù)
ServletContext sc;
ArrayList list = new ArrayList();
// 新建一個(gè)session時(shí)觸發(fā)此操作
public void sessionCreated(HttpSessionEvent se) {
sc=se.getSession().getServletContext();
System.out.println("新建一個(gè)session");
}
// 銷毀一個(gè)session時(shí)觸發(fā)此操作
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("銷毀一個(gè)session");
if (!list.isEmpty()) {
list.remove((String) se.getSession().getAttribute("userName"));
sc.setAttribute("list", list);
}
}
// 在session中添加對(duì)象時(shí)觸發(fā)此操作,在list中添加一個(gè)對(duì)象
public void attributeAdded(HttpSessionBindingEvent sbe) {
list.add((String) sbe.getValue());
sc.setAttribute("list", list);
}
// 修改、刪除session中添加對(duì)象時(shí)觸發(fā)此操作
public void attributeRemoved(HttpSessionBindingEvent arg0) {
}
public void attributeReplaced(HttpSessionBindingEvent arg0) {
}
}
在Web開發(fā)中關(guān)于監(jiān)聽器的應(yīng)用
首先,也要在web.xml配置文件中進(jìn)行聲明:
在web.xml文件中的聲明如下:(聲明片斷) 要放在filter過濾器聲明和filter-mapping聲明后面
<listener>
<listener-class>markchen.web.listener.MySessionListener</listener-class>
</listener>
<listener>
<listener-class>markchen.web.listener.MyServletContextListener</listener-class>
</listener>
//這兩個(gè)java類的內(nèi)容都和簡(jiǎn)單,僅僅是為了演示說明而已
//MySessionListener.java文件的內(nèi)容如下
//Web應(yīng)用程序中會(huì)話的生命周期監(jiān)聽器實(shí)現(xiàn)
package markchen.web.listener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MySessionListener implements HttpSessionListener {
//在會(huì)話一創(chuàng)建時(shí)該方法被調(diào)用,可以在此處編寫自己需要做特殊處理的程序代碼
public void sessionCreated(HttpSessionEvent event) {
HttpSession session = event.getSession();
String sessionId=session.getId();
System.out.println("Session::::::"+sessionId+"******Created******");
}
//在會(huì)話即將銷毀時(shí)該方法被調(diào)用,可以在此處編寫自己需要做特殊處理的程序代碼
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
String sessionId=session.getId();
System.out.println("Session::::::"+sessionId+"******Destroyed******");
}
}
注意:在sessionDestroyed()方法中一定不要再調(diào)用session.invalidate()方法了
因?yàn)槊空{(diào)用一次session.invalidate()方法都會(huì)觸發(fā)sessionDestroyed()方法的調(diào)用
進(jìn)而形成死循環(huán),最終使Web應(yīng)用程序意外終止
//MyServletContextListener.java
//Web應(yīng)用程序的生命周期監(jiān)聽器實(shí)現(xiàn)
package markchen.web.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
//在Web應(yīng)用程序初始化后該方法被調(diào)用
public void contextInitialized(ServletContextEvent event) {
System.out.println("******Application started******");
}
//在Web應(yīng)用程序銷毀時(shí)該方法被調(diào)用
public void contextDestroyed(ServletContextEvent event) {
System.out.println("******Application ended******");
}
}