Servlet 监听器Listener详解

时间:2021-09-21 21:56:26

转自:http://blog.csdn.net/u012228718/article/details/41730799

一、简介

(一)概述

1、Listener 用于监听 Javaweb程序中的事件,例如创建、修改、删除Session、request、context等,并触发响应的事件。

2、 Listener 对应观察者模式,事件发生的时候会自动触发该事件对应的Listeer。 Listener 主要用于对 Session、request、context 进行监控。servlet2.5 规范*有 8 种Listener  。

(二)实现

1、不同功能的Listener 需要实现不同的 Listener  接口,一个Listener也可以实现多个接口,这样就可以多种功能的监听器一起工作。

2、8种监听器可以分为三类:

1)监听 Session、request、context 的创建于销毁,分别为

HttpSessionLister、ServletContextListener、ServletRequestListener

2)监听对象属性变化,分别为:

HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener

3)监听Session 内的对象,分别为HttpSessionBindingListener 和 HttpSessionActivationListener。与上面六类不同,这两类 Listener 监听的是Session 内的对象,而非 Session 本身,不需要在 web.xml中配置。

2、实现web.xml的Listener配置。

1)<listener>标签与 <listener-class>

2)<listener>一般配置在 <servlet>便签的前面。

  1. package servlet.listener;
  2. import javax.servlet.ServletContextEvent;
  3. import javax.servlet.ServletContextListener;
  4. /**
  5. *
  6. * MyListener.java
  7. *
  8. * @title Context监听器
  9. * @description
  10. * @author SAM-SHO
  11. * @Date 2014-9-25
  12. */
  13. public class MyListener implements ServletContextListener {
  14. public void contextDestroyed(ServletContextEvent sce) {
  15. }
  16. public void contextInitialized(ServletContextEvent sce) {
  17. }
  18. }
  1. <!--监听器 -->
  2. <listener>
  3. <listener-class>servlet.listener.MyListener</listener-class>
  4. </listener>

二、八种类型监听器

(一)监听 Session、request、context 的创建于销毁。

HttpSessionLister、ServletContextListener、ServletRequestListener

1、三种监听器的触发时机及使用:

Servlet  监听器Listener详解

2、实例:实现监听对象的创建与销毁

  1. package servlet.listener;
  2. import javax.servlet.ServletContext;
  3. import javax.servlet.ServletContextEvent;
  4. import javax.servlet.ServletContextListener;
  5. import javax.servlet.ServletRequestEvent;
  6. import javax.servlet.ServletRequestListener;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpSession;
  9. import javax.servlet.http.HttpSessionEvent;
  10. import javax.servlet.http.HttpSessionListener;
  11. import org.apache.commons.logging.Log;
  12. import org.apache.commons.logging.LogFactory;
  13. /**
  14. *
  15. * ListenerTest.java
  16. *
  17. * @title 监听对象的创建与销毁
  18. * @description
  19. * @author SAM-SHO
  20. * @Date 2014-12-10
  21. */
  22. public class ListenerTest implements HttpSessionListener, ServletContextListener, ServletRequestListener {
  23. Log log = LogFactory.getLog(getClass());
  24. // 创建 session
  25. public void sessionCreated(HttpSessionEvent se) {
  26. HttpSession session = se.getSession();
  27. log.info("新创建一个session, ID为: " + session.getId());
  28. }
  29. // 销毁 session
  30. public void sessionDestroyed(HttpSessionEvent se) {
  31. HttpSession session = se.getSession();
  32. log.info("销毁一个session, ID为: " + session.getId());
  33. }
  34. // 加载 context
  35. public void contextInitialized(ServletContextEvent sce) {
  36. ServletContext servletContext = sce.getServletContext();
  37. log.info("即将启动" + servletContext.getContextPath());
  38. }
  39. // 卸载 context
  40. public void contextDestroyed(ServletContextEvent sce) {
  41. ServletContext servletContext = sce.getServletContext();
  42. log.info("即将关闭" + servletContext.getContextPath());
  43. }
  44. // 创建 request
  45. public void requestInitialized(ServletRequestEvent sre) {
  46. HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
  47. String uri = request.getRequestURI();
  48. uri = request.getQueryString() == null ? uri : (uri + "?" + request.getQueryString());
  49. request.setAttribute("dateCreated", System.currentTimeMillis());
  50. log.info("IP " + request.getRemoteAddr() + " 请求 " + uri);
  51. }
  52. // 销毁 request
  53. public void requestDestroyed(ServletRequestEvent sre) {
  54. HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
  55. long time = System.currentTimeMillis() - (Long) request.getAttribute("dateCreated");
  56. log.info(request.getRemoteAddr() + "请求处理结束, 用时" + time + "毫秒. ");
  57. }
  58. }

(二)监听对象属性变化,分别为HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener

1、三种监听器的触发时机及使用:

Servlet  监听器Listener详解

2、实例:实现对象属性的监听

  1. package servlet.listener;
  2. import javax.servlet.http.HttpSession;
  3. import javax.servlet.http.HttpSessionAttributeListener;
  4. import javax.servlet.http.HttpSessionBindingEvent;
  5. import org.apache.commons.logging.Log;
  6. import org.apache.commons.logging.LogFactory;
  7. /**
  8. *
  9. * SessionAttributeListenerTest.java
  10. *
  11. * @title 监听Session对象的属性
  12. * @description
  13. * @author SAM-SHO
  14. * @Date 2014-12-10
  15. */
  16. public class SessionAttributeListenerTest implements HttpSessionAttributeListener {
  17. Log log = LogFactory.getLog(getClass());
  18. // 添加属性
  19. public void attributeAdded(HttpSessionBindingEvent se) {
  20. HttpSession session = se.getSession();
  21. String name = se.getName();
  22. log.info("新建session属性:" + name + ", 值为:" + se.getValue());
  23. }
  24. // 删除属性
  25. public void attributeRemoved(HttpSessionBindingEvent se) {
  26. HttpSession session = se.getSession();
  27. String name = se.getName();
  28. log.info("删除session属性:" + name + ", 值为:" + se.getValue());
  29. }
  30. // 修改属性
  31. public void attributeReplaced(HttpSessionBindingEvent se) {
  32. HttpSession session = se.getSession();
  33. String name = se.getName();
  34. Object oldValue = se.getValue();
  35. log.info("修改session属性:" + name + ", 原值:" + oldValue + ", 新值:" + session.getAttribute(name));
  36. }
  37. }

(三)监听Session 内的对象,分别为HttpSessionBindingListener 和 HttpSessionActivationListener

1、触发时机及使用:对象必须实现Listener接口,不需要在web.xml中配置

Servlet  监听器Listener详解

2、实例:实现对象属性的监听

  1. package servlet.listener;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. import javax.servlet.http.HttpSession;
  5. import javax.servlet.http.HttpSessionActivationListener;
  6. import javax.servlet.http.HttpSessionBindingEvent;
  7. import javax.servlet.http.HttpSessionBindingListener;
  8. import javax.servlet.http.HttpSessionEvent;
  9. import org.apache.commons.logging.Log;
  10. import org.apache.commons.logging.LogFactory;
  11. /**
  12. *
  13. * PersonInfo.java
  14. *
  15. * @title 同时实现多个接口
  16. * 被串行化,需要实现Serializable接口
  17. * @description
  18. * @author SAM-SHO
  19. * @Date 2014-12-10
  20. */
  21. public class PersonInfo implements HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
  22. private static final long serialVersionUID = -4780592776386225973L;
  23. Log log = LogFactory.getLog(getClass());
  24. private String name;
  25. private Date dateCreated;
  26. // 从硬盘加载后
  27. public void sessionDidActivate(HttpSessionEvent se) {
  28. HttpSession session = se.getSession();
  29. log.info(this + "已经成功从硬盘中加载。sessionId: " + session.getId());
  30. }
  31. // 即将被钝化到硬盘时
  32. public void sessionWillPassivate(HttpSessionEvent se) {
  33. HttpSession session = se.getSession();
  34. log.info(this + "即将保存到硬盘。sessionId: " + session.getId());
  35. }
  36. // 被放进session前
  37. public void valueBound(HttpSessionBindingEvent event) {
  38. HttpSession session = event.getSession();
  39. String name = event.getName();
  40. log.info(this + "被绑定到session \"" + session.getId() + "\"的" + name + "属性上");
  41. // 记录放到session中的时间
  42. this.setDateCreated(new Date());
  43. }
  44. // 从session中移除后
  45. public void valueUnbound(HttpSessionBindingEvent event) {
  46. HttpSession session = event.getSession();
  47. String name = event.getName();
  48. log.info(this + "被从session \"" + session.getId() + "\"的" + name + "属性上移除");
  49. }
  50. @Override
  51. public String toString() {
  52. return "PersonInfo(" + name + ")";
  53. }
  54. public String getName() {
  55. return name;
  56. }
  57. public void setName(String name) {
  58. this.name = name;
  59. }
  60. public Date getDateCreated() {
  61. return dateCreated;
  62. }
  63. public void setDateCreated(Date dateCreated) {
  64. this.dateCreated = dateCreated;
  65. }
  66. }

三、Listener 实例

(一)单态登录:一个账号只能在一台机器上登录。

1、Listener 的代码:

  1. package servlet.listener.singleton;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import javax.servlet.http.HttpSession;
  5. import javax.servlet.http.HttpSessionAttributeListener;
  6. import javax.servlet.http.HttpSessionBindingEvent;
  7. import org.apache.commons.logging.Log;
  8. import org.apache.commons.logging.LogFactory;
  9. /**
  10. *
  11. * LoginSessionListener.java
  12. *
  13. * @title 实现单态登录的监听器
  14. * @description
  15. * @author SAM-SHO
  16. * @Date 2014-12-10
  17. */
  18. public class LoginSessionListener implements HttpSessionAttributeListener {
  19. Log log = LogFactory.getLog(this.getClass());
  20. Map<String, HttpSession> map = new HashMap<String, HttpSession>();
  21. public void attributeAdded(HttpSessionBindingEvent event) {
  22. String name = event.getName();
  23. // 登录
  24. if (name.equals("personInfo")) {
  25. PersonInfo personInfo = (PersonInfo) event.getValue();
  26. if (map.get(personInfo.getAccount()) != null) {
  27. // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
  28. HttpSession session = map.get(personInfo.getAccount());
  29. PersonInfo oldPersonInfo = (PersonInfo) session.getAttribute("personInfo");//map已经存在的旧的信息
  30. log.info("帐号" + oldPersonInfo.getAccount() + "在" + oldPersonInfo.getIp() + "已经登录,该登录将*下线。");
  31. session.removeAttribute("personInfo");
  32. session.setAttribute("msg", "您的帐号已经在其他机器上登录,您*下线。");
  33. }
  34. // 将session以用户名为索引,放入map中
  35. map.put(personInfo.getAccount(), event.getSession());
  36. log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp() + "登录。");
  37. }
  38. }
  39. public void attributeRemoved(HttpSessionBindingEvent event) {
  40. String name = event.getName();
  41. // 注销
  42. if (name.equals("personInfo")) {
  43. // 将该session从map中移除
  44. PersonInfo personInfo = (PersonInfo) event.getValue();
  45. map.remove(personInfo.getAccount());
  46. log.info("帐号" + personInfo.getAccount() + "注销。");
  47. }
  48. }
  49. public void attributeReplaced(HttpSessionBindingEvent event) {
  50. String name = event.getName();
  51. // 没有注销的情况下,用另一个帐号登录
  52. if (name.equals("personInfo")) {
  53. // 移除旧的的登录信息
  54. PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
  55. map.remove(oldPersonInfo.getAccount());
  56. // 新的登录信息
  57. PersonInfo personInfo = (PersonInfo) event.getSession().getAttribute("personInfo");
  58. // 也要检查新登录的帐号是否在别的机器上登录过
  59. if (map.get(personInfo.getAccount()) != null) {
  60. // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
  61. HttpSession session = map.get(personInfo.getAccount());
  62. session.removeAttribute("personInfo");
  63. session.setAttribute("msg", "您的帐号已经在其他机器上登录,您*下线。");
  64. }
  65. map.put("personInfo", event.getSession());
  66. }
  67. }
  68. }
  1. package servlet.listener.singleton;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. /**
  5. *
  6. * PersonInfo.java
  7. *
  8. * @title
  9. * @description
  10. * @author SAM-SHO
  11. * @Date 2014-12-10
  12. */
  13. public class PersonInfo implements Serializable {
  14. private static final long serialVersionUID = 4063725584941336123L;
  15. // 帐号
  16. private String account;
  17. // 登录IP地址
  18. private String ip;
  19. // 登录时间
  20. private Date loginDate;
  21. public String getAccount() {
  22. return account;
  23. }
  24. public void setAccount(String account) {
  25. this.account = account;
  26. }
  27. public String getIp() {
  28. return ip;
  29. }
  30. public void setIp(String ip) {
  31. this.ip = ip;
  32. }
  33. public Date getLoginDate() {
  34. return loginDate;
  35. }
  36. public void setLoginDate(Date loginDate) {
  37. this.loginDate = loginDate;
  38. }
  39. @Override
  40. public int hashCode() {
  41. final int prime = 31;
  42. int result = 1;
  43. result = prime * result + ((account == null) ? 0 : account.hashCode());
  44. result = prime * result + ((ip == null) ? 0 : ip.hashCode());
  45. return result;
  46. }
  47. @Override
  48. public boolean equals(Object obj) {
  49. if (this == obj)
  50. return true;
  51. if (obj == null)
  52. return false;
  53. if (getClass() != obj.getClass())
  54. return false;
  55. PersonInfo other = (PersonInfo) obj;
  56. if (account == null) {
  57. if (other.account != null)
  58. return false;
  59. } else if (!account.equals(other.account))
  60. return false;
  61. if (ip == null) {
  62. if (other.ip != null)
  63. return false;
  64. } else if (!ip.equals(other.ip))
  65. return false;
  66. return true;
  67. }
  68. }
  1. <!-- 单态登录监听器 -->
  2. <listener>
  3. <listener-class>servlet.listener.singleton.LoginSessionListener</listener-class>
  4. </listener>

(二)显示在线人数:会需要3个监听器。

1、ContextListener:获取服务启动的时间等。

2、RequestListener:获取客户端的IP、访问地址,访问次数等。

3、SessionListener:需要监听 Session 的创建与属性变化。

4、代码如下:

  1. package com.helloweenvsfei.listener;
  2. import java.util.Date;
  3. import javax.servlet.ServletContextEvent;
  4. import javax.servlet.ServletContextListener;
  5. import com.helloweenvsfei.util.ApplicationConstants;
  6. public class MyContextListener implements ServletContextListener {
  7. public void contextInitialized(ServletContextEvent event) {
  8. // 启动时,记录服务器启动时间
  9. ApplicationConstants.START_DATE = new Date();
  10. }
  11. public void contextDestroyed(ServletContextEvent event) {
  12. // 关闭时,将结果清除。也可以将结果保存到硬盘上。
  13. ApplicationConstants.START_DATE = null;
  14. ApplicationConstants.MAX_ONLINE_COUNT_DATE = null;
  15. }
  16. }
  1. package com.helloweenvsfei.listener;
  2. import javax.servlet.ServletRequestEvent;
  3. import javax.servlet.ServletRequestListener;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpSession;
  6. public class MyRequestListener implements ServletRequestListener {
  7. public void requestDestroyed(ServletRequestEvent event) {
  8. }
  9. public void requestInitialized(ServletRequestEvent event) {
  10. HttpServletRequest request = (HttpServletRequest) event
  11. .getServletRequest();
  12. HttpSession session = request.getSession(true);
  13. // 记录IP地址
  14. session.setAttribute("ip", request.getRemoteAddr());
  15. // 记录访问次数,只记录访问 .html, .do, .jsp, .action 的累计次数
  16. String uri = request.getRequestURI();
  17. String[] suffix = { ".html", ".do", ".jsp", ".action" };
  18. for (int i=0; i<suffix.length; i++) {
  19. if (uri.endsWith(suffix[i])) {
  20. break;
  21. }
  22. if(i == suffix.length-1)
  23. return;
  24. }
  25. Integer activeTimes = (Integer) session.getAttribute("activeTimes");
  26. if (activeTimes == null) {
  27. activeTimes = 0;
  28. }
  29. session.setAttribute("activeTimes", activeTimes + 1);
  30. }
  31. }
    1. package com.helloweenvsfei.listener;
    2. import java.util.Date;
    3. import javax.servlet.http.HttpSession;
    4. import javax.servlet.http.HttpSessionAttributeListener;
    5. import javax.servlet.http.HttpSessionBindingEvent;
    6. import javax.servlet.http.HttpSessionEvent;
    7. import javax.servlet.http.HttpSessionListener;
    8. import com.helloweenvsfei.util.ApplicationConstants;
    9. public class MySessionListener implements HttpSessionListener,
    10. HttpSessionAttributeListener {
    11. public void sessionCreated(HttpSessionEvent sessionEvent) {
    12. HttpSession session = sessionEvent.getSession();
    13. // 将 session 放入 map
    14. ApplicationConstants.SESSION_MAP.put(session.getId(), session);
    15. // 总访问人数++
    16. ApplicationConstants.TOTAL_HISTORY_COUNT++;
    17. // 如果当前在线人数超过历史记录,则更新最大在线人数,并记录时间
    18. if (ApplicationConstants.SESSION_MAP.size() > ApplicationConstants.MAX_ONLINE_COUNT) {
    19. ApplicationConstants.MAX_ONLINE_COUNT = ApplicationConstants.SESSION_MAP
    20. .size();
    21. ApplicationConstants.MAX_ONLINE_COUNT_DATE = new Date();
    22. }
    23. }
    24. public void sessionDestroyed(HttpSessionEvent sessionEvent) {
    25. HttpSession session = sessionEvent.getSession();
    26. // 将session从map中移除
    27. ApplicationConstants.SESSION_MAP.remove(session.getId());
    28. }
    29. public void attributeAdded(HttpSessionBindingEvent event) {
    30. if (event.getName().equals("personInfo")) {
    31. // 当前登录用户数++
    32. ApplicationConstants.CURRENT_LOGIN_COUNT++;
    33. HttpSession session = event.getSession();
    34. // 查找该帐号有没有在其他机器上登录
    35. for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {
    36. // 如果该帐号已经在其他机器上登录,则以前的登录失效
    37. if (event.getValue().equals(sess.getAttribute("personInfo"))
    38. && session.getId() != sess.getId()) {
    39. sess.invalidate();
    40. }
    41. }
    42. }
    43. }
    44. public void attributeRemoved(HttpSessionBindingEvent event) {
    45. // 注销 当前登录用户数--
    46. if (event.getName().equals("personInfo")) {
    47. ApplicationConstants.CURRENT_LOGIN_COUNT--;
    48. }
    49. }
    50. public void attributeReplaced(HttpSessionBindingEvent event) {
    51. // 重新登录
    52. if (event.getName().equals("personInfo")) {
    53. HttpSession session = event.getSession();
    54. for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {
    55. // 如果新帐号在其他机器上登录过,则以前登录失效
    56. if (event.getValue().equals(sess.getAttribute("personInfo"))
    57. && session.getId() != sess.getId()) {
    58. sess.invalidate();
    59. }
    60. }
    61. }
    62. }
    63. }

一、简介

(一)概述

1、Listener 用于监听 Javaweb程序中的事件,例如创建、修改、删除Session、request、context等,并触发响应的事件。

2、 Listener 对应观察者模式,事件发生的时候会自动触发该事件对应的Listeer。 Listener 主要用于对 Session、request、context 进行监控。servlet2.5 规范*有 8 种Listener  。

(二)实现

1、不同功能的Listener 需要实现不同的 Listener  接口,一个Listener也可以实现多个接口,这样就可以多种功能的监听器一起工作。

2、8种监听器可以分为三类:

1)监听 Session、request、context 的创建于销毁,分别为

HttpSessionLister、ServletContextListener、ServletRequestListener

2)监听对象属性变化,分别为:

HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener

3)监听Session 内的对象,分别为HttpSessionBindingListener 和 HttpSessionActivationListener。与上面六类不同,这两类 Listener 监听的是Session 内的对象,而非 Session 本身,不需要在 web.xml中配置。

2、实现web.xml的Listener配置。

1)<listener>标签与 <listener-class>

2)<listener>一般配置在 <servlet>便签的前面。

  1. package servlet.listener;
  2. import javax.servlet.ServletContextEvent;
  3. import javax.servlet.ServletContextListener;
  4. /**
  5. *
  6. * MyListener.java
  7. *
  8. * @title Context监听器
  9. * @description
  10. * @author SAM-SHO
  11. * @Date 2014-9-25
  12. */
  13. public class MyListener implements ServletContextListener {
  14. public void contextDestroyed(ServletContextEvent sce) {
  15. }
  16. public void contextInitialized(ServletContextEvent sce) {
  17. }
  18. }
  1. <!--监听器 -->
  2. <listener>
  3. <listener-class>servlet.listener.MyListener</listener-class>
  4. </listener>

二、八种类型监听器

(一)监听 Session、request、context 的创建于销毁。

HttpSessionLister、ServletContextListener、ServletRequestListener

1、三种监听器的触发时机及使用:

Servlet  监听器Listener详解

2、实例:实现监听对象的创建与销毁

  1. package servlet.listener;
  2. import javax.servlet.ServletContext;
  3. import javax.servlet.ServletContextEvent;
  4. import javax.servlet.ServletContextListener;
  5. import javax.servlet.ServletRequestEvent;
  6. import javax.servlet.ServletRequestListener;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpSession;
  9. import javax.servlet.http.HttpSessionEvent;
  10. import javax.servlet.http.HttpSessionListener;
  11. import org.apache.commons.logging.Log;
  12. import org.apache.commons.logging.LogFactory;
  13. /**
  14. *
  15. * ListenerTest.java
  16. *
  17. * @title 监听对象的创建与销毁
  18. * @description
  19. * @author SAM-SHO
  20. * @Date 2014-12-10
  21. */
  22. public class ListenerTest implements HttpSessionListener, ServletContextListener, ServletRequestListener {
  23. Log log = LogFactory.getLog(getClass());
  24. // 创建 session
  25. public void sessionCreated(HttpSessionEvent se) {
  26. HttpSession session = se.getSession();
  27. log.info("新创建一个session, ID为: " + session.getId());
  28. }
  29. // 销毁 session
  30. public void sessionDestroyed(HttpSessionEvent se) {
  31. HttpSession session = se.getSession();
  32. log.info("销毁一个session, ID为: " + session.getId());
  33. }
  34. // 加载 context
  35. public void contextInitialized(ServletContextEvent sce) {
  36. ServletContext servletContext = sce.getServletContext();
  37. log.info("即将启动" + servletContext.getContextPath());
  38. }
  39. // 卸载 context
  40. public void contextDestroyed(ServletContextEvent sce) {
  41. ServletContext servletContext = sce.getServletContext();
  42. log.info("即将关闭" + servletContext.getContextPath());
  43. }
  44. // 创建 request
  45. public void requestInitialized(ServletRequestEvent sre) {
  46. HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
  47. String uri = request.getRequestURI();
  48. uri = request.getQueryString() == null ? uri : (uri + "?" + request.getQueryString());
  49. request.setAttribute("dateCreated", System.currentTimeMillis());
  50. log.info("IP " + request.getRemoteAddr() + " 请求 " + uri);
  51. }
  52. // 销毁 request
  53. public void requestDestroyed(ServletRequestEvent sre) {
  54. HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
  55. long time = System.currentTimeMillis() - (Long) request.getAttribute("dateCreated");
  56. log.info(request.getRemoteAddr() + "请求处理结束, 用时" + time + "毫秒. ");
  57. }
  58. }

(二)监听对象属性变化,分别为HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener

1、三种监听器的触发时机及使用:

Servlet  监听器Listener详解

2、实例:实现对象属性的监听

  1. package servlet.listener;
  2. import javax.servlet.http.HttpSession;
  3. import javax.servlet.http.HttpSessionAttributeListener;
  4. import javax.servlet.http.HttpSessionBindingEvent;
  5. import org.apache.commons.logging.Log;
  6. import org.apache.commons.logging.LogFactory;
  7. /**
  8. *
  9. * SessionAttributeListenerTest.java
  10. *
  11. * @title 监听Session对象的属性
  12. * @description
  13. * @author SAM-SHO
  14. * @Date 2014-12-10
  15. */
  16. public class SessionAttributeListenerTest implements HttpSessionAttributeListener {
  17. Log log = LogFactory.getLog(getClass());
  18. // 添加属性
  19. public void attributeAdded(HttpSessionBindingEvent se) {
  20. HttpSession session = se.getSession();
  21. String name = se.getName();
  22. log.info("新建session属性:" + name + ", 值为:" + se.getValue());
  23. }
  24. // 删除属性
  25. public void attributeRemoved(HttpSessionBindingEvent se) {
  26. HttpSession session = se.getSession();
  27. String name = se.getName();
  28. log.info("删除session属性:" + name + ", 值为:" + se.getValue());
  29. }
  30. // 修改属性
  31. public void attributeReplaced(HttpSessionBindingEvent se) {
  32. HttpSession session = se.getSession();
  33. String name = se.getName();
  34. Object oldValue = se.getValue();
  35. log.info("修改session属性:" + name + ", 原值:" + oldValue + ", 新值:" + session.getAttribute(name));
  36. }
  37. }

(三)监听Session 内的对象,分别为HttpSessionBindingListener 和 HttpSessionActivationListener

1、触发时机及使用:对象必须实现Listener接口,不需要在web.xml中配置

Servlet  监听器Listener详解

2、实例:实现对象属性的监听

  1. package servlet.listener;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. import javax.servlet.http.HttpSession;
  5. import javax.servlet.http.HttpSessionActivationListener;
  6. import javax.servlet.http.HttpSessionBindingEvent;
  7. import javax.servlet.http.HttpSessionBindingListener;
  8. import javax.servlet.http.HttpSessionEvent;
  9. import org.apache.commons.logging.Log;
  10. import org.apache.commons.logging.LogFactory;
  11. /**
  12. *
  13. * PersonInfo.java
  14. *
  15. * @title 同时实现多个接口
  16. * 被串行化,需要实现Serializable接口
  17. * @description
  18. * @author SAM-SHO
  19. * @Date 2014-12-10
  20. */
  21. public class PersonInfo implements HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
  22. private static final long serialVersionUID = -4780592776386225973L;
  23. Log log = LogFactory.getLog(getClass());
  24. private String name;
  25. private Date dateCreated;
  26. // 从硬盘加载后
  27. public void sessionDidActivate(HttpSessionEvent se) {
  28. HttpSession session = se.getSession();
  29. log.info(this + "已经成功从硬盘中加载。sessionId: " + session.getId());
  30. }
  31. // 即将被钝化到硬盘时
  32. public void sessionWillPassivate(HttpSessionEvent se) {
  33. HttpSession session = se.getSession();
  34. log.info(this + "即将保存到硬盘。sessionId: " + session.getId());
  35. }
  36. // 被放进session前
  37. public void valueBound(HttpSessionBindingEvent event) {
  38. HttpSession session = event.getSession();
  39. String name = event.getName();
  40. log.info(this + "被绑定到session \"" + session.getId() + "\"的" + name + "属性上");
  41. // 记录放到session中的时间
  42. this.setDateCreated(new Date());
  43. }
  44. // 从session中移除后
  45. public void valueUnbound(HttpSessionBindingEvent event) {
  46. HttpSession session = event.getSession();
  47. String name = event.getName();
  48. log.info(this + "被从session \"" + session.getId() + "\"的" + name + "属性上移除");
  49. }
  50. @Override
  51. public String toString() {
  52. return "PersonInfo(" + name + ")";
  53. }
  54. public String getName() {
  55. return name;
  56. }
  57. public void setName(String name) {
  58. this.name = name;
  59. }
  60. public Date getDateCreated() {
  61. return dateCreated;
  62. }
  63. public void setDateCreated(Date dateCreated) {
  64. this.dateCreated = dateCreated;
  65. }
  66. }

三、Listener 实例

(一)单态登录:一个账号只能在一台机器上登录。

1、Listener 的代码:

  1. package servlet.listener.singleton;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import javax.servlet.http.HttpSession;
  5. import javax.servlet.http.HttpSessionAttributeListener;
  6. import javax.servlet.http.HttpSessionBindingEvent;
  7. import org.apache.commons.logging.Log;
  8. import org.apache.commons.logging.LogFactory;
  9. /**
  10. *
  11. * LoginSessionListener.java
  12. *
  13. * @title 实现单态登录的监听器
  14. * @description
  15. * @author SAM-SHO
  16. * @Date 2014-12-10
  17. */
  18. public class LoginSessionListener implements HttpSessionAttributeListener {
  19. Log log = LogFactory.getLog(this.getClass());
  20. Map<String, HttpSession> map = new HashMap<String, HttpSession>();
  21. public void attributeAdded(HttpSessionBindingEvent event) {
  22. String name = event.getName();
  23. // 登录
  24. if (name.equals("personInfo")) {
  25. PersonInfo personInfo = (PersonInfo) event.getValue();
  26. if (map.get(personInfo.getAccount()) != null) {
  27. // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
  28. HttpSession session = map.get(personInfo.getAccount());
  29. PersonInfo oldPersonInfo = (PersonInfo) session.getAttribute("personInfo");//map已经存在的旧的信息
  30. log.info("帐号" + oldPersonInfo.getAccount() + "在" + oldPersonInfo.getIp() + "已经登录,该登录将*下线。");
  31. session.removeAttribute("personInfo");
  32. session.setAttribute("msg", "您的帐号已经在其他机器上登录,您*下线。");
  33. }
  34. // 将session以用户名为索引,放入map中
  35. map.put(personInfo.getAccount(), event.getSession());
  36. log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp() + "登录。");
  37. }
  38. }
  39. public void attributeRemoved(HttpSessionBindingEvent event) {
  40. String name = event.getName();
  41. // 注销
  42. if (name.equals("personInfo")) {
  43. // 将该session从map中移除
  44. PersonInfo personInfo = (PersonInfo) event.getValue();
  45. map.remove(personInfo.getAccount());
  46. log.info("帐号" + personInfo.getAccount() + "注销。");
  47. }
  48. }
  49. public void attributeReplaced(HttpSessionBindingEvent event) {
  50. String name = event.getName();
  51. // 没有注销的情况下,用另一个帐号登录
  52. if (name.equals("personInfo")) {
  53. // 移除旧的的登录信息
  54. PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
  55. map.remove(oldPersonInfo.getAccount());
  56. // 新的登录信息
  57. PersonInfo personInfo = (PersonInfo) event.getSession().getAttribute("personInfo");
  58. // 也要检查新登录的帐号是否在别的机器上登录过
  59. if (map.get(personInfo.getAccount()) != null) {
  60. // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
  61. HttpSession session = map.get(personInfo.getAccount());
  62. session.removeAttribute("personInfo");
  63. session.setAttribute("msg", "您的帐号已经在其他机器上登录,您*下线。");
  64. }
  65. map.put("personInfo", event.getSession());
  66. }
  67. }
  68. }
  1. package servlet.listener.singleton;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. /**
  5. *
  6. * PersonInfo.java
  7. *
  8. * @title
  9. * @description
  10. * @author SAM-SHO
  11. * @Date 2014-12-10
  12. */
  13. public class PersonInfo implements Serializable {
  14. private static final long serialVersionUID = 4063725584941336123L;
  15. // 帐号
  16. private String account;
  17. // 登录IP地址
  18. private String ip;
  19. // 登录时间
  20. private Date loginDate;
  21. public String getAccount() {
  22. return account;
  23. }
  24. public void setAccount(String account) {
  25. this.account = account;
  26. }
  27. public String getIp() {
  28. return ip;
  29. }
  30. public void setIp(String ip) {
  31. this.ip = ip;
  32. }
  33. public Date getLoginDate() {
  34. return loginDate;
  35. }
  36. public void setLoginDate(Date loginDate) {
  37. this.loginDate = loginDate;
  38. }
  39. @Override
  40. public int hashCode() {
  41. final int prime = 31;
  42. int result = 1;
  43. result = prime * result + ((account == null) ? 0 : account.hashCode());
  44. result = prime * result + ((ip == null) ? 0 : ip.hashCode());
  45. return result;
  46. }
  47. @Override
  48. public boolean equals(Object obj) {
  49. if (this == obj)
  50. return true;
  51. if (obj == null)
  52. return false;
  53. if (getClass() != obj.getClass())
  54. return false;
  55. PersonInfo other = (PersonInfo) obj;
  56. if (account == null) {
  57. if (other.account != null)
  58. return false;
  59. } else if (!account.equals(other.account))
  60. return false;
  61. if (ip == null) {
  62. if (other.ip != null)
  63. return false;
  64. } else if (!ip.equals(other.ip))
  65. return false;
  66. return true;
  67. }
  68. }
  1. <!-- 单态登录监听器 -->
  2. <listener>
  3. <listener-class>servlet.listener.singleton.LoginSessionListener</listener-class>
  4. </listener>

(二)显示在线人数:会需要3个监听器。

1、ContextListener:获取服务启动的时间等。

2、RequestListener:获取客户端的IP、访问地址,访问次数等。

3、SessionListener:需要监听 Session 的创建与属性变化。

4、代码如下:

  1. package com.helloweenvsfei.listener;
  2. import java.util.Date;
  3. import javax.servlet.ServletContextEvent;
  4. import javax.servlet.ServletContextListener;
  5. import com.helloweenvsfei.util.ApplicationConstants;
  6. public class MyContextListener implements ServletContextListener {
  7. public void contextInitialized(ServletContextEvent event) {
  8. // 启动时,记录服务器启动时间
  9. ApplicationConstants.START_DATE = new Date();
  10. }
  11. public void contextDestroyed(ServletContextEvent event) {
  12. // 关闭时,将结果清除。也可以将结果保存到硬盘上。
  13. ApplicationConstants.START_DATE = null;
  14. ApplicationConstants.MAX_ONLINE_COUNT_DATE = null;
  15. }
  16. }
  1. package com.helloweenvsfei.listener;
  2. import javax.servlet.ServletRequestEvent;
  3. import javax.servlet.ServletRequestListener;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpSession;
  6. public class MyRequestListener implements ServletRequestListener {
  7. public void requestDestroyed(ServletRequestEvent event) {
  8. }
  9. public void requestInitialized(ServletRequestEvent event) {
  10. HttpServletRequest request = (HttpServletRequest) event
  11. .getServletRequest();
  12. HttpSession session = request.getSession(true);
  13. // 记录IP地址
  14. session.setAttribute("ip", request.getRemoteAddr());
  15. // 记录访问次数,只记录访问 .html, .do, .jsp, .action 的累计次数
  16. String uri = request.getRequestURI();
  17. String[] suffix = { ".html", ".do", ".jsp", ".action" };
  18. for (int i=0; i<suffix.length; i++) {
  19. if (uri.endsWith(suffix[i])) {
  20. break;
  21. }
  22. if(i == suffix.length-1)
  23. return;
  24. }
  25. Integer activeTimes = (Integer) session.getAttribute("activeTimes");
  26. if (activeTimes == null) {
  27. activeTimes = 0;
  28. }
  29. session.setAttribute("activeTimes", activeTimes + 1);
  30. }
  31. }
  1. package com.helloweenvsfei.listener;
  2. import java.util.Date;
  3. import javax.servlet.http.HttpSession;
  4. import javax.servlet.http.HttpSessionAttributeListener;
  5. import javax.servlet.http.HttpSessionBindingEvent;
  6. import javax.servlet.http.HttpSessionEvent;
  7. import javax.servlet.http.HttpSessionListener;
  8. import com.helloweenvsfei.util.ApplicationConstants;
  9. public class MySessionListener implements HttpSessionListener,
  10. HttpSessionAttributeListener {
  11. public void sessionCreated(HttpSessionEvent sessionEvent) {
  12. HttpSession session = sessionEvent.getSession();
  13. // 将 session 放入 map
  14. ApplicationConstants.SESSION_MAP.put(session.getId(), session);
  15. // 总访问人数++
  16. ApplicationConstants.TOTAL_HISTORY_COUNT++;
  17. // 如果当前在线人数超过历史记录,则更新最大在线人数,并记录时间
  18. if (ApplicationConstants.SESSION_MAP.size() > ApplicationConstants.MAX_ONLINE_COUNT) {
  19. ApplicationConstants.MAX_ONLINE_COUNT = ApplicationConstants.SESSION_MAP
  20. .size();
  21. ApplicationConstants.MAX_ONLINE_COUNT_DATE = new Date();
  22. }
  23. }
  24. public void sessionDestroyed(HttpSessionEvent sessionEvent) {
  25. HttpSession session = sessionEvent.getSession();
  26. // 将session从map中移除
  27. ApplicationConstants.SESSION_MAP.remove(session.getId());
  28. }
  29. public void attributeAdded(HttpSessionBindingEvent event) {
  30. if (event.getName().equals("personInfo")) {
  31. // 当前登录用户数++
  32. ApplicationConstants.CURRENT_LOGIN_COUNT++;
  33. HttpSession session = event.getSession();
  34. // 查找该帐号有没有在其他机器上登录
  35. for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {
  36. // 如果该帐号已经在其他机器上登录,则以前的登录失效
  37. if (event.getValue().equals(sess.getAttribute("personInfo"))
  38. && session.getId() != sess.getId()) {
  39. sess.invalidate();
  40. }
  41. }
  42. }
  43. }
  44. public void attributeRemoved(HttpSessionBindingEvent event) {
  45. // 注销 当前登录用户数--
  46. if (event.getName().equals("personInfo")) {
  47. ApplicationConstants.CURRENT_LOGIN_COUNT--;
  48. }
  49. }
  50. public void attributeReplaced(HttpSessionBindingEvent event) {
  51. // 重新登录
  52. if (event.getName().equals("personInfo")) {
  53. HttpSession session = event.getSession();
  54. for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {
  55. // 如果新帐号在其他机器上登录过,则以前登录失效
  56. if (event.getValue().equals(sess.getAttribute("personInfo"))
  57. && session.getId() != sess.getId()) {
  58. sess.invalidate();
  59. }
  60. }
  61. }
  62. }
  63. }