监听器就是一个实现了特定接口的Java类,主要用于监听某个对象的状态变化。
第一维度:按照被监听的对象划分:ServletRequest域、HttpSession域、ServletContext域
第二维度:监听的内容分:域对象的创建与销毁的、与对象的属性变化的、绑定到HttpSession域中的某个对象状态的
维度 | ServletContext域 | HttpSession域 | ServletRequest域 |
域对象的创建与销毁 |
ServletContextListener | HttpSessionListener | ServletRequestListener |
与对象的属性变化 | ServletContextAttributeListener |
HttpSessionAttributeListene
|
ServletRequestAttributeListener
|
绑定到HttpSession域中某个对象的状态
|
----- |
HttpSessionBindingListener
HttpSessionActivationListener
|
---- |
(1) 实现了特定接口的类为监听器,用来监听另一个java类的方法调用或者属性改变;
(2)当被监听的对象发生了方法调用或者属性改变后,监听器的对应方法就会立即执行。
监听器涉及到以下几个组成部分:
1、事件源:被监听的对象,即:request、session、servletContext三大域对象。
2、监听器:监听事件源对象,事件源对象状态的变化都会触发监听器
3、注册监听器:将监听器与事件源绑定,有两种注册方式:web.xml或@WebListener注解
4、事件:域对象发生改变
原理图:
1.统计在线人数和在线用户
2.系统启动时加载初始化信息
3.统计网站访问量
4.跟Spring结合
(1)定义一个普通类实现监听器接口
(2)重写监听器接口方法
(3)注册监听器:配置web.xml或@WebListener注解
ServletContextListener监听器:用来监听ServletContext域对象的创建和销毁。
ServletContextListener对象代表全局唯一对象,每一个web工程会产生一个ServletContext对象,服务器启动时创建,服务器关闭时销毁。
(1)创建一个普通类,实现ServletContextListener接口,并重写内部的两个方法。
package com.ujiuye.com.ujiuye.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 监听ServletContext的创建和销毁
* 1、创建一个普通的类实现特定的接口ServletContextListener
* 2、重写方法
* 3、注册监听器 web.xml和注解
*
* ServletContext随着tomcat的启动而创建,随着服务器的停止或者重启而销毁
*/
//@WebListener
public class Demo01Listener implements ServletContextListener {
//初始化方法
//当创建servletContext对象,就会被监听到,就会执行下面的方法,自动执行的
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("servletContext创建了");
}
//销毁方法
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("servletcontext销毁了创建了");
}
}
(2)注册监听器
xml:
com.ujiuye.listener.Demo01Listener
@WebListener:
(3)测试监听器
当tomcat服务器开启时执行被创建的方法contextInitialized,服务器被关闭执行被销毁的方法contextDestroyed。
HttpSessionListener监听器:用来监听HttpSession域对象的创建和销毁。
Session何时创建:Servlet中是request.getSession(),JSP页面中自带Session。
Session何时销毁:非正常关闭服务器,Session过期,session.invalidate()
(1)创建一个普通类,实现HttpSessionListener接口,并重写内部的两个方法。
package com.ujiuye.listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
/**
* 测试request创建和销毁
*/
public class Demo02Listener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request销毁了-------");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request创建了-------");
}
}
(2)注册监听器
在MyHttpSessionListener监听器类的上方添加注解@WebListener
(3)测试监听器
测试Session对象的创建:创建一个jsp页面index.jsp
直接访问index.jsp页面,由于Session时jsp的内置对象,意味着在访问index.jsp页面时创建了Session对象,因此会触发监听器的创建方法。
测试Session对象的销毁:
(1)可以在web.xml文件中配置一下session的有效期,让其在一分钟过期,当超过一分钟没有操作服务器页面就会触发销毁方法;
1
(2)执行session.invalidate()方法强制销毁session
ServletRequestListener监听器:用来监听ServletRequest域对象的创建和销毁。
Request何时创建:请求发起时创建
Request何时销毁:响应结束时销毁
创建ServletRequestListener监听器:
(1)创建一个普通类,实现ServletRequestListener接口,并重写内部的两个方法。
package com.ujiuye.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 监听session创建和销毁
*
* 1、打开浏览器 访问项目 会话开始,就会创建一个session对象 session就创建了
* 关闭浏览器代表会话结束,在打开浏览器去访问项目,
* 只会创建一个新的session,原来的session只是找不到了,并没有立即销毁
* 2、session什么时候销毁
* 默认30分钟没有操作 tomcat/conf/web.xml session-timeout标签配置
* 可以在自己的web.xml进行配置
* 调用session.invalidate() 让当前session立即销毁
*/
//@WebListener
public class Demo03Listener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session销毁");
}
}
(2)注册监听器
在MyServletRequestListener监听器类的上方添加注解@WebListener
(3)测试监听器
直接访问index.jsp,jsp有内置的request进行创建,请求结束销毁
ServletContext、HttpSession、ServletRequest中添加数据、修改数据、移除数据的监听器。
ServletContextAttributeListener监听器:监听ServletContext中属性的变化。
HttpSessionAttributeListener监听器: 监听HttpSession中属性的变化。
ServletRequestAttributeListener 监听器:监听ServletRequest中属性的变化
package com.ujiuye.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
/**
* 测试 session值的变化
*/
//@WebListener
public class Demo05Listener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
//添加
System.out.println("--------------------------------");
System.out.println("向session中添加值");
String name = se.getName();
Object value = se.getValue();
System.out.println(name);
System.out.println(value);
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
//移除
System.out.println("--------------------------------");
System.out.println("向session中移除值");
String name = se.getName();
Object value = se.getValue();
System.out.println(name);
System.out.println(value);
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
//替换
System.out.println("--------------------------------");
System.out.println("向session中替换值");
//获取的是替换之前的键值对
String name = se.getName();
Object value = se.getValue();
System.out.println(name);
System.out.println(value);
}
}
(2)注册监听器
监听器类的上方添加注解@webListener
(3)测试监听器
创建一个jsp页面session.jsp,在该页面中分别对session域做添加,移除,替换的操作,这样就会触发不同的方法执行
<%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 14:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
session.setAttribute("age",17);
session.setAttribute("age",77);
session.removeAttribute("age");
%>
此类监听器是Servlet中比较特殊的监听器,主要用来监听绑定到Session域中待定对象的状态。
1.绑定:将java对象绑定到session中;
2.解除绑定:将java对象从session中解除绑定;
3.钝化:数据随Session对象序列化到一个存储设备中(硬盘);
4.活化:数据随Session对象从一个存储设备中(硬盘)恢复到内存。
实现HttpSessionBindingListener接口的java对象,可以感知自身被绑定到Session或者从Session中解除绑定。
案例:监听一个学生对象与Session绑定与解绑的状态
(1)创建一个学生类student实现HttpSessionBindingListener接口,并重写内部两个方法。
package com.ujiuye.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/**
*
* 第7个监听器
* 监听java对象从session中解绑或者绑定
* 指的是实现了HttpSessionBindingListener接口的对象 并不是所有的java对象
* 注意: 该监听器比较特殊,针对某一个特定的java对象,不需要去加上注解@WebListener
*/
public class Student implements HttpSessionBindingListener {
private String name;
private int age;
@Override
public void valueBound(HttpSessionBindingEvent event) {
//绑定
System.out.println("-----------------------------------------");
System.out.println("student对象绑定到session中");
//获取绑定student对象简直对
String name = event.getName();
Object value = event.getValue();
System.out.println(name);
System.out.println(value);
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
//解绑
System.out.println("-----------------------------------------");
System.out.println("student对象从session中解绑了");
//获取student对象解绑的键值对
String name = event.getName();
Object value = event.getValue();
System.out.println(name);
System.out.println(value);
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
(2)测试:创建一个jsp页面,创建用户对象并分别绑定和移除Session进行测试
<%@ page import="com.ujiuye.listener.Student" %><%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 14:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
Student student = new Student("李华",48);
//将student对象绑定到session中
session.setAttribute("student",student);
//从session中解绑
session.removeAttribute("student");
%>
实现HttpSessionActivationListener接口的java对象,可以感知从内存被钝化到硬盘,从硬盘活化到内存中。
钝化时机:服务器关闭或重启,指定时间内(长时间)不操作服务器。
活化时机:服务器再次开启。
案例:监听一个老师对象的钝化与活化状态
(1)创建一个老师类Teacher实现HttpSessionActivationListener接口,实现序列化接口,并重写内部两个方法。
package com.ujiuye.listener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;
/**
* 第八个监听器
* 1、监听session活化和钝化
* 钝化 将内存中的session存到本地磁盘
* 活化 将本地磁盘的session活跃到内存中
* 2、钝化时机: 关闭服务器、重启服务器
* 3、活化时机: 开启服务器
* 4、实现HttpSessionActivationListener接口
* 5、注意: 不需要加上注解@WebListener
*
* 测试步骤
* 1、要向session中添加Teacher对象
* 2、implements序列化接口Serializable
*
*/
public class Teacher implements HttpSessionActivationListener, Serializable{
private String name;
private int age;
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
//钝化9AAC29940B893CD0C785FA7A429440AF
System.out.println("存储teacher对象的session钝化了");
//获取session的id
System.out.println(se.getSession().getId());
System.out.println("------------------------------------");
}
@Override
public void sessionDidActivate(HttpSessionEvent se) {
//活化
System.out.println("存储teacher对象的session活化了");
System.out.println(se.getSession().getId());
System.out.println("------------------------------------");
}
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
(2)配置tomcat根目录下conf文件夹里的context.xml文件,其中directory="e:\test"表示自定义钝化文件的存储路径,maxIdleSwap="1"表示超过1分钟未操作服务器会自动钝化。
(3)测试:创建一个listener_teacher.jsp页面,向Session中保存一个老师对象。
<%@ page import="com.ujiuye.listener.Teacher" %><%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 14:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
session.setAttribute("teacher",new Teacher("黎老板",18));
%>
再创建一个listener_teacher01.jsp页面获取活化后Session中的数据是否存在
<%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 15:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
System.out.println(session.getAttribute("teacher"));
%>
首先运行listener.jsp页面,向Session中存入老师信息,然后关闭服务器或通过设置maxidleSwap
="1"等待1分钟不操作服务器,都会触发钝化方法执行,同时在指定的路径e:\test下
然后重新启动服务器,访问listener_teacher01.jsp,此时会触发活化方法将Session文件中的
数据读取到内存,会读取到数据。
实现这两个接口的类不需要有web.xml文件或注解中进行注册监听器,都有由Session自主完成的。
思路分析:通过ServletContextListener监听,当Web应用上下文启动时,在ServletContext中
添加一个List集合,用来准备存放在线的用户名;然后可以通过HttpSessionAttributeListener监
听器,当用户登录成功,把用户名设置到Session中时,同时将用户名存放到ServletContext中的
List列表中;最后通过HttpSessionListener监听。
online_login.jsp:
<%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 15:39
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--登陆页面--%>
online_main.jsp:
<%--
Created by IntelliJ IDEA.
User: why
Date: 2022/10/28
Time: 15:44
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
显示在线用户名
<%--所有的用户名都在servletContext作用域中 application.getAttr(online)--%>
在线人数:${applicationScope.online.size()}
${username }
OnlineLoginServlet:
package com.ujiuye.servlet;
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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/onlineLoginServlet")
public class OnlineLoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
//设置字符集
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//接收用户名
String username = req.getParameter("username");
//lists集合中就是已经注册过的用户名
List lists = new ArrayList<>();
lists.add("张三1");
lists.add("张三2");
lists.add("张三3");
lists.add("张三4");
lists.add("李四1");
lists.add("李四2");
lists.add("李四3");
lists.add("李四4");
//判断用户是否登陆成功
if(lists.contains(username)) {
//将username放到session中
req.getSession().setAttribute("username",username);
//跳转到主页
resp.sendRedirect("online_main.jsp");
}else {
System.out.println("登陆失败");
}
}
}
OnlineListener:
package com.ujiuye.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.ArrayList;
import java.util.List;
/**
* 统计在线人数
* 1、准备登陆页面
* 2、登陆成功之后,将用户名存储到session中
* 使用的是一个浏览器进行登陆,一直在一次会话中
* 第一次登陆 向session中添加键值对
* 第二次登陆 修改session中的键值对
*
* 3、实现ServletContextListener监听器
* 监听servletContext创建和销毁
* tomcat启动时就会创建
* 4、实现HttpSessionAttributeListener监听器
* 监听session值的变化
* 添加值
* 替换值
* 5、在创建servletContext监听方法中
* 获取ServletContext对象,向其作用域添加键值对
*/
@WebListener
public class OnlineListener implements ServletContextListener,HttpSessionAttributeListener {
private ServletContext sc;
//创建servletContext
@Override
public void contextInitialized(ServletContextEvent sce) {
//获取servletContext
sc = sce.getServletContext();
//在servletContext作用域中添加一个键值对 >
List online = new ArrayList<>();
sc.setAttribute("online",online);
}
//session添加值
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
//获取键值对的key
String name = se.getName();
//说明向session作用域添加的是用户名
if("username".equals(name)) {
//获取value
String value = (String) se.getValue();
//从sc中获取list集合
List online = (List) sc.getAttribute("online");
online.add(value);
// //把online在放到sc作用域存着
// sc.setAttribute("online",online);
}
}
//session替换值
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
//获取键值对的key 替换之后的
String name = se.getName();
if("username".equals(name)) {
//获取替换之后的用户名value
//不能用getValue获取 因为获取的是之前的
String username = (String) se.getSession().getAttribute("username");
List online = (List) sc.getAttribute("online");
online.add(username);
// sc.setAttribute("online",online);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}