监听器应用【统计网站人数、自定义session扫描器、踢人小案例】

news/2024/5/20 0:42:51/文章来源:https://blog.csdn.net/Java_3y/article/details/79306293

从第一篇已经讲解过了监听器的基本概念,以及Servlet各种的监听器。这篇博文主要讲解的是监听器的应用。

统计网站在线人数

分析

我们在网站中一般使用Session来标识某用户是否登陆了,如果登陆了,就在Session域中保存相对应的属性。如果没有登陆,那么Session的属性就应该为空。

现在,我们想要统计的是网站的在线人数。我们应该这样做:我们监听是否有新的Session创建了,如果新创建了Sesssion,那么在线人数就应该+1。这个在线人数是整个站点的,所以应该有Context对象保存。

大致思路:

  • 监听Session是否被创建了
  • 如果Session被创建了,那么在Context的域对象的值就应该+1
  • 如果Session从内存中移除了,那么在Context的域对象的值就应该-1.

代码

  • 监听器代码:
    public class CountOnline implements HttpSessionListener {public void sessionCreated(HttpSessionEvent se) {//获取得到Context对象,使用Context域对象保存用户在线的个数ServletContext context = se.getSession().getServletContext();//直接判断Context对象是否存在这个域,如果存在就人数+1,如果不存在,那么就将属性设置到Context域中Integer num = (Integer) context.getAttribute("num");if (num == null) {context.setAttribute("num", 1);} else {num++;context.setAttribute("num", num);}}public void sessionDestroyed(HttpSessionEvent se) {ServletContext context = se.getSession().getServletContext();Integer num = (Integer) se.getSession().getAttribute("num");if (num == null) {context.setAttribute("num", 1);} else {num--;context.setAttribute("num", num);}}}
  • 显示页面代码:

在线人数:${num}

测试

我们每使用一个浏览器访问服务器,都会新创建一个Session。那么网站的在线人数就会+1。

使用同一个页面刷新,还是使用的是那个Sesssion,所以网站的在线人数是不会变的。

这里写图片描述


自定义Session扫描器

我们都知道Session是保存在内存中的,如果Session过多,服务器的压力就会非常大。

但是呢,Session的默认失效时间是30分钟(30分钟没人用才会失效),这造成Seesion可能会过多(没人用也存在内存中,这不是明显浪费吗?)

当然啦,我们可以在web.xml文件中配置Session的生命周期。但是呢,这是由服务器来做的,我嫌它的时间不够准确。(有时候我配置了3分钟,它用4分钟才帮我移除掉Session)

所以,我决定自己用程序手工移除那些长时间没人用的Session。

分析

要想移除长时间没人用的Session,肯定要先拿到全部的Session啦。所以我们使用一个容器来装载站点所有的Session。。

只要Sesssion一创建了,就把Session添加到容器里边。毫无疑问的,我们需要监听Session了。

接着,我们要做的就是隔一段时间就去扫描一下全部Session,如果有Session长时间没使用了,我们就把它从内存中移除。隔一段时间去做某事,这肯定是定时器的任务呀。

定时器应该在服务器一启动的时候,就应该被创建了。因此还需要监听Context

最后,我们还要考虑到并发的问题,如果有人同时访问站点,那么监听Session创建的方法就会被并发访问了定时器扫描容器的时候,可能是获取不到所有的Session的

这需要我们做同步

于是乎,我们已经有大致的思路了

  • 监听Session和Context的创建
  • 使用一个容器来装载Session
  • 定时去扫描Session,如果它长时间没有使用到了,就把该Session从内存中移除。
  • 并发访问的问题

代码

  • 监听器代码:
public class Listener1 implements ServletContextListener,HttpSessionListener {//服务器一启动,就应该创建容器。我们使用的是LinkList(涉及到增删)。容器也应该是线程安全的。List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());//定义一把锁(Session添加到容器和扫描容器这两个操作应该同步起来)private Object lock = 1;public void contextInitialized(ServletContextEvent sce) {Timer timer = new Timer();//执行我想要的任务,0秒延时,每10秒执行一次timer.schedule(new MyTask(list, lock), 0, 10 * 1000);}public void sessionCreated(HttpSessionEvent se) {//只要Session一创建了,就应该添加到容器中synchronized (lock) {list.add(se.getSession());}System.out.println("Session被创建啦");}public void sessionDestroyed(HttpSessionEvent se) {System.out.println("Session被销毁啦。");}public void contextDestroyed(ServletContextEvent sce) {}}
  • 任务代码:
/** 在任务中应该扫描容器,容器在监听器上,只能传递进来了。** 要想得到在监听器上的锁,也只能是传递进来** */class MyTask extends TimerTask {private List<HttpSession> sessions;private Object lock;public MyTask(List<HttpSession> sessions, Object lock) {this.sessions = sessions;this.lock = lock;}@Overridepublic void run() {synchronized (lock) {//遍历容器for (HttpSession session : sessions) {//只要15秒没人使用,我就移除它啦if (System.currentTimeMillis() - session.getLastAccessedTime() > (1000 * 15)) {session.invalidate();sessions.remove(session);}}}}}
  • 测试:

15秒如果Session没有活跃,那么就被删除!

这里写图片描述

  • 使用集合来装载我们所有的Session
  • 使用定时器来扫描session的声明周期【由于定时器没有session,我们传进去就好了】
  • 关于并发访问的问题,我们在扫描和检测session添加的时候,同步起来就好了【当然,定时器的锁也是要外面传递进来的】

踢人小案列

列出所有的在线用户,后台管理者拥有踢人的权利,点击踢人的超链接,该用户就被注销了。

分析

首先,怎么能列出所有的在线用户呢??一般我们在线用户都是用Session来标记的,所有的在线用户就应该用一个容器来装载所有的Session。。

我们监听Session的是否有属性添加(监听Session的属性有添加、修改、删除三个方法。如果监听到Session添加了,那么这个肯定是个在线用户!)。

装载Session的容器应该是在Context里边的【属于全站点】,并且容器应该使用Map集合【待会还要通过用户的名字来把用户踢了】

思路:

  • 写监听器,监听是否有属性添加在Session里边了
  • 写简单的登陆页面。
  • 列出所有的在线用户
  • 实现踢人功能(也就是摧毁Session)

代码

  • 监听器
public class KickPerson implements HttpSessionAttributeListener {// Public constructor is required by servlet specpublic KickPerson() {}public void attributeAdded(HttpSessionBindingEvent sbe) {//得到context对象,看看context对象是否有容器装载SessionServletContext context = sbe.getSession().getServletContext();//如果没有,就创建一个呗Map map = (Map) context.getAttribute("map");if (map == null) {map = new HashMap();context.setAttribute("map", map);}//---------------------------------------------------------------------------------------//得到Session属性的值Object o = sbe.getValue();//判断属性的内容是否是User对象if (o instanceof User) {User user = (User) o;map.put(user.getUsername(), sbe.getSession());}}public void attributeRemoved(HttpSessionBindingEvent sbe) {/* This method is called when an attributeis removed from a session.*/}public void attributeReplaced(HttpSessionBindingEvent sbe) {/* This method is invoked when an attibuteis replaced in a session.*/}
}
  • 登陆页面

<form action="${pageContext.request.contextPath }/LoginServlet" method="post">用户名:<input type="text" name="username"><input type="submit" value="登陆">
</form>
  • 处理登陆Servlet
//得到传递过来的数据String username = request.getParameter("username");User user = new User();user.setUsername(username);//标记该用户登陆了!request.getSession().setAttribute("user", user);//提供界面,告诉用户登陆是否成功request.setAttribute("message", "恭喜你,登陆成功了!");request.getRequestDispatcher("/message.jsp").forward(request, response);
  • 列出在线用户
<c:forEach items="${map}" var="me">${me.key} <a href="${pageContext.request.contextPath}/KickPersonServlet?username=${me.key}">踢了他吧</a><br>
</c:forEach>
  • 处理踢人的Servlet
String username = request.getParameter("username");//得到装载所有的Session的容器Map map = (Map) this.getServletContext().getAttribute("map");//通过名字得到SessionHttpSession httpSession = (HttpSession) map.get(username);httpSession.invalidate();map.remove(username);//摧毁完Session后,返回列出在线用户页面request.getRequestDispatcher("/listUser.jsp").forward(request, response);

测试

使用多个浏览器登陆来模拟在线用户(同一个浏览器使用的都是同一个Session)

这里写图片描述


监听Seesion的创建和监听Session属性的变化有啥区别???

  • Session的创建只代表着浏览器给服务器发送了请求。会话建立
  • Session属性的变化就不一样了,登记的是具体用户是否做了某事(登陆、购买了某商品)

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_725930.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈CDN、SEO、XSS、CSRF

CDN 什么是CDN 初学Web开发的时候&#xff0c;多多少少都会听过这个名词->CDN。 CDN在我没接触之前&#xff0c;它给我的印象是用来优化网络请求的&#xff0c;我第一次用到CDN的时候是在找JS文件时。当时找不到相对应的JS文件下载地址(之前一般我都是把JS下载下来&#…

国内那些的求职网站

阅读文本大概需要6分钟。金三银四&#xff0c;也许你需要CSDN JOBCSDN JOB是中国最专业的IT技术人才招聘平台&#xff0c;为IT工程师及IT企业提供更加全面更加专业的职业服务&#xff0c;号称最懂程序员的社区招聘。官网&#xff1a;https://job.csdn.net/领英LinkedIn&#xf…

系统网站架构(淘宝、京东) 架构师能力

来一张看上去是淘宝的架构的图&#xff1a; 参考地址&#xff1a;http://hellojava.info/?p520 说几点我认可的地方&#xff1a; 架构需要掌握的点&#xff1a;通信连接方式&#xff1a;大量的连接通常会有两种方式&#xff1a; 1. 大量client连一个server 在现如今NonBlocki…

网站性能优化整理笔记

为什么80%的码农都做不了架构师&#xff1f;>>> 优化网站响应时间方法 1、减少http请求 可以降低网站的响应时间和减少传输的数据&#xff0c;主要方法&#xff1a; 1&#xff09;将多个图片合并成一个文件&#xff0c;减少图片下载的请求 2&#xff09;合并js脚本…

爬一爬哪个操蛋的药品网站,建立药品库

阅读文本大概需要5分钟。互联网医疗公司&#xff0c;有一个完整、完全、正确的药品库非常重要&#xff1b;今天来说一说小编在上一个东家为了建立一个自己的药品库是怎么做的。首先我们是一家小公司&#xff0c;但是我们有一个纽约敲钟的梦想&#xff0c;虽然就要闹得发不了工资…

从零开始写项目终极【维护网站、修复Bug】

url自动携带jsessionid在我使用浏览器收藏了我写的网站的时候&#xff0c;有的时候会访问不了页面。看了一下原因&#xff0c;是由于url携带了jsessionId&#xff0c;我就奇怪为啥会自动携带jsession了。我分析是由“记住我“功能引起的这个bug&#xff0c;于是我就去查找了一下…

classname帝国怎么用php调用,分享帝国cms怎么调用栏目别名考虑到seo优化

在新模板制作过程中&#xff0c;由于栏目名称比较长&#xff0c;用在标题上没有问题&#xff0c;对seo有利&#xff0c;但是在页面上不希望这么长&#xff0c;简单即可&#xff0c;提过提供了栏目别名&#xff0c;如果能调用就方便了&#xff0c;请留意下面的修改方法修改后栏目…

监听器应用【统计网站人数、自定义session扫描器、踢人小案例】(修订版)

前言只有光头才能变强。文本已收录至我的GitHub仓库&#xff0c;欢迎Star&#xff1a;https://github.com/ZhongFuCheng3y/3y从第一篇已经讲解过了监听器的基本概念&#xff0c;以及Servlet各种的监听器。这篇博文主要讲解的是监听器的应用。统计网站在线人数ps:这个可以使用We…

大型分布式网站架构设计与实践

阅读文本大概需要3分钟。SOA和RPC随着互联网规模发展&#xff0c;面向服务的体系架构(SOA)成为主流的架构方式&#xff0c;SOA的本质思想是高内聚、低耦合地实现分治&#xff0c;各个系统之间通过服务的方式进行交互&#xff0c;这样保证了交互的标准性&#xff0c;这对于一个复…

为什么有些网站域名不以www开头?什么是二级域名?

本文公众号来源&#xff1a;漫话编程 作者&#xff1a;漫话编程我在初学的时候不清楚啥叫顶级域名&#xff0c;啥是二级域名以及为啥我们输入网站地址的时候可以省略www&#xff01;这篇文章通俗易懂地告诉你&#xff01;38女神节那一天&#xff0c;女朋友问我淘宝网国际站的…

大型网站技术架构剖析

阅读文本大概需要3分钟。大型网站系统特点高并发&#xff0c;大流量高可用海量数据用户分布广泛&#xff0c;网络情况复杂安全环境恶劣需求快速变更&#xff0c;发布频繁渐进式发展大型网站发展演化过程一台服务器特点&#xff1a;没人应用程序、数据库、文件都在一个服务器。应…

[网站优化实战]公共CDN库/Nginx启用Gzip/全站CDN加速

本文公众号来源&#xff1a;Rude3Knife 作者&#xff1a;蛮三刀把刀网站加载优化的过程&#xff08;主要针对静态资源&#xff09;&#xff0c;思路可以借鉴一下&#xff01;前言接触到CDN的起因&#xff1a;我自己搭建的网站https://price.monitor4all.cn/网页打开的速度一直…

《大型网站系统与Java中间件》读书笔记(上)

前言 只有光头才能变强。 文本已收录至我的GitHub仓库&#xff0c;欢迎Star&#xff1a;https://github.com/ZhongFuCheng3y/3y 这本书买了一段时间了&#xff0c;之前在杭州没带过去&#xff0c;现在读完第三章&#xff0c;来做做笔记 这本书前三章都在科普和回顾中间件/分布式…

《大型网站系统与Java中间件》读书笔记 (二)

前言只有光头才能变强。文本已收录至我的GitHub仓库&#xff0c;欢迎Star&#xff1a;https://github.com/ZhongFuCheng3y/3y回顾上一篇&#xff1a;《大型网站系统与Java中间件》读书笔记&#xff08;一&#xff09;这周周末读了第四章&#xff0c;现在过来做做笔记&#xff0…

《大型网站系统与Java中间件》读书笔记 (中)

前言 只有光头才能变强。 文本已收录至我的GitHub仓库&#xff0c;欢迎Star&#xff1a;https://github.com/ZhongFuCheng3y/3y 回顾上一篇&#xff1a; 《大型网站系统与Java中间件》读书笔记&#xff08;一&#xff09; 这周周末读了第四章&#xff0c;现在过来做做笔记&am…

几个简单步骤可以提高网站浏览体验

摘要&#xff1a; STEP 1确定网站定位 你的网站定位是要以企业形象官网为主&#xff0c;或是以单纯贩售商品的购物网站&#xff0c;还是要跟使用者做互动活动的网站&#xff1f; 每个网站的目的都不尽相同&#xff0c;形象官网&#xff0c;可能需要着重于品牌理念、品牌故事、…

一次面试引发的思考(中小型网站优化思考)

前言 故事的起因是这样的&#xff0c;由于本人地处偏僻工作地点在美丽的冰城哈尔滨虽然地方很美丽&#xff0c;但是这里的软件行业实在是算不上“美丽”&#xff0c;这么多年由于个人原因或者公司原因经常换工作&#xff0c;因为这里都是中小型公司&#xff0c;没有什么大公司。…

我采访了同事,让他掏出了每天都会浏览的干货网站...这几个网站也太牛了吧!

前言 在周六的晚上&#xff0c;我日常去到公司写文章。想写一篇程序员常浏览的网站&#xff0c;刚好同事在我后面看我在干什么。于是我就对他进行了采访&#xff0c;问了一下他常去的网站有哪些。 这次我采访的是鸡蛋&#xff0c;他跟我一样大&#xff0c;但是技术比我优秀实在…

Django项目实践4 - Django网站管理(后台管理员)

http://blog.csdn.net/pipisorry/article/details/45079751 上篇&#xff1a;Django项目实践3 - Django模型 Introduction 对于某一类站点&#xff0c; 管理界面 是基础设施中很重要的一部分。这是以网页和有限的可信任管理者为基础的界面&#xff0c;它能够让你加入&#xff0…

亿级流量网站构架核心技术

高并发原则无状态拆分系统维度&#xff1a;根据系统功能/业务进行拆分功能维度&#xff1a;对一个系统进行功能再拆分读写维度&#xff1a;根据读写比例进行拆分AOP维度&#xff1a;根据访问特征模块维度&#xff1a;比如按照基础或代码维护特征进行拆分服务化&#xff1a;进程…