监听器介绍

什么是监听器

生活中的例子:
班主任,根据学员上课的状态,做出相应的处理(睡觉了,扣分,玩手机,扣分没收,发呆,扣分)
监听器:监听事件源,根据事件源上发生事件,做出相应的处理。
image.png

监听机制相关概念

事件源:发生事件的源头,监听器需要监听的对象。
事件:事件源上发生的动作,监听器监听的内容。
监听器:负责监听事件源的对象。
image.png

web监听器介绍

javaweb监听器介绍

JavaWEB中的监听器主要监听JavaWEB中的request、session、ServletContext对象的各种变化。
主要监听的任务:
监听request、ServletContext 、session对象的创建和销毁(练习)
ServletRequestListener
ServletContextListener
HttpSessionListener
监听request、session、ServletContext 对象存放的数据变化情况(练习)
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
监听session中保存的JavaBean的状态
HttpSessionBindingListener
HttpSessionActivationListener

javaweb监听器创建步骤(示例:ServletRequestListener)

需要定义一个类实现对应的监听器接口

ServletRequestListener定义(API截图):
image.png
image.png
代码演示:

  1. package cn.igeek.listener;
  2. import javax.servlet.ServletRequestEvent;
  3. import javax.servlet.ServletRequestListener;
  4. public class MyServletRequestListener implements ServletRequestListener{
  5. @Override
  6. //监听request对象销毁的方法
  7. public void requestDestroyed(ServletRequestEvent sre) {
  8. System.out.println("MyServletRequestListener.....requestDestroyed....");
  9. }
  10. @Override
  11. //监听request对象初始化的方法
  12. public void requestInitialized(ServletRequestEvent sre) {
  13. System.out.println("MyServletRequestListener.....requestInitialized....");
  14. }
  15. }

image.png

配置监听器对象

image.png
注意:当服务器加载项目的时候,会读取web.xml文件中listener标签,那么服务器会自动创建监听器对象,并且自动调用其方法

自动调用其方法,也是通过反射调用(因为他的方法名称和参数是固定的)

监听器的小结:
1)创建一个类,实现监听器接口
2)在监听器对象的方法中,书写相关的代码
3)在web.xml中配置当前监听器。

ServletContext创建销毁监听

ServletContextListener定义(API截图):
image.png
image.png
代码演示:

  1. package cn.igeek.listener;
  2. import javax.servlet.ServletContextEvent;
  3. import javax.servlet.ServletContextListener;
  4. public class MyServletContextListener implements ServletContextListener{
  5. @Override
  6. public void contextInitialized(ServletContextEvent sce) {
  7. System.out.println("MyServletContextListener.....contextInitialized....");
  8. }
  9. @Override
  10. public void contextDestroyed(ServletContextEvent sce) {
  11. System.out.println("MyServletContextListener.....contextDestroyed....");
  12. }
  13. }

监听器配置:

<listener>
      <listener-class>cn.igeek.listener.MyServletContextListener</listener-class>
  </listener>

监听servletcontext对象初始化截图:
image.png
监听servletcontext对象销毁截图:
image.png

ServletContextListener案例:定时任务

需求:项目启动时,获取服务器时间(new Date()),每一秒钟更新一次,打印在控制台
思路:
1)监控项目的启动(使用ServletContextListener来监听ServletContext对象的初始化)
1)获取服务器时间:new Date();
2)每一秒更新一次:定时器Timer
4)给定时器设置定时任务

Timer:定时器 任务调度的对象
image.png
image.png
image.png
image.png
task:定时器的任务(类)
delay:从什么时候开始执行,立即执行设置为:0
period:间隔多少时间重复执行,毫秒值,1秒=1000毫秒

TimerTask:定时器的任务(类)
image.png
image.png
Run方法中应该写我们的定时任务:每一秒钟更新一次时间,打印在控制台上

代码实现:

package cn.igeek.listener;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * @author wjn
 *  1)    创建一个类,实现监听器接口
    2)    在监听器对象的方法中,书写相关的代码
    3)    在web.xml中配置当前监听器。
 */
public class MyServletContextListener implements ServletContextListener{

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyServletContextListener....contextInitialized...");
        //监控项目的启动(使用ServletContextListener来监听ServletContext对象的初始化)
        //2)    获取服务器时间:new Date();
        //3)    每一秒更新一次:定时器Timer
        //4)          给定时器设置定时任务

        //获取定时器
        Timer timer = new Timer();
        //调用定时器的设置定时任务的方法
        //firstTime 0:立即执行
        //period:间隔多长时间执行一次,1000
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                //在run方法中,书写,要执行的任务
                //过时的方法一般不推荐使用,但是,过时的方法,jdk不会删除它的效果。
                //当前显示时间,可以使用服务器中的时间——java代码,new Date();
                //当前显示时间——javascript代码,new Date();
                //javascript代码,是在浏览器运行,客户端的时间,一般是不使用客户端的时间
                //业务:整点秒杀
                //获取的是服务器时间,用户,是没有办法控制
                //获取客户端时间,时间有客户控制,时间是不对的
                //一般尊循的原则,只要可以控制在服务器的,绝对不给客户端
                System.out.println(new Date().toLocaleString());
            }
        }, 0, 1000);

    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyServletContextListener....contextDestroyed...");
    }

}

效果:
image.png

HttpSessionListener对象监听session的创建与销毁监听

HttpSessionListener定义(API截图):
image.png
image.png
代码演示:

package cn.igeek.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyHttpSessionListener implements HttpSessionListener{

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionCreated....");

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionDestroyed....");

    }

}

配置文件:

<listener>
        <listener-class>cn.igeek.listener.MyHttpSessionListener</listener-class>
    </listener>

Invalidate.jsp页面代码:
image.png
效果截图:
image.png

案例——统计在线人数

需求:统计当前访问网站的人数有多少人?

问题:什么时候我们可以知道用户访问了网站?
只要用户访问了我们的网站,session一定会创建。只要用户离开,点退出(注销),session就销毁。

思路:
只要判断session创建,在线人数就加一
只要判断session销毁,在线人数就减一

在线人数的数据,要存在哪里?
答:ServletContext对象中,所有应用程序范围都可以获取,所有访问当前网站的用户,都应该可以看到在线人数

总思路:
1 现在项目启动的时候,初始化在线人数0,保存在ServletContext
2 监听到session创建数据加一
3 监听到session销毁数据减一
4 在页面展示数据

代码实现:
image.png
监听器代码:

package cn.igeek.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionCreated....");
        // 在监听器中只要判断session创建,在线人数就加一

        ServletContext context = se.getSession().getServletContext();
        // 获取里面的在线人数
        Integer onlineNum = (Integer) context.getAttribute("onlineNum");
        onlineNum = onlineNum + 1;
        context.setAttribute("onlineNum", onlineNum);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("MyHttpSessionListener....sessionDestroyed....");
        // 在监听器中只要判断session销毁,在线人数就减去一

        ServletContext context = se.getSession().getServletContext();
        // 获取里面的在线人数
        Integer onlineNum = (Integer) context.getAttribute("onlineNum");
        onlineNum = onlineNum - 1;
        context.setAttribute("onlineNum", onlineNum);

    }

}

index.jsp显示在线人数,显示退出链接:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <title>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>

  <body>
    igeek-filter2项目主页<br>
    当前在线人数:${onlineNum }
    <a href="${pageContext.request.contextPath }/validate.jsp">退出</a>
  </body>
</html>

页面效果:
image.png

属性变化的监听

属性监听器介绍

主要是监听使用setAttribute、removeAttribute方法。
ServletContextAttributeListener 专门用于监听ServletContext对象中的属性的变化情况
HttpSessionAttributeListener 专门用于监听session对象中的属性的变化情况
ServletRequestAttributeListener专门用于监听request对象中的属性的变化情况
它们中的的监听添加、删除、修改的方法名称全部一致:
image.png
代码演示:
Jsp:

<%
           session.setAttribute("name", "毛爷爷");
           session.setAttribute("name", "邓爷爷");
           session.removeAttribute("name");

%>

监听器:

package cn.igeek.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener    {

    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeAdded...");
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeRemoved...");
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("MyHttpSessionAttributeListener....attributeReplaced...");
    }

}

配置文件:

<listener>
        <listener-class>cn.igeek.listener.MyHttpSessionAttributeListener</listener-class>
    </listener>

image.png

Session中的bean(JavaBean)监听

当我们给Session中保存一个Java对象的时候,或者把Java对象从Session中移除的时候会触发专门用来监听Session中对象变化的监听器中的方法。拥有这个方法的对象——HttpSessionBindingListener接口

属性监听和bean监听的区别:
属性监听:是对三个容器中的任何属性(包括对象和不是对象的数据,基本类型数据)的变化,进行监听
Bean监听:它只监听javabean对象往session中保存和session中移出的过程。
image.png
image.png
由于HttpSessionBindingListener是用来监听某个JavaBean对象的绑定(存入session容器)和解绑(从session容器中移除)的,所以这个监听器的实现类必须是被操作的JavaBean(HttpSessionBindingListener不需要再web.xml中配置)

javaBean:

package cn.igeek.domain;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class User implements HttpSessionBindingListener{

    private int age;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("User....valueBound...");

    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("User....valueUnbound...");

    }

}

JSP:

<%
            session.setAttribute("user", new User());

         session.removeAttribute("user");
     %>

效果:
image.png
Bean监听需求:
在线人数,根据session创建和销毁,来做人数的增减。
在线会员统计:
1)User类实现bean监听接口
2)每次监听到loginUser对象被绑定到session中的时候,会员人数加一
3)每次监听到loginUser对象被解绑的时候,会员人数减一

总结:

  1. 熟悉监听器相关的概念(事件源事件监听器)
  2. 掌握监听器的创建步骤
  3. 完成笔记中两个案例(定时任务 在线人数)

服务器的启动时间动态获取如何做?