JavaWeb(六)Listener監聽器
監聽器
監聽器就是一個實現特定接口的普通java程序,這個程序專門用於監聽另一個java對象的方法調用或屬性改變,當被監聽對象發生上述事件後,監聽器某個方法將立即被執行。
Servlet監聽器
在Servlet規範中定義了多種類型的監聽器,它們用於監聽的事件源分別為 ServletContext, HttpSession 和 ServletRequest 這三個域對象。
Servlet規範針對這三個對象上的操作,又把這多種類型的監聽器劃分為三種類型。
- 監聽三個域對象創建和銷毀的事件監聽器
- 監聽域對象中屬性的增加和刪除的事件監聽器
- 監聽綁定到 HttpSession 域中的某個對象的狀態的事件監聽器。
編寫監聽器
和編寫其它事件監聽器一樣,編寫servlet監聽器也需要實現一個特定的接口,並針對相應動作覆蓋接口中的相應方法。
和其它事件監聽器略有不同的是,servlet監聽器的註冊不是直接註冊在事件源上,而是由WEB容器負責註冊,開發人員只需在web.xml文件中使用<listener>標簽配置好監聽器,web容器就會自動把監聽器註冊到事件源中。
一個 web.xml 文件中可以配置多個 Servlet 事件監聽器,web 服務器按照它們在 web.xml 文件中的註冊順序來加載和註冊這些 Serlvet 事件監聽器。
ServletContext監聽器
ServletContextListener 接口用於監聽 ServletContext 對象的創建和銷毀事件。
當 ServletContext 對象被創建時,激發contextInitialized (ServletContextEvent sce)方法
當 ServletContext 對象被銷毀時,激發contextDestroyed(ServletContextEvent sce)方法。
servletContext域對象何時創建和銷毀:
- 創建:服務器啟動針對每一個web應用創建servletcontext
- 銷毀:服務器關閉前先關閉代表每一個web應用的servletContext
1 package com.hanqi.listener; 2 3 importjavax.servlet.ServletContextEvent; 4 import javax.servlet.ServletContextListener; 5 6 public class TestApplicationListener implements ServletContextListener { 7 8 @Override 9 public void contextDestroyed(ServletContextEvent arg0) { 10 System.out.println("application對象銷毀"); 11 } 12 13 @Override 14 public void contextInitialized(ServletContextEvent arg0) { 15 System.out.println("創建application對象"); 16 } 17 }
訪問時會在控制臺打印“創建application對象”
HttpSession監聽器
HttpSessionListener接口用於監聽HttpSession的創建和銷毀
創建一個Session時,sessionCreated(HttpSessionEvent se) 方法將會被調用。
銷毀一個Session時,sessionDestroyed (HttpSessionEvent se) 方法將會被調用。
Session域對象創建和銷毀的時機創建:用戶每一次訪問時,服務器創建session
- 銷毀:如果用戶的session 30分鐘沒有使用,服務器就會銷毀session,我們在web.xml裏面也可以配置session失效時間
ServletRequest 監聽器
ServletRequestListener 接口用於監聽ServletRequest 對象的創建和銷毀。
Request 對象被創建時,監聽器的requestInitialized方法將會被調用。
Request對象被銷毀時,監聽器的requestDestroyed方法將會被調用。
servletRequest域對象創建和銷毀的時機:
- 創建:用戶每一次訪問,都會創建一個reqeust
- 銷毀:當前訪問結束,request對象就會銷毀
當向被監聽器對象中增加一個屬性時,web容器就調用事件監聽器的 attributeAdded 方法進行相應,這個方法接受一個事件類型的參數,監聽器可以通過這個參數來獲得正在增加屬性的域對象和被保存到域中的屬性對象
各個域屬性監聽器中的完整語法定義為:
- public void attributeAdded(ServletContextAttributeEvent scae)
- public void attributeAdded (HttpSessionBindingEvent hsbe)
- public void attributeAdded(ServletRequestAttributeEvent srae)
監聽三個域的屬性變化
Servlet規範定義了監聽 ServletContext, HttpSession, HttpServletRequest 這三個對象中的屬性變更信息事件的監聽器。
這三個監聽器接口分別是ServletContextAttributeListener, HttpSessionAttributeListener ServletRequestAttributeListener
這三個接口中都定義了三個方法來處理被監聽對象中的屬性的增加,刪除和替換的事件,同一個事件在這三個接口中對應的方法名稱完全相同,只是接受的參數類型不同。
當向被監聽器對象中增加一個屬性時,web容器就調用事件監聽器的 attributeAdded 方法進行相應,這個方法接受一個事件類型的參數,監聽器可以通過這個參數來獲得正在增加屬性的域對象和被保存到域中的屬性對象
各個域屬性監聽器中的完整語法定義為:
- public void attributeAdded(ServletContextAttributeEvent scae)
- public void attributeAdded (HttpSessionBindingEvent hsbe)
- public void attributeAdded(ServletRequestAttributeEvent srae)
當刪除被監聽對象中的一個屬性時,web 容器調用事件監聽器的這個方法進行相應
各個域屬性監聽器中的完整語法定義為:
- public void attributeRemoved(ServletContextAttributeEvent scae)
- public void attributeRemoved (HttpSessionBindingEvent hsbe)
- public void attributeRemoved (ServletRequestAttributeEvent srae)
當監聽器的域對象中的某個屬性被替換時,web容器調用事件監聽器的這個方法進行相應
各個域屬性監聽器中的完整語法定義為:
- public void attributeReplaced(ServletContextAttributeEvent scae)
- public void attributeReplaced (HttpSessionBindingEvent hsbe)
- public void attributeReplaced (ServletRequestAttributeEvent srae)
例子:
1 package com.hanqi.listener.attr; 2 3 import javax.servlet.ServletRequestAttributeEvent; 4 import javax.servlet.ServletRequestAttributeListener; 5 6 public class TestRequestAttributeListener implements ServletRequestAttributeListener { 7 8 @Override 9 public void attributeAdded(ServletRequestAttributeEvent arg0) { 10 System.out.println("request對象添加屬性"); 11 } 12 13 @Override 14 public void attributeRemoved(ServletRequestAttributeEvent arg0) { 15 System.out.println("移除request屬性"); 16 } 17 18 @Override 19 public void attributeReplaced(ServletRequestAttributeEvent arg0) { 20 System.out.println("替換request屬性"); 21 } 22 23 }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% request.setAttribute("hanqi", "淄博漢企");//設置request屬性 request.removeAttribute("hanqi");移除request屬性 session.getCreationTime();//獲取session的創建時間 %> <h1>首頁</h1> <hr> 當前在線人數: <%=application.getAttribute("userCount") %> <hr> 用戶列表: User [sessionid, session創建時間] </body> </html>
應用:統計在線用戶數量和用戶信息
1 package com.util; 2 3 import java.util.Date; 4 5 public class User { 6 private String sid; 7 private Date stime; 8 9 public String getSid() { 10 return sid; 11 } 12 public void setSid(String sid) { 13 this.sid = sid; 14 } 15 public Date getStime() { 16 return stime; 17 } 18 public void setStime(Date stime) { 19 this.stime = stime; 20 } 21 @Override 22 public String toString() { 23 return "User :sid=" + sid + ", stime=" + stime + "|"; 24 } 25 }
1 package com.listener; 2 3 import java.text.SimpleDateFormat; 4 import java.util.ArrayList; 5 import java.util.Date; 6 import java.util.Iterator; 7 8 import javax.servlet.annotation.WebListener; 9 import javax.servlet.http.HttpSession; 10 import javax.servlet.http.HttpSessionEvent; 11 import javax.servlet.http.HttpSessionListener; 12 13 import com.util.User; 14 15 /** 16 * Application Lifecycle Listener implementation class SessionListener 17 * 18 */ 19 @WebListener 20 public class SessionListener implements HttpSessionListener { 21 22 private int userCount;//記錄在線人數 23 private ArrayList<User> userList;//記錄在線人的信息 24 /** 25 * Default constructor. 26 */ 27 public SessionListener() { 28 // TODO Auto-generated constructor stub 29 } 30 31 /** 32 * @see HttpSessionListener#sessionCreated(HttpSessionEvent) 33 */ 34 //session創建時的方法 35 public void sessionCreated(HttpSessionEvent sessionEvent) { 36 // TODO Auto-generated method stub 37 userCount++;//用戶每一次訪問時,服務器創建session,用戶數量+1 38 if(userList==null) { 39 userList = new ArrayList<User>(); 40 } 41 //獲取HttpSession,便於顯示,不用每一次都調用 42 HttpSession session = sessionEvent.getSession(); 43 44 String sessionid = session.getId();//獲取唯一ID 45 long stime = session.getCreationTime();//獲取創建時間 46 //調用方法查看是不是已經存在的用戶,如果不存在,新建用戶存入信息,加到集合中 47 if(!checkUsersSession(sessionid, userList)) { 48 User u = new User(); 49 u.setStime(new Date(stime)); 50 u.setSid(sessionid); 51 userList.add(u); 52 } 53 //設置session屬性,在線人數和在線信息 54 session.getServletContext().setAttribute("userCount", userCount); 55 session.getServletContext().setAttribute("userList", userList); 56 } 57 58 private boolean checkUsersSession(String sessionid, ArrayList<User> userList2) { 59 //查看是不是已經存在的用戶,遍歷集合,如果集合中有某個元素的id等於傳入的id,返回true 60 for(User u : userList2) { 61 if(u.getSid().equals(sessionid)) { 62 return true; 63 } 64 } 65 return false; 66 } 67 68 /** 69 * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent) 70 */ 71 //session銷毀時的方法 72 public void sessionDestroyed(HttpSessionEvent sessionEvent) { 73 //用戶下線,人數-1 74 userCount--; 75 HttpSession session = sessionEvent.getSession(); 76 77 String sessionid = session.getId(); 78 System.out.println(sessionid + "的用戶下線"); 79 //獲取銷毀的用戶的sessionid,在從集合中找到,移除 80 if(checkUsersSession(sessionid, userList)) { 81 Iterator<User> iter = userList.iterator(); 82 while(iter.hasNext()) { 83 User u = iter.next(); 84 if(u.getSid().equals(sessionid)) { 85 iter.remove(); 86 } 87 } 88 } 89 session.getServletContext().setAttribute("userCount", userCount); 90 session.getServletContext().setAttribute("userList", userList); 91 } 92 }
1 <%@ page language="java" contentType="text/html; charset=utf-8" 2 pageEncoding="utf-8" import="java.util.ArrayList,com.util.User"%> 3 <%@ page import="java.util.*" %> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 12 當前在線人數: <%=application.getAttribute("userCount") %> 13 <hr> 14 在線用戶列表:<br> 15 <% 16 List<User> userList = (List<User>)application.getAttribute("userList");//獲取application對象,用戶信息集合 17 if(userList!=null) {//如果集合不為空,遍歷顯示 18 for(User u : userList) { 19 out.print(u+"<br>"); 20 } 21 } 22 %> 23 </body> 24 </html>
嘗試加一個踢人推出的功能
JavaWeb(六)Listener監聽器