当前位置: 首页 > news >正文

6-会话、过滤器、监听器

6-会话、过滤器、监听器

文章目录

  • 6-会话、过滤器、监听器
  • 会话
    • 会话概述
      • 为什么需要会话管理
      • 会话管理实现的手段
    • Cookie
      • 概述
      • 使用
      • 时效设置
      • 路径设置:特定请求才携带cookie
    • Session
      • HttpSession的概述
      • HttpSession的使用
      • HttpSession的使用-getSession()方法原理
      • HttpSession的时效性
    • 三大域对象
      • 概述
      • 图解
      • 域对象的通用API
  • 过滤器
    • 概述
      • 什么是过滤器?
      • 源码及API
    • 使用示例:单过滤器
    • 生命周期
    • 多个过滤器(过滤器链)的使用
    • 注解方式配置过滤器
  • 监听器
    • 概述
      • 什么是监听器?
      • 监听器分类
    • 6个主要监听器-application域监听器
      • ServletContextListener
      • ServletContextAttributeListener
      • 测试用例
    • 6个主要监听器-session域监听器
      • HttpSessionListener
      • HttpSessionAttributeListener
      • 测试用例
    • 6个主要监听器-request域监听器
      • ServletRequestListener
      • ServletRequestAttributeListener
      • 测试用例
    • session域的两个特殊监听器--session绑定监听器
      • HttpSessionBindingListener
      • HttpSessionBindingListener-测试用例
    • session域的两个特殊监听器--钝化活化监听器
      • 什么是钝化、活化?
      • 钝化、活化的配置
      • HttpSessionActivationListener
      • HttpSessionActivationListener-测试用例

会话

会话概述

为什么需要会话管理

因为HTTP是无状态协议

  • 无状态就是不保存状态,即无状态协议(stateless),HTTP协议自身不对请求和响应之间的通信状态进行保存
  • 在HTTP协议这个级别,协议对于发送过的请求或者响应都不做持久化处理

举例:张三去一家饭馆点了几道菜,觉得味道不错,第二天又去了,对老板说,还点上次的那几道菜

  • 无状态: 老板没有记录张三是否来过,更没有记录上次他点了那些菜,张三只能重新再点一遍
  • 有状态: 老板把每次来吃饭的用户都做好记录,查阅一下之前的记录,查到了张三之前的菜单,直接下单

会话管理实现的手段

Cookie + Session配合

  • cookie是在客户端保留少量数据的技术,主要通过响应头向客户端响应一些客户端要保留的信息
  • session是在服务端保留更多数据的技术,主要通过HttpSession对象保存一些和客户端相关的信息
  • cookie和session配合记录请求状态

举例:张三去银行办业务

  • 张三第一次去某个银行办业务,银行会为张三开户(Session,存入在服务端,即银行),并向张三发放一张银行卡(cookie,存储在客户端,即张三身上)
  • 张三后面每次去银行,就可以携带之前的银行卡(cookie),银行根据银行卡找到之前张三的账户(session)

Cookie

概述

cookie是一种客户端会话技术,cookie由服务端产生,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。

  • 服务端创建cookie,将cookie放入响应对象中,Tomcat容器将cookie转化为set-cookie响应头,响应给客户端
  • 客户端在收到cookie的响应头时,在下次请求该服务的资源时,会以cookie请求头的形式携带之前收到的Cookie
  • cookie是一种键值对格式的数据,从tomcat8.5开始可以保存中文,但是不推荐
  • 由于cookie是存储于客户端的数据,比较容易暴露,一般不存储一些敏感或者影响安全的数据

image-20231106112003443

使用

向响应中增加cookie

@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 创建CookieCookie cookie1 =new Cookie("c1""c1_message");Cookie cookie2 =new Cookie("c2""c2_message");// 将cookie放入响应对象resp.addCookie(cookie1);resp.addCookie(cookie2);}
}

image-20231106112225836

从响应中读取cookie

@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {//获取请求中的cookieCookie[] cookies = req.getCookies();//迭代cookies数组if (null != cookies && cookies.length!= 0) {for (Cookie cookie : cookies) {System.out.println(cookie.getName()+":"+cookie.getValue());}}}
}

image-20231106112250837

时效设置

cookie级别

  • 会话级Cookie
    • 服务器端并没有明确指定Cookie的存在时间
    • 在浏览器端,Cookie数据存在于内存中,只要浏览器还开着,Cookie数据就一直都在;浏览器关闭,内存中的Cookie数据就会被释放
  • 持久化Cookie
    • 服务器端明确设置了Cookie的存在时间
    • 在浏览器端,Cookie数据会被保存到硬盘上,Cookie在硬盘上存在的时间根据服务器端限定的时间来管控,不受浏览器关闭的影响
    • 持久化Cookie到达了预设的时间会被释放

默认情况下Cookie的有效期是一次会话范围内,即会话级cookie

设置持久化cookie

@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 创建CookieCookie cookie1 =new Cookie("c1""c1_message");cookie1.setMaxAge(60);Cookie cookie2 =new Cookie("c2""c2_message");// 将cookie放入响应对象resp.addCookie(cookie1);resp.addCookie(cookie2);}
}

路径设置:特定请求才携带cookie

访问互联网资源时不能每次都需要把所有Cookie带上。访问不同的资源时,可以携带不同的cookie

  • 当设置了cookie访问路径后,只有特定路径的请求才会携带该cookie
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 创建CookieCookie cookie1 =new Cookie("c1""c1_message");// 设置cookie的提交路径cookie1.setPath("/web03_war_exploded/servletB");Cookie cookie2 =new Cookie("c2""c2_message");// 将cookie放入响应对象resp.addCookie(cookie1);resp.addCookie(cookie2);}
}

Session

HttpSession的概述

HttpSession是一种保留更多信息在服务端的一种技术,服务器会为每一个客户端开辟一块内存空间,即session对象. 客户端在发送请求时,都可以使用自己的session. 这样服务端就可以通过session来记录某个客户端的状态了

  • 服务端在为客户端创建session时,会同时将session对象的id,即JSESSIONID以cookie的形式放入响应对象
  • 后端创建完session后,客户端会收到一个特殊的cookie,叫做JSESSIONID
  • 客户端下一次请求时携带JSESSIONID,后端收到后,根据JSESSIONID找到对应的session对象
  • 通过该机制,服务端通过session就可以存储一些专门针对某个客户端的信息了
  • session也是域对象(后续详细讲解)

image-20231106113134174

HttpSession的使用

案例:用户提交form表单到ServletA,携带用户名,ServletA获取session 将用户名存到Session,用户再请求其他任意Servlet,获取之间存储的用户

  • 定义表单
<form action="servletA" method="post">用户名:<input type="text" name="username"><input type="submit" value="提交">
</form>
  • 定义ServletA,将用户名存入session
@WebServlet("/servletA")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 获取请求中的参数String username = req.getParameter("username");// 获取session对象HttpSession session = req.getSession();// 获取Session的IDString jSessionId = session.getId();System.out.println(jSessionId);// 判断session是不是新创建的sessionboolean isNew = session.isNew();System.out.println(isNew);// 向session对象中存入数据session.setAttribute("username",username);}
}
  • 响应体中有一个JSESSIONID

image-20231106113526028

  • 定义其他Servlet,从session中读取用户名
@WebServlet("/servletB")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 获取session对象HttpSession session = req.getSession();// 获取Session的IDString jSessionId = session.getId();System.out.println(jSessionId);// 判断session是不是新创建的sessionboolean isNew = session.isNew();System.out.println(isNew);// 从session中取出数据String username = (String)session.getAttribute("username");System.out.println(username);}
}
  • 请求中携带了一个JSESSIONID的cookie

image-20231106113624345

HttpSession的使用-getSession()方法原理

1682477914654

HttpSession的时效性

为什么要设置session的时效?

  • 用户量很大之后,Session对象相应的也要创建很多。如果一味创建不释放,那么服务器端的内存迟早要被耗尽。
  • 客户端关闭行为无法被服务端直接侦测,或者客户端较长时间不操作也经常出现,类似这些的情况,就需要对session的时限进行设置了

默认的session最大闲置时间(两次使用同一个session中的间隔时间) 在tomcat/conf/web.xml配置为30分钟

image-20231106113900024

自己在当前项目的web.xml对最大闲置时间进行重新设定

image-20231106113925514

通过HttpSession的API 对最大闲置时间进行设定

// 设置最大闲置时间
session.setMaxInactiveInterval(60);

直接让session失效

// 直接让session失效
session.invalidate();

三大域对象

概述

一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同

  • web项目中,我们一定要熟练使用的域对象分别是:请求域,会话域,应用域
  • 请求域对象是HttpServletRequest,传递数据的范围是一次请求之内及请求转发
  • 会话域对象是HttpSession,传递数据的范围是一次会话之内,可以跨多个请求
  • 应用域对象是ServletContext,传递数据的范围是本应用之内,可以跨多个会话

生活举例:热水器摆放位置不同,使用的范围就不同

  1. 摆在张三工位下,就只有张三一个人能用
  2. 摆在办公室的公共区,办公室内的所有人都可以用
  3. 摆在楼层的走廊区,该楼层的所有人都可以用

图解

image-20231106144108701

域对象的通用API

API功能
void setAttribute(String name,String value)向域对象中添加/修改数据
Object getAttribute(String name);从域对象中获取数据
removeAttribute(String name);移除域对象中的数据

过滤器

概述

什么是过滤器?

Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中最为实用的技术之一

  • Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口
  • Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFilter方法
    • Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应
  • Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理
  • Filter是GOF中责任链模式的典型案例
  • Filter的常用应用包括但不限于: 登录权限检查,解决网站乱码,过滤敏感字符,日志记录,性能分析… …

工作位置图解

image-20231106150329851

源码及API

package jakarta.servlet;
import java.io.IOException;public interface Filter {default public void init(FilterConfig filterConfig) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOExceptionServletException;default public void destroy() {}
}
API目标
default public void init(FilterConfig filterConfig)初始化方法,由容器调用并传入初始配置信息filterConfig对象
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)过滤方法,核心方法,过滤请求,决定是否放行,响应之前的其他处理等都在该方法中
default public void destroy()销毁方法,容器在回收过滤器对象之前调用的方法

使用示例:单过滤器

请求日志开发

  • 用户请求到达目标资源之前,记录用户的请求资源路径
  • 响应之前记录本次请求目标资源运算的耗时
  • 可以选择将日志记录进入文件,为了方便测试,这里将日志直接在控制台打印

步骤1:定义过滤器类

package com.atguigu.filters;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LoggingFilter  implements Filter {private SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {// 参数父转子// doFilter方法中的请求和响应对象是以父接口的形式声明的,实际传入的实参就是HttpServletRequest和HttpServletResponse子接口级别的// 可以安全强转HttpServletRequest request =(HttpServletRequest)  servletRequest;HttpServletResponse  response =(HttpServletResponse)  servletResponse;// 拼接日志文本String requestURI = request.getRequestURI();String time = dateFormat.format(new Date());String beforeLogging =requestURI+"在"+time+"被请求了";// 打印日志System.out.println(beforeLogging);// 获取系统时间long t1 = System.currentTimeMillis();// 放行请求:没有这一行代码,请求就此终止// 传参request,response:说明没有产生新的请求、响应对象filterChain.doFilter(request,response);// 获取系统时间long t2 = System.currentTimeMillis();// 拼接日志文本String afterLogging =requestURI+"在"+time+"的请求耗时:"+(t2-t1)+"毫秒";// 打印日志System.out.println(afterLogging);}
}

步骤2:定义servlet请求

@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 处理器请求System.out.println("servletA处理请求的方法,耗时10毫秒");// 模拟处理请求耗时try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
@WebServlet(urlPatterns = "/servletB", name = "servletBName")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 处理器请求System.out.println("servletB处理请求的方法,耗时15毫秒");// 模拟处理请求耗时try {Thread.sleep(15);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

步骤3:XML配置过滤器的范围

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0"><!--配置filter,并为filter起别名--><filter><filter-name>loggingFilter</filter-name><filter-class>com.atguigu.filters.LoggingFilter</filter-class></filter><!--为别名对应的filter配置要过滤的目标资源--><filter-mapping><filter-name>loggingFilter</filter-name><!--通过映射路径确定过滤资源--><url-pattern>/servletA</url-pattern><!--通过后缀名确定过滤资源--><url-pattern>*.html</url-pattern><!--通过servlet别名确定过滤资源--><servlet-name>servletBName</servlet-name></filter-mapping>
</web-app>
  • 一个filter-mapping下,servlet-name和url-pattern子标签可以同时存在
    • servlet-name、url-pattern均可以有多个
  • 匹配规则:url-pattern
规则解释
/servletA精确匹配,表示对servletA资源的请求进行过滤
/*表示对所有资源进行过滤
*.html表示对以.html结尾的路径进行过滤
  • 匹配规则:servlet-name,通过servlet别名确定过滤资源

工作图解

image-20231106151456796

生命周期

阶段对应方法执行时机执行次数
创建对象构造器web应用启动时1
初始化方法void init(FilterConfig filterConfig)构造完毕1
过滤请求void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)每次请求多次
销毁default void destroy()web应用关闭时1次
  • 过滤器作为web项目的组件之一,和Servlet的生命周期类似,略有不同,没有servlet的load-on-startup的配置,默认就是系统启动立刻构造

多个过滤器(过滤器链)的使用

概念

一个web项目中,可以同时定义多个过滤器,多个过滤器对同一个资源进行过滤时,工作位置有先后,整体形成一个工作链,称之为过滤器链

  • 过滤器链中的过滤器的顺序由filter-mapping顺序决定
  • 每个过滤器过滤的范围不同,针对同一个资源来说,过滤器链中的过滤器个数可能是不同的
  • 如果某个Filter是使用ServletName进行匹配规则的配置,那么这个Filter执行的优先级要更低

图解

image-20231106152010891

示例

1、servlet资源代码

package com.atguigu.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 java.io.IOException;@WebServlet("/servletC")
public class ServletC extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {System.out.println("servletC service method  invoked");}
}

2、三个过滤器

public class Filter1  implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {System.out.println("filter1 before chain.doFilter code invoked");filterChain.doFilter(servletRequest,servletResponse);System.out.println("filter1 after  chain.doFilter code invoked");}
}
public class Filter2 implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {System.out.println("filter2 before chain.doFilter code invoked");filterChain.doFilter(servletRequest,servletResponse);System.out.println("filter2 after  chain.doFilter code invoked");}
}
public class Filter3 implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {System.out.println("filter3 before chain.doFilter code invoked");filterChain.doFilter(servletRequest,servletResponse);System.out.println("filter3 after  chain.doFilter code invoked");}
}

3、XML配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0"><filter><filter-name>filter1</filter-name><filter-class>com.atguigu.filters.Filter1</filter-class></filter><filter><filter-name>filter2</filter-name><filter-class>com.atguigu.filters.Filter2</filter-class></filter><filter><filter-name>filter3</filter-name><filter-class>com.atguigu.filters.Filter3</filter-class></filter><!--filter-mapping的顺序决定了过滤器的工作顺序--><filter-mapping><filter-name>filter1</filter-name><url-pattern>/servletC</url-pattern></filter-mapping><filter-mapping><filter-name>filter2</filter-name><url-pattern>/servletC</url-pattern></filter-mapping><filter-mapping><filter-name>filter3</filter-name><url-pattern>/servletC</url-pattern></filter-mapping></web-app>

4、图解

image-20231106152434181

注解方式配置过滤器

完整的XML配置

<!--配置filter,并为filter起别名-->
<filter><filter-name>loggingFilter</filter-name><filter-class>com.atguigu.filters.LoggingFilter</filter-class><!--配置filter的初始参数--><init-param><param-name>dateTimePattern</param-name><param-value>yyyy-MM-dd HH:mm:ss</param-value></init-param>
</filter>
<!--为别名对应的filter配置要过滤的目标资源-->
<filter-mapping><filter-name>loggingFilter</filter-name><!--通过映射路径确定过滤资源--><url-pattern>/servletA</url-pattern><!--通过后缀名确定过滤资源--><url-pattern>*.html</url-pattern><!--通过servlet别名确定过滤资源--><servlet-name>servletBName</servlet-name>
</filter-mapping>

注解方式配置

package com.atguigu.filters;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;@WebFilter(filterName = "loggingFilter",initParams = {@WebInitParam(name="dateTimePattern",value="yyyy-MM-dd HH:mm:ss")},urlPatterns = {"/servletA""*.html"},servletNames = {"servletBName"}
)
public class LoggingFilter  implements Filter {private SimpleDateFormat dateFormat ;/*init初始化方法,通过filterConfig获取初始化参数* init方法中,可以用于定义一些其他初始化功能代码* */@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 获取初始参数String dateTimePattern = filterConfig.getInitParameter("dateTimePattern");// 初始化成员变量dateFormat=new SimpleDateFormat(dateTimePattern);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOExceptionServletException {// 参数父转子HttpServletRequest request =(HttpServletRequest)  servletRequest;HttpServletResponse  response =(HttpServletResponse)  servletResponse;// 拼接日志文本String requestURI = request.getRequestURI();String time = dateFormat.format(new Date());String beforeLogging =requestURI+"在"+time+"被请求了";// 打印日志System.out.println(beforeLogging);// 获取系统时间long t1 = System.currentTimeMillis();// 放行请求filterChain.doFilter(request,response);// 获取系统时间long t2 = System.currentTimeMillis();String afterLogging =requestURI+"在"+time+"的请求耗时:"+(t2-t1)+"毫秒";// 打印日志System.out.println(afterLogging);}
}

监听器

概述

什么是监听器?

监听器:专门用于对域对象 对象身上 发生的事件或状态改变进行监听和相应处理的对象

  • 监听器是GOF设计模式中,观察者模式的典型案例

  • 观察者模式: 当被观察的对象发生某些改变时, 观察者自动采取对应的行动的一种设计模式

  • 监听器使用的感受类似JS中的事件,被观察的对象发生某些情况时,自动触发代码的执行

  • 监听器并不监听web项目中的所有组件,仅仅是对三大域对象做相关的事件监听

监听器分类

web中定义八个监听器接口作为监听器的规范,这八个接口按照不同的标准可以形成不同的分类

按照监听的对象分类

监听器分类分类组成
application域监听器ServletContextListener、ServletContextAttributeListener
session域监听器HttpSessionListener、HttpSessionAttributeListener、HttpSessionBindingListener、HttpSessionActivationListener
request域监听器ServletRequestListener、ServletRequestAttributeListener

按照监听的事件分类

监听器分类分类组成
域对象的创建和销毁监听器ServletContextListener、HttpSessionListener、ServletRequestListener
域对象数据增删改事件监听器ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener
其他监听器HttpSessionBindingListener、HttpSessionActivationListener
  • 6个主要监听器:除了HttpSessionAttributeListener、ServletRequestAttributeListener的其他6个监听器
  • 另外两个监听器用的不多,了解即可

6个主要监听器-application域监听器

ServletContextListener

监听ServletContext对象的创建与销毁

方法名作用
contextInitialized(ServletContextEvent sce)ServletContext创建时调用
contextDestroyed(ServletContextEvent sce)ServletContext销毁时调用

ServletContextAttributeListener

监听ServletContext中属性的添加、移除和修改

方法名作用
attributeAdded(ServletContextAttributeEvent scab)向ServletContext中添加属性时调用
attributeRemoved(ServletContextAttributeEvent scab)从ServletContext中移除属性时调用
attributeReplaced(ServletContextAttributeEvent scab)当ServletContext中的属性被修改时调用
  • ServletContextAttributeEvent包含的方法:
方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getServletContext()获取ServletContext对象

测试用例

定义监听器

package com.atguigu.listeners;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebListener;@WebListener
public class ApplicationListener implements ServletContextListenerServletContextAttributeListener {// 监听初始化@Overridepublic void contextInitialized(ServletContextEvent sce) {ServletContext application = sce.getServletContext();System.out.println("application"+application.hashCode()+" initialized");}// 监听销毁@Overridepublic void contextDestroyed(ServletContextEvent sce) {ServletContext application = sce.getServletContext();System.out.println("application"+application.hashCode()+" destroyed");}// 监听数据增加@Overridepublic void attributeAdded(ServletContextAttributeEvent scae) {String name = scae.getName();Object value = scae.getValue();ServletContext application = scae.getServletContext();System.out.println("application"+application.hashCode()+" add:"+name+"="+value);}// 监听数据移除@Overridepublic void attributeRemoved(ServletContextAttributeEvent scae) {String name = scae.getName();Object value = scae.getValue();ServletContext application = scae.getServletContext();System.out.println("application"+application.hashCode()+" remove:"+name+"="+value);}// 监听数据修改@Overridepublic void attributeReplaced(ServletContextAttributeEvent scae) {String name = scae.getName();Object value = scae.getValue();ServletContext application = scae.getServletContext();Object newValue = application.getAttribute(name);System.out.println("application"+application.hashCode()+" change:"+name+"="+value+" to "+newValue);}
}

定义触发监听器的代码

// ServletA用于向application域中放入数据
@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 向application域中放入数据ServletContext application = this.getServletContext();application.setAttribute("k1""v1");application.setAttribute("k2""v2");}
}// ServletB用于向application域中修改和移除数据
@WebServlet(urlPatterns = "/servletB", name = "servletBName")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {ServletContext appliation  = getServletContext();//  修改application域中的数据appliation.setAttribute("k1""value1");//  删除application域中的数据appliation.removeAttribute("k2");}
}

6个主要监听器-session域监听器

HttpSessionListener

监听HttpSession对象的创建与销毁

方法名作用
sessionCreated(HttpSessionEvent hse)HttpSession对象创建时调用
sessionDestroyed(HttpSessionEvent hse)HttpSession对象销毁时调用
  • HttpSessionEvent对象代表从HttpSession对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpSession对象

HttpSessionAttributeListener

监听HttpSession中属性的添加、移除和修改

方法名作用
attributeAdded(HttpSessionBindingEvent se)向HttpSession中添加属性时调用
attributeRemoved(HttpSessionBindingEvent se)从HttpSession中移除属性时调用
attributeReplaced(HttpSessionBindingEvent se)当HttpSession中的属性被修改时调用
  • HttpSessionBindingEvent包含的方法如下:
方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getSession()获取触发事件的HttpSession对象

测试用例

定义监听器

package com.atguigu.listeners;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.*;@WebListener
public class SessionListener implements HttpSessionListenerHttpSessionAttributeListener {// 监听session创建@Overridepublic void sessionCreated(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("session"+session.hashCode()+" created");}// 监听session销毁@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("session"+session.hashCode()+" destroyed");}// 监听数据增加@Overridepublic void attributeAdded(HttpSessionBindingEvent se) {String name = se.getName();Object value = se.getValue();HttpSession session = se.getSession();System.out.println("session"+session.hashCode()+" add:"+name+"="+value);}// 监听数据移除@Overridepublic void attributeRemoved(HttpSessionBindingEvent se) {String name = se.getName();Object value = se.getValue();HttpSession session = se.getSession();System.out.println("session"+session.hashCode()+" remove:"+name+"="+value);}// 监听数据修改@Overridepublic void attributeReplaced(HttpSessionBindingEvent se) {String name = se.getName();Object value = se.getValue();HttpSession session = se.getSession();Object newValue = session.getAttribute(name);System.out.println("session"+session.hashCode()+" change:"+name+"="+value+" to "+newValue);}}

定义触发监听器的代码

// servletA用于创建session并向session中放数据
@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 创建session,并向session中放入数据HttpSession session = req.getSession();session.setAttribute("k1""v1");session.setAttribute("k2""v2");}
}// servletB用于修改删除session中的数据并手动让session不可用
@WebServlet(urlPatterns = "/servletB", name = "servletBName")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {HttpSession session = req.getSession();//  修改session域中的数据session.setAttribute("k1""value1");//  删除session域中的数据session.removeAttribute("k2");// 手动让session不可用session.invalidate();}
}

6个主要监听器-request域监听器

ServletRequestListener

监听ServletRequest对象的创建与销毁

方法名作用
requestInitialized(ServletRequestEvent sre)ServletRequest对象创建时调用
requestDestroyed(ServletRequestEvent sre)ServletRequest对象销毁时调用
  • ServletRequestEvent对象代表从HttpServletRequest对象身上捕获到的事件,通过这个事件对象我们可以获取到触发事件的HttpServletRequest对象。另外还有一个方法可以获取到当前Web应用的ServletContext对象。

ServletRequestAttributeListener

监听ServletRequest中属性的添加、移除和修改

方法名作用
attributeAdded(ServletRequestAttributeEvent srae)向ServletRequest中添加属性时调用
attributeRemoved(ServletRequestAttributeEvent srae)从ServletRequest中移除属性时调用
attributeReplaced(ServletRequestAttributeEvent srae)当ServletRequest中的属性被修改时调用
  • ServletRequestAttributeEvent包含的方法如下:
方法名作用
getName()获取修改或添加的属性名
getValue()获取被修改或添加的属性值
getServletRequest ()获取触发事件的ServletRequest对象

测试用例

定义监听器

package com.atguigu.listeners;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebListener;@WebListener
public class RequestListener implements ServletRequestListenerServletRequestAttributeListener {// 监听初始化@Overridepublic void requestInitialized(ServletRequestEvent sre) {ServletRequest request = sre.getServletRequest();System.out.println("request"+request.hashCode()+" initialized");}// 监听销毁@Overridepublic void requestDestroyed(ServletRequestEvent sre) {ServletRequest request = sre.getServletRequest();System.out.println("request"+request.hashCode()+" destoryed");}// 监听数据增加@Overridepublic void attributeAdded(ServletRequestAttributeEvent srae) {String name = srae.getName();Object value = srae.getValue();ServletRequest request = srae.getServletRequest();System.out.println("request"+request.hashCode()+" add:"+name+"="+value);}//  监听数据移除@Overridepublic void attributeRemoved(ServletRequestAttributeEvent srae) {String name = srae.getName();Object value = srae.getValue();ServletRequest request = srae.getServletRequest();System.out.println("request"+request.hashCode()+" remove:"+name+"="+value);}// 监听数据修改@Overridepublic void attributeReplaced(ServletRequestAttributeEvent srae) {String name = srae.getName();Object value = srae.getValue();ServletRequest request = srae.getServletRequest();Object newValue = request.getAttribute(name);System.out.println("request"+request.hashCode()+" change:"+name+"="+value+" to "+newValue);}
}

定义触发监听器的代码

//  servletA向请求域中放数据
@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {// 向request中增加数据req.setAttribute("k1""v1");req.setAttribute("k2""v2");// 请求转发req.getRequestDispatcher("servletB").forward(req,resp);}
}// servletB修改删除域中的数据
@WebServlet(urlPatterns = "/servletB", name = "servletBName")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {//  修改request域中的数据req.setAttribute("k1""value1");//  删除session域中的数据req.removeAttribute("k2");}
}

session域的两个特殊监听器–session绑定监听器

HttpSessionBindingListener

session绑定监听器,监听当前监听器对象在Session域中的增加与移除

方法名作用
valueBound(HttpSessionBindingEvent event)该类的实例被放到Session域中时调用
valueUnbound(HttpSessionBindingEvent event)该类的实例从Session中移除时调用
  • HttpSessionBindingEvent包含的方法如下:
方法名作用
getName()获取当前事件涉及的属性名
getValue()获取当前事件涉及的属性值
getSession()获取触发事件的HttpSession对象

HttpSessionBindingListener-测试用例

定义监听器

package com.atguigu.listeners;import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;public class MySessionBindingListener  implements HttpSessionBindingListener {// 监听绑定@Overridepublic void valueBound(HttpSessionBindingEvent event) {HttpSession session = event.getSession();String name = event.getName();System.out.println("MySessionBindingListener"+this.hashCode()+" binding into session"+session.hashCode()+" with name "+name);}// 监听解除绑定@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {HttpSession session = event.getSession();String name = event.getName();System.out.println("MySessionBindingListener"+this.hashCode()+" unbond outof session"+session.hashCode()+" with name "+name);}
}

定义触发监听器的代码

@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletExceptionIOException {HttpSession session = req.getSession();// 绑定监听器session.setAttribute("bindingListener"new MySessionBindingListener());// 解除绑定监听器session.removeAttribute("bindingListener");}
}

session域的两个特殊监听器–钝化活化监听器

什么是钝化、活化?

  • session对象在服务端是以对象的形式存储于内存的,session过多,服务器的内存也是吃不消的
  • 而且一旦服务器发生重启,所有的session对象都将被清除,也就意味着session中存储的不同客户端的登录状态丢失
  • 为了分摊内存压力并且为了保证session重启不丢失,我们可以设置将session进行钝化处理
  • 在关闭服务器前或者到达了设定时间时,对session进行序列化到磁盘,这种情况叫做session的钝化
  • 在服务器启动后或者再次获取某个session时,将磁盘上的session进行反序列化到内存,这种情况叫做session的活化

钝化、活化的配置

步骤1:在web目录下,添加 META-INF下创建Context.xml

image-20231106161207795

步骤2:文件中配置钝化

<?xml version="1.0" encoding="UTF-8"?>
<Context><Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"><!--directory:钝化session数据的保存路径--><Store className="org.apache.catalina.session.FileStore" directory="d:\mysession"></Store></Manager>
</Context>

步骤3:钝化,请求servletA,获得session,并存入数据,然后重启服务器

@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();// 添加数据session.setAttribute("k1","v1");}
}

步骤4:活化,请求servletB获取session,获取重启前存入的数据

@WebServlet(urlPatterns = "/servletB", name = "servletBName")
public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();Object v1 = session.getAttribute("k1");System.out.println(v1);}
}

HttpSessionActivationListener

监听某个对象在Session中的序列化与反序列化

方法名作用
sessionWillPassivate(HttpSessionEvent se)该类实例和Session一起钝化到硬盘时调用
sessionDidActivate(HttpSessionEvent se)该类实例和Session一起活化到内存时调用
  • HttpSessionEvent包含的方法如下:
方法名作用
getSession()获取触发事件的HttpSession对象

HttpSessionActivationListener-测试用例

定义监听器

package com.atguigu.listeners;import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionActivationListener;
import jakarta.servlet.http.HttpSessionEvent;import java.io.Serializable;public class ActivationListener  implements HttpSessionActivationListener, Serializable {//  监听钝化@Overridepublic void sessionWillPassivate(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("session with JSESSIONID "+ session.getId()+" will passivate");}//  监听活化@Overridepublic void sessionDidActivate(HttpSessionEvent se) {HttpSession session = se.getSession();System.out.println("session with JSESSIONID "+ session.getId()+" did activate");}
}

定义触发监听器的代码

@WebServlet(urlPatterns = "/servletA",name = "servletAName")
public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();// 添加数据session.setAttribute("k1","v1");// 添加钝化活化监听器session.setAttribute("activationListener",new ActivationListener());}
}

相关文章:

  • ZZ038 物联网应用与服务赛题第D套
  • 目前为止看过最帅气的一篇论文YOLOv3: An Incremental Improvement(2018.4)
  • Cuda cmake支持C++17
  • 学习笔记:利用CANOE Panel和CAPL脚本模拟主节点发送LIN通信指令
  • AI:63-基于Xception模型的服装分类
  • 大数据学习之Spark性能优化
  • USB HID在系统下通信的一些总结
  • IP地址修改方法有哪几种
  • C#学习中关于Visual Studio中ctrl+D快捷键(快速复制当前行)失效的解决办法
  • 基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI 失物招领小程序 设计与实现
  • 富文本编辑器
  • HDFS系统权限详解
  • source activate my_env 和conda activate my_env 有什么区别
  • AI创作系统ChatGPT商业运营系统源码+支持GPT4/支持ai绘画
  • 死锁的原因及解决方法
  • 【刷算法】从上往下打印二叉树
  • AngularJS指令开发(1)——参数详解
  • C++入门教程(10):for 语句
  • emacs初体验
  • JavaScript服务器推送技术之 WebSocket
  • maven工程打包jar以及java jar命令的classpath使用
  • mongodb--安装和初步使用教程
  • nginx 负载服务器优化
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 包装类对象
  • 代理模式
  • 聊聊directory traversal attack
  • 思维导图—你不知道的JavaScript中卷
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 译自由幺半群
  • mysql面试题分组并合并列
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • 正则表达式-基础知识Review
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • # C++之functional库用法整理
  • # 数论-逆元
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (1)SpringCloud 整合Python
  • (16)Reactor的测试——响应式Spring的道法术器
  • (二)fiber的基本认识
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (四)鸿鹄云架构一服务注册中心
  • **PHP二维数组遍历时同时赋值
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • @KafkaListener注解详解(一)| 常用参数详解
  • [20150707]外部表与rowid.txt
  • [52PJ] Java面向对象笔记(转自52 1510988116)
  • [BZOJ 3282] Tree 【LCT】
  • [C++]类和对象(中)
  • [C++]命名空间等——喵喵要吃C嘎嘎