WEB應用開發中的監聽器是指對整個WEB環境的監聽,當被監視的對象(ServletContext)發生狀況(生命週期,setAttribute)時,當即調用相應的方法進行處理。 html
實現了監聽者模式(觀察者模式)。 java
servlet 規範中爲每種事件監聽器都定義了相應的接口,在編寫事件監聽器程序時只需實現這些接口就能夠了。 web 服務器根據用戶編寫的事件監聽器所實現的接口把它註冊到相應的被監聽對象上。 web
一些Servlet事件監聽器須要在web應用程序的部署文件描述符文件(web.xml)中進行註冊,一個web.xml能夠註冊多個servlet事件監聽器。web服務器按照它們在web.xml中註冊順序來加載和註冊這些servlet事件監聽器。 瀏覽器
servlet事件監聽器的註冊和調用過程都是由web容器自動完成的,當發生被監聽的對象被建立,修改,銷燬等事件時,web容器將調用與之相關的servlet事件監聽器對象的相應方法,用戶在這些方法中編寫的事件處理代碼即被執行。 安全
因爲在一個web應用程序中只會爲每一個事件監聽器類建立一個實例對象,有可能出現多個線程同時調用一個事件監聽對象的狀況,因此要注意多線程安全問題。 服務器
用於監聽應用程序環境對象(ServletContext)的事件監聽器 session
用於監聽用戶會話對象(HttpSession)的事件監聽器 多線程
用於監聽請求消息對象(ServletRequest)的事件監聽器 app
用於監聽域對象自身的建立和銷燬的事件監聽器 jsp
用於監聽域對象中的屬性的增長和刪除的事件監聽器
用於監聽綁定到HttpSession域中的某個對象的狀態的事件監聽器域對象建立和銷燬的事件監聽器就是用來監聽 ServletContext, HttpSession, HttpServletRequest 這三個對象的建立和銷燬事件的監聽器。
ServletContext
建立:是在 Web 服務器啓動並加載某個 Web 應用程序時建立相應的ServletContext 對象;銷燬:是在 Web 服務器關閉或卸載時爲每一個 Web 應用程序銷燬相應的ServletContext 對象。
HttpSession
建立:是在瀏覽器開始與服務器會話時建立;銷燬:是在調用HttpSession.invalidate();超過了Session的最大有效時間間隔,服務器進程被中止的時候。
ServletRequest
建立:每次請求開始時建立;銷燬:每次訪問結束後銷燬 。
ServletContextListener 接口
ServletContextListener 接口用於監聽 ServletContext 對象的建立和銷燬事件。方法參數是ServletContextEvent事件是在servlet對象建立時自動激活的事件。
HttpSessionListener 接口
HttpSessionListener 接口用於監聽HttpSession對象的建立和銷燬。銷燬一個Session時,激發public void sessionDestroyed(HttpSessionEvent se)方法。
ServletRequestListener接口
ServletRequestListener 接口用於監聽ServletRequest 對象的建立和銷燬。銷燬一個ServletRequest時,激發public void requestDestroyed(ServletRequestEvent sre)方法。
域對象中屬性的變動的事件監聽器就是用來監聽 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 (ServletRequestAttributeEvent srae)
當對象從 HttpSession 對象中解除綁定時,web 服務器調用該對象的 void valueUnbound(HttpSessionBindingEvent event)方法。
統計當前在線人數
User.java
package cn.heimar.online; public class User { private String id; private String name; private String ip; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } }IndexServlet.java
package cn.heimar.online; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class IndexServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); User u = (User) session.getAttribute("USER_IN_SESSION"); if (u == null) { u = new User(); u.setId(session.getId()); u.setIp(req.getRemoteAddr()); session.setAttribute("USER_IN_SESSION", u); } req.getRequestDispatcher("/WEB-INF/login.jsp").forward(req, resp); } }
LoginServlet.java
package cn.heimar.online; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginServlet extends HttpServlet { private boolean hasLength(String s) { return s != null && !"".equals(s.trim()); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String name = req.getParameter("username"); String password = req.getParameter("password"); if (hasLength(name) && hasLength(password)) { HttpSession session = req.getSession(); User u = (User) session.getAttribute("USER_IN_SESSION"); u.setName(name); req.getRequestDispatcher("/WEB-INF/success.jsp").forward(req, resp); } else { resp.sendRedirect(req.getContextPath()+"/index"); } } }
OnlineServlet.java
package cn.heimar.online; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class OnlineServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String cmd = req.getParameter("cmd"); String id = req.getParameter("id"); List<User> guests = new ArrayList<User>(); List<User> users = new ArrayList<User>(); @SuppressWarnings("unchecked") List<User> onlines = (List<User>) this.getServletContext() .getAttribute("ONLINE_IN_CTX"); if ("remove".equals(cmd) && id != null && !"".equals(id)) { for (User u : onlines) { if (u.getId().equals(id)) { u.setName(null); } } } for (User u : onlines) { if (u.getName() != null) { users.add(u); } else { guests.add(u); } } req.setAttribute("guests", guests); req.setAttribute("users", users); req.getRequestDispatcher("/WEB-INF/online.jsp").forward(req, resp); } }
OnlineServletCtxListener.java
package cn.heimar.online; import java.util.ArrayList; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * 在線用戶統計ServletContext監聽器 * 在應用啓動時,初始化在線用戶列表屬性「ONLINE_IN_CTX」 */ public class OnlineServletCtxListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { sce.getServletContext().setAttribute("ONLINE_IN_CTX", new ArrayList<User>()); } @Override public void contextDestroyed(ServletContextEvent sce) { // TODO Auto-generated method stub } }
OnlineSessionAttrListener.java
package cn.heimar.online; import java.util.List; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; /** * 在線用戶統計HttpSessionAttribute監聽器 * 在當前用戶session中添加「USER_IN_SESSION」時,將該用戶添加到在線用戶列表 */ public class OnlineSessionAttrListener implements HttpSessionAttributeListener { @Override public void attributeAdded(HttpSessionBindingEvent event) { String name = event.getName(); if ("USER_IN_SESSION".equals(name)) { User u = (User) event.getValue(); List<User> onlines = (List<User>) event.getSession() .getServletContext().getAttribute("ONLINE_IN_CTX"); onlines.add(u); } } @Override public void attributeRemoved(HttpSessionBindingEvent se) { // 能夠在用戶退出後將當前用戶從在線用戶列表中刪除。此處不演示 } @Override public void attributeReplaced(HttpSessionBindingEvent se) { // TODO Auto-generated method stub } }
OnlineSessionListener.java
package cn.heimar.online; import java.util.List; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * 在線用戶統計HttpSession監聽器 * 在當前用戶session銷燬時,將該用戶從在線用戶列表中移除 */ public class OnlineSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { // TODO Auto-generated method stub } @Override public void sessionDestroyed(HttpSessionEvent se) { User u = (User) se.getSession().getAttribute("USER_IN_SESSION"); List<User> onlines = (List<User>) se.getSession().getServletContext() .getAttribute("ONLINE_IN_CTX"); for (int i = 0; i < onlines.size(); i++) { User t = onlines.get(i); if (t.getId().equals(u.getId())) { onlines.remove(i); } } } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!--註冊監聽器--> <listener> <listener-class>cn.heimar.online.OnlineServletCtxListener</listener-class> </listener> <listener> <listener-class>cn.heimar.online.OnlineSessionAttrListener</listener-class> </listener> <listener> <listener-class>cn.heimar.online.OnlineSessionListener</listener-class> </listener> <servlet> <servlet-name>index</servlet-name> <servlet-class>cn.heimar.online.IndexServlet</servlet-class> </servlet> <servlet> <servlet-name>login</servlet-name> <servlet-class>cn.heimar.online.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>online</servlet-name> <servlet-class>cn.heimar.online.OnlineServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>index</servlet-name> <url-pattern>/index</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>online</servlet-name> <url-pattern>/online</url-pattern> </servlet-mapping> </web-app>
login.jsp
<%@ 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> <form method="post" action="<%=request.getContextPath() %>/login"> <table> <tr> <td>姓名:</td> <td><input type="text" name="username" /></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="登錄" /></td> </tr> </table> </form> </body> </html>online.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!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> 遊客: <table border="1"> <tr> <td width="100">ID</td> <td width="100">IP</td> </tr> <c:forEach var="g" items="${guests }"> <tr> <td>${g.id }</td> <td>${g.ip }</td> </tr> </c:forEach> </table> <br/> <br/> 在線用戶: <table border="1"> <tr> <td width="100">ID</td> <td width="100">用戶名</td> <td width="100">操做</td> </tr> <c:forEach var="u" items="${users }"> <tr> <td>${u.id }</td> <td>${u.name }</td> <td><a href="<%=request.getContextPath() %>/online?cmd=remove&id=${u.id }">T掉</a></td> </tr> </c:forEach> </table> </body> </html>success.jsp
<%@ 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> 登錄成功.. <br/> <a href="<%=request.getContextPath() %>/online">查看在線用戶列表</a> </body> </html>