1.什么是监听器?  58

  - 监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。

  - 在Servlet中,所有的监听器接口都是以“Listener”结尾。

1.1 监听器有什么用? 58

  - 监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。

  - 特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。

2. Servlet规范中提供了哪些监听器?58

 - jakarta.servlet包下:

    - ServletContextListener

    - ServletContextAttributeListener

    - ServletRequestListener

    - ServletRequestAttributeListener

  - jakarta.servlet.http包下:

    - HttpSessionListener

    - HttpSessionAttributeListener

      - 该监听器需要使用@WebListener注解进行标注。

      - 该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。

 HttpSessionBindingListener

      - 该监听器不需要使用@WebListener进行标注。

      - 假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。

      - 假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。

  - HttpSessionIdListener

      - session的id发生改变的时候,监听器中的唯一一个方法就会被调用。

 - HttpSessionActivationListener

      - 监听session对象的钝化和活化的。

      - 钝化:session对象从内存存储到硬盘文件。

      - 活化:从硬盘文件把session恢复到内存。

3. 实现一个监听器的步骤:以ServletContextListener为例。58

  - 第一步:编写一个类实现ServletContextListener接口。并且实现里面的方法。


void contextInitialized(ServletContextEvent event)
      void contextDestroyed(ServletContextEvent event)

  - 第二步:在web.xml文件中对ServletContextListener进行配置,如下:

      <listener>
          <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>
      </listener>


    - 当然,第二步也可以不使用配置文件,也可以用注解,例如:@WebListener

3.1  ServletContextListener   ServletRequestListener   HttpSessionListener   58

代码在com.bjpowernode.javaweb.listener

MyServletContextListener

package com.bjpowernode.javaweb.listener;

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;

//监听器ServletContextListener讲解  58
@WebListener
public class MyServletContextListener implements ServletContextListener {

    //监听器中的方法不需要程序员手动调用。是发生某个特殊事件之后被服务器调用。

    @Override
    // 服务器启动时间点,想在这个时候执行一段代码,写就行了。
    public void contextInitialized(ServletContextEvent sce) {
        // 现在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
        // 这个方法是在ServletContext对象被创建的时候调用。
        System.out.println("ServletContext对象创建了");

    }

    @Override
    // 服务器关闭时间点。
    public void contextDestroyed(ServletContextEvent sce) {
        // 现在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
        // 这个方法是在ServletContext对象被销毁的时候调用。
        System.out.println("ServletContext对象被销毁了");
    }
}

MyServletRequestListener

package com.bjpowernode.javaweb.listener;

import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.annotation.WebListener;

//ServletRequestListener监听器  58
@WebListener
public class MyServletRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("request销毁了");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("request对象初始化了");
    }
}

MyHttpSessoinListener

package com.bjpowernode.javaweb.listener;

import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;

//ttpSessionListener监听器  58
@WebListener
public class MyHttpSessoinListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("session被创建了");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("session被销毁了");
    }
}

代码在com.bjpowernode.javaweb.servlet

ExitServlet
package com.bjpowernode.javaweb.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

//退出系统的Servlet  58
@WebServlet("/exit")
public class ExitServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession(false);
        if(session !=null){
            //销毁session
            session.invalidate();
        }
    }
}

my.jsp

<%--HttpSessionListener监听器的退出系统配置  58--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
my jsp page
<a href="${pageContext.request.contextPath}/exit">退出系统</a>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

<!--    配置MyServletContextListener监听器  58-->
    <!--<listener>
        <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>
    </listener>
-->
</web-app>

3.2 HttpSessionAttributeListener    59

代码在com.bjpowernode.javaweb.listener

MyHttpSessionAttributeListener
package com.bjpowernode.javaweb.listener;

import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionBindingEvent;

//MyHttpSessionAttributeListener监听器  59
@WebListener
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

    // 向session域当中存储数据的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("session data add");
    }

    // 将session域当中存储的数据删除的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("session data remove");
    }

    // session域当中的某个数据被替换的时候,以下方法被WEB服务器调用。
    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("session data replace");
    }
}

com.bjpowernode.javaweb.servlet

HttpSessionAttributeServlet
package com.bjpowernode.javaweb.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

//向session域中存数据的servlet  59
@WebServlet("/session/attribute/test")
public class HttpSessionAttributeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //获取session对象
        HttpSession session = request.getSession();
        //向session域中存储数据
        session.setAttribute("user","zhangsan");
        //替换
        session.setAttribute("user","lisi");
        //删除
        session.removeAttribute("user");

    }
}

监听域对象创建和销毁监听器_java

3.3  HttpSessionBindingListener   60

com.bjpowernode.javaweb.bean

User1
package com.bjpowernode.javaweb.bean;

import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;

//普通的javabean实现了HttpSessionBindingListener接口  60
public class User1 implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("绑定数据");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("解绑数据");
    }

    private String usercode;
    private String username;
    private String password;

    public User1() {
    }

    public User1(String usercode, String username, String password) {
        this.usercode = usercode;
        this.username = username;
        this.password = password;
    }

    public String getUsercode() {
        return usercode;
    }

    public void setUsercode(String usercode) {
        this.usercode = usercode;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
User2
package com.bjpowernode.javaweb.bean;

//普通的java类  60
public class User2 {
    private String usercode;
    private String username;
    private String password;

    public User2() {
    }

    public User2(String usercode, String username, String password) {
        this.usercode = usercode;
        this.username = username;
        this.password = password;
    }

    public String getUsercode() {
        return usercode;
    }

    public void setUsercode(String usercode) {
        this.usercode = usercode;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
com.bjpowernode.javaweb.servlet
HttpSessionBindingListenerServlet
package com.bjpowernode.javaweb.servlet;

import com.bjpowernode.javaweb.bean.User1;
import com.bjpowernode.javaweb.bean.User2;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

//一个HttpSessionBindingListener的servlet  60
@WebServlet("/session/bind")
public class HttpSessionBindingListenerServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //获取session对象
        HttpSession session = request.getSession();
        //准备两个User对象
        User1 user1 = new User1("111","zhangsan","123");
        User2 user2 = new User2("111","zhangsan","123");
        //将User1存储到session域
        session.setAttribute("user1",user1);
        //将User2存储到session域
        session.setAttribute("user2",user2);

    }
}

4. 注意:58

所有监听器中的方法都是不需要javaweb程序员调用的,由服务器来负责调用,什么时候被调用呢?

  - 当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。

5. 思考一个业务场景:60

  - 请编写一个功能,记录该网站实时的在线用户的个数。

  - 我们可以通过服务器端有没有分配session对象,因为一个session代表了一个用户。有一个session就代表有一个用户。如果你采用这种逻辑去实现的话,session有多少个,在线用户就有多少个。这种方式的话:HttpSessionListener够用了。session对象只要新建,则count++,然后将count存储到ServletContext域当中,在页面展示在线人数即可。

  - 业务发生改变了,只统计登录的用户的在线数量,这个该怎么办?

    - session.setAttribute("user", userObj); 

    - 用户登录的标志是什么?session中曾经存储过User类型的对象。那么这个时候可以让User类型的对象实现HttpSessionBindingListener监听器,只要User类型对象存储到session域中,则count++,然后将count++存储到ServletContext对象中。页面展示在线人数即可。

6. 实现oa项目中当前登录在线的人数。(此代码写在course26中) 61

  - 什么代表着用户登录了?

    - session.setAttribute("user", userObj); User类型的对象只要往session中存储过,表示有新用户登录。

  - 什么代表着用户退出了?

    - session.removeAttribute("user"); User类型的对象从session域中移除了。

    - 或者有可能是session销毁了。(session超时)