监听
监听: 对某一些操作进行监视,那么就称为监听
在web 中的监听主要的功能是永远对ServletContext、Session、Request进行监听的一种操作

1、对application 进行监听
Application是Servlet 进行监听接口的对象,表示的是整个上下午的环境
如果要想实现对application 监听则可以使用如下两个接口
ServletContextListener 是对整个上下文环境的监控
ServletContextAttributeListener 对属性的监听
package org.gz.servlet.listener;
import javax.servlet.*;
public class ServletContextListener implements ServleContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("========容器初始化--->" + event.getServletContext().getContextPath());
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("=====容器销毁 ----->"+ event.getServletContext().getContextPath());
}
}
此时的监听操作只是做了一个简单的输出
过滤器: <filter> 、<filter-mapping>
但是现在的监听器就省事了,直接编写<listener>
如果现在一个web.xml文件之中包含简单Servlet 、过滤器、监听器,则建议的缩写配置的顺序
<filter>
<filter-mapping>
<listener>
<servlet>
<servlet-mapping>
监听器的配置
<listener>
<listener-class>
org.gz.servlet.listener.ServletContextListenerdemo
</listener-class>
</listener
只要是容器的启动和关闭都要触发这些操作
还可以实现 ServletContextAttributeListener 接口,此接口可以直接对属性监听
package org.gz.servlet.listener.attribute;
import javax.servlet.*;
public class ServletContextAttributeListenerdemo implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent scab) {
System.out.println("增加属性名称--》" + scab.getName() + " ,属性内容————》" + scab.getValue());
}
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println("删除属性名称--》" + scab.getName() + " ,属性内容————》" + scab.getValue());
}
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println("替换属性名称--》" + scab.getName() + " ,属性内容————》" + scab.getValue());
}
}
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
this.getServletContext().setAttribute("info","www.baidu.com");
%>
</body>
</html>
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
this.getServletContext().removeAttribute("info");
%>
</body>
</html>
监听器就是实现接口,覆写方法, 实际上这个与SWING中的操作都是非常类似的
2、对session 监听
在监听器中,针对于session的监听操作提供了三个接口:
HttpSessionListener
HttpSessionAttributeListener
HttpSessionBindingListener
Session 属于HTTP协议的范畴,所以这些接口肯定在javax.servlet.http 包中定义的。
在Servlet中如果要想取得session 依靠HttpServletRequest 接口中的getSession()方法
package org.gz.servlet.sesssionlistener;
import javax.servlet.http.*;
// org.gz.servlet.sesssionlistener.HttpSessionListenerDemo
public class HttpSessionListenerDemo implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session创建,SESSION ID= " + se.getSession().getId());
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session销毁,SESSION ID= " + se.getSession().getId());
}
}
/*
<listener>
<listener-class>
org.gz.servlet.sesssionlistener.HttpSessionListenerDemo
</listener-class>
</listener>
*/
在讲解内置对象的时候一直强调,当客户端第一次连接到服务器上的时候服务器将会自动为用户创建一个新的session , 同时会分配一个新的 session id。
现在session 已经被创建,在第一次访问的时候触发了事件,可是还有一点,什么时候销毁呢?
如果现在想要让一个session 销毁的化,有两种方法,但是这两种方法并不是直接关闭服务器就可以实现的:
session注销: invalidate()
超时时间到了, 在tomcat中一般的超时时间是30 分钟。
//D:\java rj\web\tomcat-6.0.18\conf\web.xml
<session-config>
<session-timeout>30</session-timeout>
</session-config>
当然: 也可以根据自己的情况修改,例如:将本想买中的超时时间修改为1 分钟
// E:\webdemo\WEB-INF\web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
// 手工注销
session.invalidate();
%>
</body>
</html>
之前一直强调,当调用invalidate() 方法的时候就意味着 session 的内容将被清空
不过一般的销毁时间都是设置在30 分钟或更长的时间,如果时间保存长也就意味着占用空间的时间就长
package org.gz.servlet.attributelistener;
import javax.servlet.http.*;
// org.gz.servlet.attributelistener.HttpSessionAttributeListenerdemo
public class HttpSessionAttributeListenerdemo implements HttpSessionAttributeListener {
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println(se.getSession().getId() + " ,增加属性--->名称: " +
se.getName() + ", 属性内容: " + se.getValue() );
}
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println(se.getSession().getId() + " ,删除属性--->名称: " +
se.getName() + ", 属性内容: " + se.getValue() );
}
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println(se.getSession().getId() + " ,替换属性--->名称: " +
se.getName() + ", 属性内容: " + se.getValue() );
}
}
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
// 手工注销
session.removeAttribute("info");
%>
</body>
</html>
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
// 手工注销
session.setAttribute("info","www.baidu.com");
%>
</body>
</html>
package org.gz.servlet.bindinglistener;
import javax.servlet.http.*;
// org.gz.servlet.bindinglistener.HttpSessionBindingListenerdemo
public class HttpSessionBindingListenerdemo implements HttpSessionBindingListener {
private String name;
public HttpSessionBindingListenerdemo (String name) {
this.name = name;
}
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("在session中保存HttpSessionBindingListenerdemo 对象(name = "
+ this.getName() + " ) , session id = " + event.getSession().getId());
}
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("在session中移除HttpSessionBindingListenerdemo 对象(name = "
+ this.getName() + " ) , session id = " + event.getSession().getId());
}
public String getName() {
return this.name;
}
public void setName(String name){
this.name = name;
}
}
/*
此处根本就不需要任何配置文件的支持
*/
<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ page import="org.gz.servlet.bindinglistener.*"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
//由于此处需要手工绑定,所以才不需要做任何额外的配置 移除 session.removeAttribute("info");
HttpSessionBindingListenerdemo binding = new HttpSessionBindingListenerdemo("gz");
session.setAttribute("info",binding); //直接保存 HttpSessionBindingListenerdemo 对象
%>
</body>
</html>
3、对request监听
在Servlet 2.4 之后增加了对request 操作的监听,主要使用 ServletRequestListener、 ServletRequestAttributeListener 两个接口
package org.gz.servlet.reqestlistener;
import javax.servlet.*;
public class ServletRequestListenerdemo implements ServletRequestListener {
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request 初始化 http://" +
sre.getServletRequest().getRemoteAddr() +
sre.getServletContext().getContextPath());
}
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request 销毁 http://" +
sre.getServletRequest().getRemoteAddr() +
sre.getServletContext().getContextPath());
}
}
package org.gz.servlet.reqestattributelistener;
import javax.servlet.*;
public class ServletRequestAttributeListenerdemo implements ServletRequestAttributeListener {
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("增加request属性-->属性名称: " + srae.getName() + ",属性内容: " + srae.getValue());
}
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("删除request属性-->属性名称: " + srae.getName() + ",属性内容: " + srae.getValue());
}
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("替换request属性-->属性名称: " + srae.getName() + ",属性内容: " + srae.getValue());
}
}
/*
<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ page import="org.gz.servlet.bindinglistener.*"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
request.setAttribute("info","www.baidu.com");
//request.setAttribute("info","www.baidu.com"); //将出现替换
request.removeAttribute("info");
%>
</body>
</html>
<listener>
<listener-class>
org.gz.servlet.reqestattributelistener.ServletRequestAttributeListenerdemo
</listener-class>
</listener>
*/
从实际来讲,对request 范围的监听操作并不是很常见的,用的最多的还是ServletContext、HttpSession监听
4、监听器的实例
经常会在各个站点上看见一些在线人员的列表操作,实际上次操作就可以通过监听完成
在整个的操作中,需要使用以下几个接口 :
所有的人员列表应该用集合保存,但是这个集合所有的用户都可以看见,而且以后也要操作,
那么证明在整个监听中必然需要有一个 application 对象保存
用户登录成功,增加属性,肯定要在属性监听接口中使用
当用户离开之后,
package org.gz.servlet.context;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
// org.gz.servlet.context.OnlineUserList
public class OnlineUserList implements ServletContextListener,HttpSessionAttributeListener,HttpSessionListener {
private ServletContext app = null;
//ServletContextListener
public void contextInitialized(ServletContextEvent sce) {
this.app = sce.getServletContext(); //初始化
this.app.setAttribute("online",new TreeSet()); //设置内容,准备集合 TreeSet 按照 Comparable 二分法排序
}
public void contextDestroyed(ServletContextEvent sce) { }
// HttpSessionAttributeList
public void attributeAdded(HttpSessionBindingEvent se) {
Set all = (Set) this.app.getAttribute("online"); // 取出属性集合
all.add(se.getValue()); // 保存属性名字
this.app.setAttribute("online",all); // 重新设置回去
}
public void attributeRemoved(HttpSessionBindingEvent se) {
Set all = (Set) this.app.getAttribute("online");
all.remove(se.getSession().getAttribute("userid")); //用户离开删除
this.app.setAttribute("online",all);
}
public void attributeReplaced(HttpSessionBindingEvent se) { }
// HttpSessionListener
public void sessionCreated(HttpSessionEvent se) { }
public void sessionDestroyed(HttpSessionEvent se) {
Set all = (Set) this.app.getAttribute("online");
all.remove(se.getSession().getAttribute("userid")); //用户离开删除 没有getValue()这个方法
this.app.setAttribute("online",all); //操作完了之后重新放回集合之中
}
}
/*
<%@ page contentType="text/html" pageEncoding="GBK"%>
<html>
<head> <title>欢迎光临</title>
</head>
<%
request.setCharacterEncoding("GBK");
%>
<body>
<form action="online_listener.jsp" method="post">
用户ID: <input type="text" name="userid">
<input type="submit" value="登录">
</form>
<%
String userid = request.getParameter("userid");
if(!(userid == null || "".equals(userid))) { //userid 不为空
session.setAttribute("userid",userid);
response.sendRedirect("online_list.jsp");
}
%>
</body>
</html>
<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ page import="java.util.*"%>
<html>
<head> <title>欢迎光临</title>
</head>
<body>
<%
Set all = (Set)this.getServletContext().getAttribute("online");
Iterator iter = all.iterator();
while(iter.hasNext()) {
%>
<h3><%=iter.next()%></h3>
<%
}
%>
</body>
</html>
*/
/*
<listener>
<listener-class>
org.gz.servlet.context.OnlineUserList
</listener-class>
</listener>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
E:\webdemo\WEB-INF\classes>javac -d . *.java
注意:OnlineUserList.java 使用了未经检查或不安全的操作。
注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。 (编译出现这样的情况是由于List集合没有加泛型)
*/
使用监听器可以对application 、session、request 的属性范围进行监听
在web 中可以配置每一个session 的超时时间