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");
}
}
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超时)