监听器(Listener)
1、监听器的概念:Listener也是Servlet规范2.3中加入的,对应设计模式中的Listener模式,事件发生的时候会自动触发该事件对应的Listener。Listener主要用于对Session、request、context等进行监控。目前的Servlet2.5规范中共有8种Listener,分别完成对不同事件的监听。
监听器(Listener)的使用方法
使用Listener需要实现相应的Listener接口。应该触发Listener事件的时候,Tomcat会自动调用Listener的方法。使用Listener的方法一般如下:
首先自定义一个Listener类,实现相应的Listener接口:
package com.ajax.util;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/*自定义监听器*/
public class Self_DefindeListener implements ServletContextListener{
/*在Tomcat容器启动时就会触发该方法*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("===context init!");
}
/*在Tomcat容器销毁时就会触发该方法*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("===context Destory!");
}
}
在web.xml中配置相应的监听器:
<!-- 配置监听器 -->
<listener>
<listener-class>com.ajax.util.Self_DefindeListener</listener-class>
</listener>
常用的八种监听器
1、ServletContextListener
[接口方法]:contextInitialized()与 contextDestroyed()
[接收事件] ServletContextEvent
[触发场景] 在Container加载Web应用程序时(例如启动 Container之后),会呼叫contextInitialized(),而当容器移除Web应用程序时,会呼叫contextDestroyed ()方法。
[触发场景] 在Container加载Web应用程序时(例如启动 Container之后),会呼叫contextInitialized(),而当容器移除Web应用程序时,会呼叫contextDestroyed ()方法。
2、ServletContextAttributeListener
[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved()
[接收事件] ServletContextAttributeEvent
[触发场景] 若有对象加入为application(ServletContext)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、attributeRemoved()。
[接收事件] ServletContextAttributeEvent
[触发场景] 若有对象加入为application(ServletContext)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、attributeRemoved()。
3、HttpSessionListener
[接口方法] sessionCreated()与sessionDestroyed ()
[接收事件] HttpSessionEvent
[触发场景] 在session (HttpSession)对象建立或被消灭时,会分别呼叫这两个方法。
[接收事件] HttpSessionEvent
[触发场景] 在session (HttpSession)对象建立或被消灭时,会分别呼叫这两个方法。
4、HttpSessionAttributeListener
[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved()
[接收事件] HttpSessionBindingEvent
[触发场景] 若有对象加入为session(HttpSession)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。
[接收事件] HttpSessionBindingEvent
[触发场景] 若有对象加入为session(HttpSession)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。
5、HttpSessionActivationListener
[接口方法] sessionDidActivate()与 sessionWillPassivate()
[接收事件] HttpSessionEvent
[触发场景] Activate与Passivate是用于置换对象的动作,当session对象为了资源利用或负载平衡等原因而必须暂时储存至硬盘或其它储存器时(透过对象序列化),所作的动作称之为Passivate,而硬盘或储存器上的session对象重新加载JVM时所采的动作称之为Activate,所以容易理解的,sessionDidActivate()与 sessionWillPassivate()分别于Activeate后与将Passivate前呼叫。
[接收事件] HttpSessionEvent
[触发场景] Activate与Passivate是用于置换对象的动作,当session对象为了资源利用或负载平衡等原因而必须暂时储存至硬盘或其它储存器时(透过对象序列化),所作的动作称之为Passivate,而硬盘或储存器上的session对象重新加载JVM时所采的动作称之为Activate,所以容易理解的,sessionDidActivate()与 sessionWillPassivate()分别于Activeate后与将Passivate前呼叫。
6、ServletRequestListener
[接口方法] requestInitialized()与 requestDestroyed()
[接收事件] RequestEvent
[触发场景] 在request(HttpServletRequest)对象建立或被消灭时,会分别呼叫这两个方法。
[接收事件] RequestEvent
[触发场景] 在request(HttpServletRequest)对象建立或被消灭时,会分别呼叫这两个方法。
7、ServletRequestAttributeListener
[接口方法] attributeAdded()、 attributeReplaced()、attributeRemoved()
[接收事件] HttpSessionBindingEvent
[触发场景] 若有对象加入为request(HttpServletRequest)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。
[接收事件] HttpSessionBindingEvent
[触发场景] 若有对象加入为request(HttpServletRequest)对象的属性,则会呼叫attributeAdded(),同理在置换属性与移除属性时,会分别呼叫attributeReplaced()、 attributeRemoved()。
8、HttpSessionBindingListener
[接口方法] valueBound()与valueUnbound()
[接收事件] HttpSessionBindingEvent
[触发场景] 实现HttpSessionBindingListener接口的类别,其实例如果被加入至session(HttpSession)对象的属性中,则会呼叫 valueBound(),如果被从session(HttpSession)对象的属性中移除,则会呼叫valueUnbound(),实现HttpSessionBindingListener接口的类别不需在web.xml中设定。
[接收事件] HttpSessionBindingEvent
[触发场景] 实现HttpSessionBindingListener接口的类别,其实例如果被加入至session(HttpSession)对象的属性中,则会呼叫 valueBound(),如果被从session(HttpSession)对象的属性中移除,则会呼叫valueUnbound(),实现HttpSessionBindingListener接口的类别不需在web.xml中设定。
监听器适用的情景
实现单态登录、统计在线人数、初始化系统资源等功能。
下面是实现一个统计网站当前在线人数以及历史访问人数的功能
自定义一个类实现相应的监听器接口
package com.register.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/*一、使用监听来统计在线人数(需要使用到的监听有ServletContextListener,HttpSessionAttributeListener)
* 统计在线人数原理:
* 1、首先在ServletContext上下文初始化的时候在application域中放置一个ArrayList或者HashSet集合容器
* 2、当用户登录成功的时候,使用session.setAttribute(key,value)将用户的信息保存到session中,这时会触发attributeAdded方法,我们
* 只需要将相应的session中的value值取出放到ArrayList或者HashSet集合容器,并判断是否已经存在,如果已经存在则不加入到容器。
* 3、当用户退出登录时,使用session.remove(value)方法,将当前用户移除,这时会触发attributeRemoved方法,这里只需要将集合中
* 的这个value删除即可。
* 4、当我们在页面中可以直接拿到application中的onlineUser这个集合,这个集合的长度就是当前在线用户。
* 二、使用监听统计历史访问人数
* 1、使用application来统计历史访问人数,只需要在application域中放一个计数器,每次用户登录时这个计数器会加1
* 三、application:application为整个站点共享,只有重启服务器的时候才会重置application中的对象。
* */
@SuppressWarnings("all")
public class OnlineUserListener implements ServletContextListener,HttpSessionAttributeListener{
private ServletContext application=null;
//容器进行初始化,向application中放入一个空的集合容器
@Override
public void contextInitialized(ServletContextEvent sce) {
//这里用来处理当服务器重启或意外shut down时历史访问人数,这里采用写文件的方式
FileInputStream fis=null;
String str=null;
try{
fis=new FileInputStream(new File("E:\\SSH_Registeration\\count.txt"));//需要在计算机的相应位置新建一个文本文件
byte [] b=new byte[1024];
int len;
while((len=fis.read(b))!=-1){
str=new String(b,0,len);
}
fis.close();
}catch(Exception e){
e.printStackTrace();
}
this.application=sce.getServletContext();
this.application.setAttribute("OnlineUser", new ArrayList<String>());//在线人数
int countUser=Integer.parseInt(str)>=0?Integer.parseInt(str):0;//历史人数是否已经存在
this.application.setAttribute("historyUser", countUser);//访问历史人数
}
//当往session域中加入变量时,也就是登录成功
@Override
public void attributeAdded(HttpSessionBindingEvent hse) {
//正在线人数
List<String> list=(List<String>)this.application.getAttribute("OnlineUser");
if(hse.getName().equals("username")){
if(!list.contains(hse.getValue().toString())){
list.add(hse.getValue().toString());
}
}
this.application.setAttribute("OnlineUser", list);
//历史访问人数
int countUser=(Integer) this.application.getAttribute("historyUser");
this.application.setAttribute("historyUser", countUser+1);
}
//用户注销时
@Override
public void attributeRemoved(HttpSessionBindingEvent hse) {
List<String> list=(List<String>) this.application.getAttribute("OnlineUser");
if(hse.getName().equals("username")){
list.remove(hse.getValue());
}
this.application.setAttribute("OnlineUser", list);
}
//当服务器tomcat因为某些原因或者人为shut down 时,将当前的访问历史人数写入到文件中
@Override
public void contextDestroyed(ServletContextEvent sce) {
int historyUser=(Integer) this.application.getAttribute("historyUser");
try {
FileOutputStream fos=new FileOutputStream(new File("E:\\SSH_Registeration\\count.txt"));
fos.write((historyUser+"").getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void attributeReplaced(HttpSessionBindingEvent arg0) {//session的值被替换时触发}
}
在web.xml加入相应的监听器配置
<!-- 统计在线人数 以及历史访问人数-->
<listener>
<listener-class>com.register.util.OnlineUserListener</listener-class>
</listener>