监听器简介
-
是一个
实现特定接口
的普通Java程序,这个程序专门用于监听另一个Java对象的方法调用或属性改变
, 当被监听对象发生上述事件后,监听器某个方法立即被执行。
(捕捉某个对象被创建、销毁的时机;属性变化的时机)
-
Listener接口与事件对应表
-
编写监听器的步骤:
(1)编写实现类
(2)在web.xml中进行部署
(3)编写测试页面 -
根据监听器的应用范围,大致可分为三类:
(1)ServletContext范围
的监听器可以进行一些初始化的动作,如:当Web应用启动的时候进行全局配置
(2)Session范围
的监听器对一个会话过程(与客户端关联)中所产生的事件进行响应,可以对客户端信息的变化进行跟踪
(3)Request范围
的监听器可以监听用户的每次请求
与ServletContext相关监听器
-
单个Web站点的资源都共享一个javax.servlet.ServletContext类的实体。
通过该对象可以存取应用程序的全局对象以及初始化阶段的变量。 -
全局对象即为application范围对象,其生命周期
从容器启动至容器关闭。
初始阶段的变量是指在web.xml中,由<context-param>
元素设定的变量,该变量的范围时application范围。 -
不理解时,我们可以查看源代码,可以知道举体的内容:
例如:ServletContextAttributeListener
, 源代码如图所示:
根据注释可知,在一个新的attribute加入context后,被加进去后被调用。
举个例子:
每访问一次页面,pv_count加一,得到页面访问量。
Servlet类:页面显示页面访问量。
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ServletForContext
*/
@WebServlet("/ServletForContext")
public class ServletForContext extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.设置请求的编码方式
request.setCharacterEncoding("utf-8");
// 2.设置响应的类型
response.setContentType("text/html;charset=utf-8");
// 3.获取请求的信息getParameter getAtrribute
// 4.处理请求(例如查询数据库)
// 5.处理响应结果(每访问一次,pv_count加一)
PrintWriter writer = response.getWriter();
ServletContext context = getServletContext();
int pv_count = (int) context.getAttribute("pv_count");
pv_count++;
writer.write("当前页面访问量" + pv_count);
context.setAttribute("pv_count", pv_count);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
ServletContextListener:创建(初始化操作)、销毁
package listener1;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import javafx.scene.Scene;
/**
* Application Lifecycle Listener implementation class ServletContextListener
*
*/
@WebListener
public class ServletContextListener implements javax.servlet.ServletContextListener {
/**
* Default constructor.
*/
public ServletContextListener() {
// TODO Auto-generated constructor stub
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext销毁");
sce.getServletContext().removeAttribute("pv_count");
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext创建");
// 可以初始化
ServletContext context = sce.getServletContext();
context.setAttribute("pv_count", 0);
}
}
关于ServletContextListener接口:
- 实现了该接口的程序,当JavaWeb应用程序启动时,会考试监听工作。
- 首先调用contextInitialized()方法接收对应的ServletContextEvent事件
通知正在收听的对象,应用程序已经被加载及初始化 - 当应用从容器中移除时,会自动调用contextDestroyed()方法
通知正在收听的对象,应用程序已经被载出 - 以上两个方法都会接受到ServletContextEvent事件对象,该对象可以调用getServletContext()方法取得ServletContext对象(全局对象)
ServletContextAttributeListener:修改等。
package listener1;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class
* ServletContextAttributeListener
*
*/
@WebListener
public class ServletContextAttributeListener implements javax.servlet.ServletContextAttributeListener {
/**
* Default constructor.
*/
public ServletContextAttributeListener() {
// TODO Auto-generated constructor stub
}
/**
* @see ServletContextAttributeListener#attributeAdded(ServletContextAttributeEvent)
*/
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext新建属性: " + scae.getName() + "--->" + scae.getValue());
}
/**
* @see ServletContextAttributeListener#attributeRemoved(ServletContextAttributeEvent)
*/
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext移除属性: " + scae.getName() + "--->" + scae.getValue());
}
/**
* @see ServletContextAttributeListener#attributeReplaced(ServletContextAttributeEvent)
*/
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext修改属性的旧值: " + scae.getName() + "--->" + scae.getValue());
System.out.println("ServletContext修改属性的新值: " + scae.getServletContext().getAttribute(scae.getName()));
}
}
关于ServletContextAttributeListener接口:
- 实现该接口的程序,能够监听ServletContext属性的变化,例如:当往ServletContext中添加数据时,该程序会被调用。
效果:
页面能打印出页面访问量
控制台打印结果:
注意:
-
上述例子,直接通过注解方式。也可在xml中添加也可:
<listener> <listener-class>包名.类名</listener-class> </listener>
-
可在xml中添加一个全局变量。例如pv_count的初值:
<context-param> <param-name>count</param-name> <param-value>0</param-value> </context-param>
在赋初值的代码那可增加:
String count = context.getInitParameter("count").;
context.setAttribute("pv_count", Integer.parseInt(count))
与HttpSession相关监听器
- session更针对一次会话,可以用来统计用户在线人数。
(举个例子:
firefox中setAttribute(“name”. “xhx”); 关闭firefox后,打开chrome,获得的name值为none) - 关于
HttpSessionListener
HttpSessionListener监听Session对象的创建与销毁,当有Session对象创建或销毁时,会自动调用sessionCreated()或sessionDestroyed()两个方法
举个例子:
实现统计用户在线人数,创建session对象时,登录人数++;销毁session时,登陆人数–;
在线用户数量应该为是ServletContext中的。
第一个类:用来设置uv_count初始值0.
package listener1;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
import javafx.scene.Scene;
/**
* Application Lifecycle Listener implementation class ServletContextListener
*
*/
@WebListener
public class ListenerServletContext implements javax.servlet.ServletContextListener {
/**
* Default constructor.
*/
public ListenerServletContext() {
// TODO Auto-generated constructor stub
}
/**
* @see ListenerServletContext#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext销毁");
sce.getServletContext().removeAttribute("pv_count");
sce.getServletContext().removeAttribute("uv_count");
}
/**
* @see ListenerServletContext#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext创建");
// 可以初始化
ServletContext context = sce.getServletContext();
context.setAttribute("pv_count", 0);
context.setAttribute("uv_count", 0);
}
}
监听器:当新建session时,加加操作;更新、修改均有。
package listener1;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* Application Lifecycle Listener implementation class ListenerForSession
*
*/
@WebListener
public class ListenerForSession implements HttpSessionListener, HttpSessionAttributeListener {
/**
* Default constructor.
*/
public ListenerForSession() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpSessionListener#sessionCreated(HttpSessionEvent)
*/
public void sessionCreated(HttpSessionEvent se) {
System.out.println("创建Session");
ServletContext context = se.getSession().getServletContext();
int uv_count = (int) context.getAttribute("uv_count");
uv_count++;
context.setAttribute("uv_count", uv_count);
}
/**
* @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
*/
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("销毁Session");
ServletContext context = se.getSession().getServletContext();
int uv_count = (int) context.getAttribute("uv_count");
uv_count--;
context.setAttribute("uv_count", uv_count);
}
/**
* @see HttpSessionAttributeListener#attributeAdded(HttpSessionBindingEvent)
*/
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("Session添加属性:" + se.getName() + "-->" + se.getValue());
}
/**
* @see HttpSessionAttributeListener#attributeRemoved(HttpSessionBindingEvent)
*/
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("Session移除属性:" + se.getName() + "-->" + se.getValue());
}
/**
* @see HttpSessionAttributeListener#attributeReplaced(HttpSessionBindingEvent)
*/
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("Session修改的旧属性:" + se.getName() + "-->" + se.getValue());
System.out.println("Session修改后的新属性:" + se.getSession().getAttribute(se.getName()));
}
}
访问这个页面,就让session失效。
package servlet;
//作用:让session失效
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/ServletForSession2")
public class ServletForSession2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession().invalidate();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
servlet类
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class ServletForSession
*/
@WebServlet("/ServletForSession")
public class ServletForSession extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.设置请求的编码方式
request.setCharacterEncoding("utf-8");
// 2.设置响应的类型
response.setContentType("text/html;charset=utf-8");
// 3.获取请求的信息getParameter getAtrribute
// 4.处理请求(例如查询数据库)
// 5.处理响应结果(第一次,创建session)
PrintWriter writer = response.getWriter();
HttpSession session = request.getSession();
System.out.println(session.getId());
//只是为了看监听器的作用
session.setAttribute("name", "aaa");
session.setAttribute("name", "bbb");
session.removeAttribute("name");
//打印用户量
ServletContext context = getServletContext();
int count = (int)context.getAttribute("uv_count");
writer.write("当前的用户访问量是:" + count);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
控制台输出如下:
补充:
HttpSessionEvent事件
- HttpSessionListener接口与HttpSessionActivationListener接口都使用HttpSessionEvent事件对象
- HttpSessionEvent类主要的方法:
getSession()
HttpSessionActivationListener接口
- 该接口主要用于:
同一个Session转移到不同JVM的情形
(如:负载均衡,这些JVM可以在同一台机器或分散在网络中的多台机器) - 当Session被储存起来,并且等待转移至另一个JVM,这段时间称为
失效状态
(Passivate),若Session中的属性对象实现HttpSessionActivationListener接口时,Container会自动调用sessionWillPassivate()方法通知该对象的Session已变成失效状态 - 当Session被转移至其他JVM之后,它又成为
有效状态(Activate)
,此时Container会自动调用sessionDidActivate()方法通知该对象的Session已变成有效状态 - HttpSessionAttributeListener会监听Session范围的变化,功能与ServletContextAttributeListener接口类似,包含三个方法
attributeAdded()
attributeReplaced()
attributeRemove()
HttpSessionBindingEvent事件
1. 主要有三种方法:getName(), getSession(), getValue();
HttpSessionBindingListener
-
需要自定义实现HttpSessionBindingListener接口的类
-
实例化监听器类的对象。
-
只监听具体的属性,如下所示,只监听“testBinding”
举个例子:
4. 实现HttpSessionBindingListener接口后,只要有对象加入Session范围或从Session范围中移除时,容器会分别自动调用下面两个方法:
valueBound(HttpSessionBindingEvent e)
valueUnbound(HttpSessionBindingEvent e) -
HttpSessionBindingListener接口是唯一
不需要在web.xml中设定的Listener
例如实现记录访问过的用户(在context中加一个list,每次触发valueBound时,进行添加操作。)
与ServletRequest相关监听器
- 当有请求产生或销毁,会自动调用该接口实现的requestInitalized()或requestDestroyed()方法。
- 该接口使用ServletRequestEvent事件。
ServletRequestEvent的主要方法:
getServletContext(), getServletRequest()
.
举一个简单例子,体会这几个方法:
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ServletForRequest
*/
@WebServlet("/ServletForRequest")
public class ServletForRequest extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("age", 18);
request.setAttribute("age", 19);
request.removeAttribute("age");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
package listener1;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class ListenerForRequest
*
*/
@WebListener
public class ListenerForRequest implements ServletRequestListener, ServletRequestAttributeListener {
/**
* Default constructor.
*/
public ListenerForRequest() {
}
/**
* @see ServletRequestListener#requestDestroyed(ServletRequestEvent)
*/
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("销毁Request对象");
}
/**
* @see ServletRequestAttributeListener#attributeRemoved(ServletRequestAttributeEvent)
*/
public void attributeRemoved(ServletRequestAttributeEvent srae) {
// TODO Auto-generated method stub
}
/**
* @see ServletRequestListener#requestInitialized(ServletRequestEvent)
*/
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("新建Request对象");
}
/**
* @see ServletRequestAttributeListener#attributeAdded(ServletRequestAttributeEvent)
*/
public void attributeAdded(ServletRequestAttributeEvent srae) {
// TODO Auto-generated method stub
}
/**
* @see ServletRequestAttributeListener#attributeReplaced(ServletRequestAttributeEvent)
*/
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("Request修改前的旧值" + srae.getName() + "-->" + srae.getValue());
System.out.println("Request修改前的新值" + srae.getName() + "-->" + srae.getServletRequest().getAttribute(srae.getName()));
}
}
效果如下图所示:
小总结:
- 得到ServletContext方法:
(1)Servlet中:getServletContext();
(2)监听器中:
1)ServletContextListener中的监听对象ServletContextEvent也可直接调用这个getServletContext()方法
2)监听器ServletContextAttributeListener(因为它implements javax.servlet.ServletContextAttributeListener),它的事件对象ServletContextAttributeEvent (extends ServletContextEvent), 也可直接调用getServletContext()方法。
(3)监听器:
1)HttpSessionListener中的事件对象HttpSessionEvent:调用getSession().getServletContext()方法
HttpSessionAttributeListener中的事件对象HttpSessionBindingEvent:调用:getSession().getServletContext()方法
(HttpSessionBindingEvent extends HttpSessionEvent )
(4)监听器的ServletRequestListener, ServletRequestAttributeListener事件对象ServletRequestEvent,ServletRequestAttributeEvent,可调用getServletContext()
方法