監聽器

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());
}
}
相關文章
相關標籤/搜索