测试方向基础——监听器浅析

监听器简介

  1. 是一个实现特定接口的普通Java程序,这个程序专门用于监听另一个Java对象的方法调用或属性改变, 当被监听对象发生上述事件后,监听器某个方法立即被执行。
    (捕捉某个对象被创建、销毁的时机;属性变化的时机)
    在这里插入图片描述

  2. Listener接口与事件对应表
    在这里插入图片描述

  3. 编写监听器的步骤:
    (1)编写实现类
    (2)在web.xml中进行部署
    (3)编写测试页面

  4. 根据监听器的应用范围,大致可分为三类:
    (1)ServletContext范围的监听器可以进行一些初始化的动作,如:当Web应用启动的时候进行全局配置
    (2)Session范围的监听器对一个会话过程(与客户端关联)中所产生的事件进行响应,可以对客户端信息的变化进行跟踪
    (3)Request范围的监听器可以监听用户的每次请求

与ServletContext相关监听器

  1. 单个Web站点的资源都共享一个javax.servlet.ServletContext类的实体。通过该对象可以存取应用程序的全局对象以及初始化阶段的变量。

  2. 全局对象即为application范围对象,其生命周期从容器启动至容器关闭。初始阶段的变量是指在web.xml中,由<context-param>元素设定的变量,该变量的范围时application范围。

  3. 不理解时,我们可以查看源代码,可以知道举体的内容:
    例如: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接口:

  1. 实现了该接口的程序,当JavaWeb应用程序启动时,会考试监听工作。
  2. 首先调用contextInitialized()方法接收对应的ServletContextEvent事件
    通知正在收听的对象,应用程序已经被加载及初始化
  3. 当应用从容器中移除时,会自动调用contextDestroyed()方法
    通知正在收听的对象,应用程序已经被载出
  4. 以上两个方法都会接受到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接口:

  1. 实现该接口的程序,能够监听ServletContext属性的变化,例如:当往ServletContext中添加数据时,该程序会被调用。

效果:
页面能打印出页面访问量
控制台打印结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:

  1. 上述例子,直接通过注解方式。也可在xml中添加也可:

    <listener>
    <listener-class>包名.类名</listener-class>
    </listener>
    
  2. 可在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相关监听器

  1. session更针对一次会话,可以用来统计用户在线人数。
    (举个例子:
    firefox中setAttribute(“name”. “xhx”); 关闭firefox后,打开chrome,获得的name值为none)
  2. 关于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事件

  1. HttpSessionListener接口与HttpSessionActivationListener接口都使用HttpSessionEvent事件对象
  2. HttpSessionEvent类主要的方法:getSession()

HttpSessionActivationListener接口

  1. 该接口主要用于:同一个Session转移到不同JVM的情形(如:负载均衡,这些JVM可以在同一台机器或分散在网络中的多台机器)
  2. 当Session被储存起来,并且等待转移至另一个JVM,这段时间称为失效状态(Passivate),若Session中的属性对象实现HttpSessionActivationListener接口时,Container会自动调用sessionWillPassivate()方法通知该对象的Session已变成失效状态
  3. 当Session被转移至其他JVM之后,它又成为有效状态(Activate),此时Container会自动调用sessionDidActivate()方法通知该对象的Session已变成有效状态
  4. HttpSessionAttributeListener会监听Session范围的变化,功能与ServletContextAttributeListener接口类似,包含三个方法
    attributeAdded()
    attributeReplaced()
    attributeRemove()

HttpSessionBindingEvent事件
1. 主要有三种方法:getName(), getSession(), getValue();

HttpSessionBindingListener

  1. 需要自定义实现HttpSessionBindingListener接口的类

  2. 实例化监听器类的对象。

  3. 只监听具体的属性,如下所示,只监听“testBinding”
    举个例子:
    在这里插入图片描述
    4. 实现HttpSessionBindingListener接口后,只要有对象加入Session范围或从Session范围中移除时,容器会分别自动调用下面两个方法:
    valueBound(HttpSessionBindingEvent e)
    valueUnbound(HttpSessionBindingEvent e)

  4. HttpSessionBindingListener接口是唯一不需要在web.xml中设定的Listener

    在这里插入图片描述
    例如实现记录访问过的用户(在context中加一个list,每次触发valueBound时,进行添加操作。)

与ServletRequest相关监听器

  1. 当有请求产生或销毁,会自动调用该接口实现的requestInitalized()或requestDestroyed()方法。
  2. 该接口使用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()));
    	
    }
	
}

效果如下图所示:
在这里插入图片描述

小总结:

  1. 得到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()方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xuhx&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值