本文共 11397 字,大约阅读时间需要 37 分钟。
一、概述
1.1 事件监听涉及三个组件
事件监听涉及到三个组件:事件源、事件参数对象、事件监听器。
当事件源上发生某一个动作时,它会调用事件监听器的一个方法,并在调用该方法时把事件参数对象传递进去,
开发人员在监听器中通过事件参数对象,就可以拿到事件源,从而对事件源进行操作。其原理就是。
1.2 什么是监听器
监听器用于监听web应用中某些对象(request,session,application)、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计访问人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。
1.3 监听器类型
(1) 声明周期监听器
-
ServletContext上下文监听器,要实现ServletContextListener接口
内部方法
①初始化:contextInitialized ②销毁:contextDestroyed -
Session监听器,要实现HttpSessionListener接口
内部方法
①sessionCreated:监听Session对象的创建 ②sessionDestroyed:监听Session对象的销毁 -
request监听器,要实现ServletRequestListener接口
内部方法
①requestInitialized:监听request对象的初始化 ②requestDestroyed:监听request对象的销毁
(2) 属性变化监听器
-
ServletContext属性变化监听器,实现ServletContextAttributeListener接口
内部的方法:
attributeAdded:监听属性的添加 attributeRemoved:监听属性的移除 attributeReplaced:监听属性的修改 -
session属性变化监听器,实现HttpSessionAttributeListener接口,监听HttpSession的内容的变化
内部方法:
attributeAdded:监听属性的添加 attributeRemoved:监听属性的移除 attributeReplaced:监听属性的修改 -
request属性变化监听器,继承ServletRequestAttributeListener接口,监听属性内容变化
内部方法:
attributeAdded:监听属性的添加 attributeRemoved:监听属性的移除 attributeReplaced:监听属性的修改
(3) 感知型监听器
-
【对象】从session添加或移除,继承HttpSessionBindingListener接口
内部方法:
valueBound:监听对象的绑定 valueUnbound:监听对象的解除绑定 -
对象钝化和活化,继承HttpSessionActivationListener接口
内部方法:
sessionWillPassivate:监听Session内部存储对象的钝化-写入硬盘 sessionDidActivate:监听Session内部存储对象的活化-读取 对应类需要实现序列化接口Serializable
二、监听器的使用
根据需求,遵从对应的接口,实现相应的方法即可。
2.1 两种配置方式
web.xml中进行配置
com.qf.web.listener.RequestLeftListener
注解
Servlet3.0之后新增的,使用注解【@WebListener】进行监听器的注册
2.2 案例
ServletContextListener接口,主要作用域application
@WebListenerpublic class ApplicationListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("初始化程序,提前加载配置文件和jar包"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("程序结束的时候释放资源"); }}
HttpSessionListener接口
监听会话的创建和销毁,可以统计在线人数,因为只有浏览器和服务器建立了连接,才会产生session,相当于在线。
HttpSessionListener部分
@WebListenerpublic class OnlineCountListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { //application作用域是整个app程序,不易销毁,可以用来记录session【作用域大的记录作用域小的】 ServletContext application = se.getSession().getServletContext(); synchronized (this) { Integer count = (Integer) application.getAttribute("count"); if (null == count) { count = 1; } else { count++; } application.setAttribute("count", count); //之后count值会发送到前端页面 } } @Override public void sessionDestroyed(HttpSessionEvent se) { //如果session销毁了,注意不是关闭浏览器,而是超过30分钟没有活跃,或者手动销毁 //销毁了该方法会监听到 ServletContext application = se.getSession().getServletContext(); synchronized (this) { Integer count = (Integer) application.getAttribute("count"); if (count != null && count > 0) { count--; } } }}
前端部分
<%@ page contentType="text/html;charset=UTF-8" language="java" %>当前在线人数 当前在线人数:${ count}
同样的道理,【ServletRequestListener接口】 可以实现访问人数的统计,因为访问就是单纯的发送请求,不需要建立连接
@WebListenerpublic class VisitCountListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { ServletContext application = sre.getServletContext(); synchronized (this) { Integer count = (Integer) application.getAttribute("count"); if (count != null && count > 0) { count--; } } } @Override public void requestInitialized(ServletRequestEvent sre) { ServletContext application = sre.getServletContext(); synchronized (this) { Integer count = (Integer) application.getAttribute("count"); if (count == null) { count = 1; } else { count++; } application.setAttribute("count", count); } }}
三个属性变化监听器
ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener同时遵从,一起实现接口
@WebListenerpublic class AttributeListener implements ServletContextAttributeListener, HttpSessionAttributeListener, ServletRequestAttributeListener { /*上下文的三种属性监听,application*/ @Override public void attributeAdded(ServletContextAttributeEvent scae) { System.out.println("Application监听到添加了" + scae.getName() + ":" + scae.getValue()); } @Override public void attributeRemoved(ServletContextAttributeEvent scae) { System.out.println("Application监听到移除了" + scae.getName() + ":" + scae.getValue()); } @Override public void attributeReplaced(ServletContextAttributeEvent scae) { System.out.println("Application监听到替换了" + scae.getName() + ":" + scae.getValue()); } /*request的三种属性监听*/ @Override public void attributeAdded(ServletRequestAttributeEvent srae) { System.out.println("request监听到添加了" + srae.getName() + ":" + srae.getValue()); } @Override public void attributeRemoved(ServletRequestAttributeEvent srae) { System.out.println("request监听到移除了" + srae.getName() + ":" + srae.getValue()); } @Override public void attributeReplaced(ServletRequestAttributeEvent srae) { System.out.println("request监听到替换了" + srae.getName() + ":" + srae.getValue()); } /*session的三种属性监听,application*/ @Override public void attributeAdded(HttpSessionBindingEvent se) { System.out.println("session监听到添加了" + se.getName() + ":" + se.getValue()); } @Override public void attributeRemoved(HttpSessionBindingEvent se) { System.out.println("session监听到移除了" + se.getName() + ":" + se.getValue()); } @Override public void attributeReplaced(HttpSessionBindingEvent se) { System.out.println("session监听到替换了" + se.getName() + ":" + se.getValue()); }}
servlet部分
@WebServlet(name = "AttrServlet", value = "/attrservlet")public class AttrServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext application = this.getServletContext(); application.setAttribute("appname", "xxx管理系统"); application.setAttribute("appname", "yyy管理系统"); //同一个name设置两次value就是替换 application.removeAttribute("appname"); request.setAttribute("username", "张三"); request.setAttribute("username", "李四"); request.removeAttribute("username"); request.getSession().setAttribute("age", "20"); request.getSession().setAttribute("age", "30"); request.getSession().removeAttribute("age"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }}//打印结果Application监听到添加了appname:xxx管理系统Application监听到替换了appname:xxx管理系统Application监听到移除了appname:yyy管理系统request监听到添加了username:张三request监听到替换了username:张三request监听到移除了username:李四session监听到添加了age:20session监听到替换了age:20session监听到移除了age:30
HttpSessionBindingListener接口
主要用于监听【对象】的绑定到session和解绑,需要【domain实体类】遵从【HttpSessionBindingListener接口】,而不是创建监听,注意:不需要注解了
User类,属性是用户名和密码
public class User implements HttpSessionBindingListener { private String username; private String password; ...构造方法,get,set方法等不展示 //需要实现两个监听方法 @Override public void valueBound(HttpSessionBindingEvent event) { System.out.println("绑定到session" + event.getName() + ":" + event.getValue() + "sessionId" + event.getSession().getId()); } @Override public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("解绑:" + event.getSession().getId()); }}
servlet类,登录和退出类
/*登录*/@WebServlet(name = "LoginServlet", value = "/loginservlet")public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user = new User("damin", "123"); request.getSession().setAttribute("user", user);//对象放进去后,在User类中的绑定监听方法就执行了 System.out.println("用户登录了"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }}/*退出*/@WebServlet(name = "LoginOutServlet",value = "/outservlet")public class LoginOutServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().removeAttribute("user"); System.out.println("用户退出了"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); }}//打印结果绑定到sessionuser:User{ username='damin', password='123'}sessionIdB4B93A07C7D58C42A2871902C36916E7用户登录了解绑:B4B93A07C7D58C42A2871902C36916E7用户退出了
对象钝化和活化,继承HttpSessionActivationListener接口【了解】
同样,需要让【domain实体类】遵从并实现这个接口,此外,还必须遵从序列化接口【Serializable】
User类
public class User implements HttpSessionActivationListener, Serializable { private String username; private String password; ... @Override public void sessionWillPassivate(HttpSessionEvent se) { System.out.println("对象钝化了..."+se.getSession().getId()); } @Override public void sessionDidActivate(HttpSessionEvent se) { System.out.println("对象活化了..."+se.getSession().getId()); }}
在META-INF(在web下新建)中创建【context.xml】
Session管理器【了解】
基本思路就是将所有session放入一个集合,定时查看是否有问题,超过时间就将其失效。
这里是用来【定制器技术Timer】,参考
public class SessionManagerListener implements ServletContextListener, HttpSessionListener { private Listsessions; //设定定时器 private Timer timer; @Override public void contextInitialized(ServletContextEvent sce) { //初始化集合 sessions = Collections.synchronizedList(new LinkedList<>()); timer = new Timer(); //指定任务,每10秒执行一次 timer.schedule(new TimerTask() { @Override public void run() { synchronized (sessions) { //遍历session Iterator iterator = sessions.iterator(); while (iterator.hasNext()) { HttpSession session = iterator.next(); //如果最后访问时间和当前时间相差1分钟,则失效 if (System.currentTimeMillis() - session.getLastAccessedTime() > 60000) { session.invalidate(); System.out.println("删除了session:" + session.getId()); iterator.remove(); } } } } }, 0, 10000); } @Override public void contextDestroyed(ServletContextEvent sce) { timer.cancel(); //当application结束的时候,也取消定时器 } @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("会话创建了..." + se.getSession().getId()); //来一个会话就放到集合中 sessions.add(se.getSession()); } @Override public void sessionDestroyed(HttpSessionEvent se) { }}
javaEE有自己的Session管理机制,基本原理一致
转载地址:https://blog.csdn.net/qq_45337431/article/details/100607874 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!