1 事件三要素
a)事件源:操做事件的對象,例如:窗體Frame
b)事件監聽器:事件監聽器監聽事件源,例如WindowListner,它是一個接口
c)事件,例如:單擊事件,經過事件,能夠取得事件源javascript
2 適配器模式
a)當一個接口有較多的方法時,而實現類只需對其中少數幾個實現,此時可使用適配器模式
b)適配器模式經常使用於GUI編程,而web監聽器中並不存在Adapter(適配器)
*3 八種web監聽器詳解
a)Web中有三個事件源,分別是ServletContext->HttpSession->ServletRequest
***注意:Listener都是單例模式,當web應用啓動時建立Listener實例,並在web應用中止時銷燬Listener實例。
b)ServletContext對象
>>建立和銷燬:ServletContextListener.
Web容器部署時容器自動調用contextInitialized()方法,
Web容器從新部署時容器自動調用contextDestroyed()方法。
>>屬性變化:ServletContextAttributeListner
application.setAttirbute("name","jack") ----> void attributeAdded(ServletContextAttributeEvent event)
setAttribute("name","傑克") ----> void attributeReplaced(ServletContextAttributeEvent event)
removeAttribute("name") ----> void attributeRemoved(ServletContextAttributeEvent event)java
案例:
1)利用監聽器初始化數據庫
web
code: public class MyServletContextListener implements ServletContextListener { private ContextDao dao = new ContextDao(); @Override public void contextInitialized(ServletContextEvent event) { try { dao.createTable(); System.out.println("建立表成功!"); dao.insertTable("jack"); System.out.println("插入數據成功!"); } catch (SQLException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent event) { try { dao.dropTable(); System.out.println("刪除表成功!"); } catch (SQLException e) { e.printStackTrace(); } } } web.xml <listener> <listener-class>listener.context.MyServletContextListener</listener-class> </listener>
2) 指定時間往數據庫插入一次數據,5秒的延遲
數據庫
public class MyServletContextListener1 implements ServletContextListener { private TimerDao dao = new TimerDao(); private Timer timer; private TimerTask task; public MyServletContextListener1() { this.timer = new Timer(); /*初始化TimerTask對象*/ task = new TimerTask() { @Override public void run() { try { dao.insertTable(UUID.randomUUID().toString(), new Date()); } catch (SQLException e) { e.printStackTrace(); } } }; } public void contextInitialized(ServletContextEvent event) { try { dao.createTable(); //每隔5秒像數據庫插入一條數據 timer.schedule(task, 0, 1000*5); } catch (SQLException e) { e.printStackTrace(); } } public void contextDestroyed(ServletContextEvent event) { try { dao.destoryTable(); } catch (SQLException e) { e.printStackTrace(); } } }
3)ServletContextAttributeListener測試
code:apache
//listener public class MyServletContextAttributeListener implements ServletContextAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent event) { System.out.println("attributeAdded==>" + event.getName() + " : " + event.getValue()); } @Override public void attributeReplaced(ServletContextAttributeEvent event) { //注意:此時的getValue獲得的是替換前的value值。 System.out.println("attributeReplaced==>" + event.getName() + " : " + event.getValue()); } @Override public void attributeRemoved(ServletContextAttributeEvent event) { System.out.println("attriattributeRemoved==>" + event.getName() + " : " + event.getValue()); } } //java application.setAttribute("name", "jack"); application.setAttribute("name", "傑克"); application.removeAttribute("name"); //輸出結果: attributeAdded==>name : jack attributeReplaced==>name : jack attriattributeRemoved==>name : 傑克 c)ServletRequest對象 >>建立和銷燬:ServletRequestListener. 每次請求容器自動調用requestInitialized()方法, 響應完畢容器自動調用requestDestroyed()方法 >>屬性變化:ServletRequestAttributeListner(與ServletContextAttributeListener相似,例子省略) request.setAttirbute("name","jack") setAttribute("name","傑克") removeAttribute("name")
案例:
1)回寫顯示訪問此網站的次數,訪問者ip,以及訪問者本地時間【js】。編程
code: public class MyServletRequestListener implements ServletRequestListener { private Integer queryNum = 0; @Override public void requestDestroyed(ServletRequestEvent event) { System.out.println("requestDestroyed()"); } @Override public void requestInitialized(ServletRequestEvent event) { HttpServletRequest request = (HttpServletRequest) event.getServletRequest(); String ip = request.getRemoteAddr(); synchronized (this) { queryNum++; } request.setAttribute("ip", ip); request.setAttribute("num", queryNum); System.out.println("requestInitialized()"); } } js: <script type="text/javascript"> function nowTime() { window.setInterval("updateTime()", 1000); } function updateTime() { var nowDate = new Date().toLocaleString(); //定位區域並輸出 var spanElement = document.getElementById("spanId"); spanElement.innerHTML = nowDate; } </script> </head> <body onload="nowTime()"> 您的ip:${requestScope.ip} <br/> 網站訪問次數:${requestScope.num} <br/> 當前時間:<span id="spanId"></span> <br/> </body>
d)HttpSession對象
>>建立和銷燬:HttpSessionListener.
當Web容器建立HttpSession對象時容器自動調用sessionCreated()方法
當Web容器銷燬HttpSession對象時容器自動調用sessionDestroyed()方法
>>屬性變化:HttpSessionAttributeListner (與ServletContextAttributeListener相似,例子省略)
session.setAttirbute("name","jack")
setAttribute("name","傑克")
removeAttribute("name") tomcat
案例:
1)HttpSessionListener調用函數測試安全
web.xml <listener> <listener-class>listener.session.MyHttpSessionListener</listener-class> </listener> <!-- 設置session的過時時間爲1分鐘,默認爲30分鐘 【注意:實際上時間並不爲1分鐘】--> <session-config> <session-timeout>1</session-timeout> </session-config> code: public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent event) { HttpSession session = event.getSession(); //若爲新建立的session if (session.isNew()) { System.out.println("sessionCreated, ID:" + session.getId()); } } @Override public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); if (!session.isNew()) { System.out.println("sessionDestroyed, ID:" + session.getId()); } } }
2)利用Session掃描器:精確控制session的聲明週期
code:session
public class SessionScanner implements HttpSessionListener, ServletContextListener { private List<HttpSession> sessionList = Collections.synchronizedList(new ArrayList<HttpSession>()); Timer timer = new Timer(); @Override public void contextInitialized(ServletContextEvent event) { timer.schedule(new MyTimerTask(sessionList), 0, 1*1000); } @Override public void contextDestroyed(ServletContextEvent event) { //取消當前定時器 timer.cancel(); } @Override public void sessionCreated(HttpSessionEvent event) { HttpSession session = event.getSession(); synchronized (sessionList) { sessionList.add(session); } System.out.println("Session產生:" + session.hashCode() + " : " + new Date().toLocaleString() ); } @Override public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); System.out.println("Session銷燬:" + session.hashCode() + " : " + new Date().toLocaleString()); } } class MyTimerTask extends TimerTask { public MyTimerTask(List<HttpSession> sessionList) { this.list = sessionList; } @Override public void run() { synchronized (list) { ListIterator<HttpSession> listIt = list.listIterator(); while(listIt.hasNext()) { HttpSession session = listIt.next(); //測試HttpSession的存在時間 int middle = (int) ( System.currentTimeMillis() - session.getLastAccessedTime() ) / 1000; if (middle > 60 ) { //從list中移除當前HttpSession元素 listIt.remove(); //使得此session失效 session.invalidate(); } } } } }
e)HttpSessionBindListener監聽器,專用於監聽JavaBean對象在HttpSession中的狀態狀況:
檢測JavaBean在Session中的狀態,感知本身什麼時候綁定在HttpSession中,什麼時候從HttpSession中移除。
code:app
//listener public class User implements HttpSessionBindingListener { @Override public void valueBound(HttpSessionBindingEvent event) { System.out.println("valueBound==>" + event.getName() + " : " + event.getValue()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("valueUnbound==>" + event.getName() + " : " + event.getValue()); } } //java session.setAttribute("user", new User()); try { Thread.sleep(10000); } catch (Exception e) { } session.removeAttribute("user");
運行結果:
valueBound==>user : listener.domain.User@5f5220ee
valueUnbound==>user : listener.domain.User@5f5220ee
f)HttpSessionActivationListener監聽器,專用於監聽JavaBean對象的鈍化與激活:
鈍化與激活概念:
1)當HttpSession不用時,但用在HttpSession的有效期中,這時將內存中的HttpSessio移到外存,叫鈍化。
2)反之,將HttpSession由外存移到內存,叫激活。
JavaBean對象,感知本身什麼時候被鈍化,合適被激活,由web容器決定。
配置鈍化激活時間:
針對全部項目:在tomcat的conf/context.xml進行配置.
針對單個項目:只需在此項目的META-INF/加入一個context.xml文件便可。
配置內容以下:
<?xml version="1.0" encoding="utf-8"?> <Context> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> //設置session鈍化時間爲1分鐘 <Store className="org.apache.catalina.session.FileStore" directory="target" /> //設置鈍化文件目標存放目錄 </Manager> </Context>
默認鈍化文件.session的目標文件夾爲: tomcat的work目錄下。
code:
public class Stu implements HttpSessionActivationListener { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public void sessionDidActivate(HttpSessionEvent event) { System.out.println("sessionDidActivate"); } @Override public void sessionWillPassivate(HttpSessionEvent event) { System.out.println("sessionWillPassivate"); } }
注意: 但凡是監聽三個域對象,就須要在web.xml文件中配置,除外,無須要web.xml文件配置。
因此:
HttpSessionBindListener和HttpSessionActivationListener監聽器無需在web.xml中進行配置。
4 監聽器的工做過程和生命週期
開發過程:
a)寫一個普通類實現對應的接口,即事件監聽器
b)在web.xml文件中註冊事件監聽器
<!-- 事件源註冊事件監聽器,由容器完成 -->
<listener>
<listener-class>cn.itcast.web.listener.MyServletContextListener</listener-class>
</listener>
生命週期:
*空參構造(1次)->初始化(1次)->銷燬化(1次),是一個單例的模式
在部署web應用是產生,即用戶第一次訪問以前已經產生,在從新部署web應用時,後銷燬原監聽器,再產生新的監聽器
*5 案例
a)java.util.Timer定時器是之後臺線程方式控制運行,它是線程安全,無需手工加鎖
b)timer.schedule(new MyTimerTask(),0,5000);固定頻度執行
c)Calendar c = Calendar.getInstance();
c.set(2011,10,6,10,30,40);
timer.schedule(new MyTimerTask(),c.getTime());指定時間執行
d)***Serlvet,Filter和Listener同樣具備線程安全問題
e)當HttpSession過時時,Web容器負付執行對應的銷燬方法,可是時間不精確
f)**Listener在Jsp或Servlet以前被執行
g)在線人數使用:context,第N個訪問者使用:session
*補充:Timer類 ———— 定時器(線程安全的)
補充:timer.cancel() 方法,能夠終止Timer定時器
public class TimerDemo { public static void main(String[] args) { Timer timer = new Timer(); //延遲5秒進行,並每隔1秒執行一次任務 //timer.schedule(new MyTimerTask(), 5000, 1000); //在2015年1月12日15時34分50秒執行一次任務 Calendar calendar = Calendar.getInstance(); calendar.set(2015, 0, 12, 15, 34, 50); timer.schedule(new MyTimerTask(), calendar.getTime()); } } class MyTimerTask extends TimerTask { @Override public void run() { System.out.println(new Date().toLocaleString()); } }