思考:不可以通过sessionid来统计用户在线人数,因为session的作用域仅仅在一个浏览器上,换一个浏览器就会产生不同的sessionid。所以考虑使用ip地址来统计用户在线人数。
参考博客:
统计在线人数及登录:IPhttps://blog.csdn.net/qq_42352374/article/details/103152521
但是,考虑到一个ip地址可以登录多个用户。即,张三使用该电脑登录,然后李四也使用该电脑登录。那么此时ip地址相同,但是同时在线人数应该为2.所以本人考虑通过统计ip地址和用户名信息,来获取用户在线人数:

Login.jsp

<%--Created by IntelliJ IDEA.User: 杨Date: 2021/3/26Time: 9:52To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title>
</head>
<body>
<%!String uname;
%>
<%
Cookie[] cookies= request.getCookies();
for(Cookie cookie:cookies){if(cookie.getName().equals("uname")){uname=cookie.getValue();
}}%>
<form action="LoginServlet" method="post">用户名:<input type="text" name="uname" value="<%=(uname==null)?"":uname%>"><br>密码:<input type="password" name="upwd"><br><input type="submit" value="登录"><input type="reset" value="重置">
</form>
</body>
</html>

LoginSuccess(main).jsp

<%--Created by IntelliJ IDEA.User: 杨Date: 2021/3/26Time: 9:52To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title>
</head>
<body>
<%!String uname;
%>
<%
Cookie[] cookies= request.getCookies();
for(Cookie cookie:cookies){if(cookie.getName().equals("uname")){uname=cookie.getValue();
}}%>
<form action="LoginServlet" method="post">用户名:<input type="text" name="uname" value="<%=(uname==null)?"":uname%>"><br>密码:<input type="password" name="upwd"><br><input type="submit" value="登录"><input type="reset" value="重置">
</form>
</body>
</html>

dao层中LoginDao.java:

package cn.imu.dao;import cn.imu.entity.User;import java.sql.*;public class LoginDao {private static  final String URL="jdbc:mysql://localhost:3306/user_db";private static final String USERNAME="root";private static final String PWD="yangxinming123";//登录public static int login(User user) {//-1:系统异常,0:用户名或密码有误,1:登录成功int result=-1 ;Connection connection=null;PreparedStatement prepareStatement=null;ResultSet rs=null;try {Class.forName("com.mysql.cj.jdbc.Driver");connection = DriverManager.getConnection(URL, USERNAME, PWD);String sql="select count(*) from user where uname=? and upwd=?";prepareStatement= connection.prepareStatement(sql);prepareStatement.setString(1, user.getName());prepareStatement.setString(2, user.getPwd());rs = prepareStatement.executeQuery();//只有一条数据,不需要用循环,直接用if语句搞定if(rs.next()){result=rs.getInt(1);}if(result>0){return 1;//登录成功}else{return 0;//登录失败(用户名或密码错误)}} catch (ClassNotFoundException e) {e.printStackTrace();return  -1;} catch (SQLException throwables) {throwables.printStackTrace();return -1;}finally {if(rs!=null) {try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(prepareStatement!=null) {try {prepareStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(connection!=null) {try {connection.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}

entity实体中:User.java:

package cn.imu.entity;public class User {private String name;private String pwd;public void setName(String name) {this.name = name;}public void setPwd(String pwd) {this.pwd = pwd;}public String getName() {return name;}public String getPwd() {return pwd;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}public User(String name, String pwd) {this.name = name;this.pwd = pwd;}
}

UserCount.java

package cn.imu.entity;public class UserCount {private String sessionIdString;private String ipString;private String fistTimeString;private User user;public String getSessionIdString() {return sessionIdString;}public void setSessionIdString(String sessionIdString) {this.sessionIdString = sessionIdString;}public String getIpString() {return ipString;}public void setIpString(String ipString) {this.ipString = ipString;}public String getFistTimeString() {return fistTimeString;}public void setFistTimeString(String fistTimeString) {this.fistTimeString = fistTimeString;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}
}

filter过滤器中,对未进行登录的用户,进行过滤,使之无法访问LoginSuccess(main).jsp主页。LoginFilter:

package cn.imu.filter;import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;@WebFilter(filterName = "LoginFilter",
servletNames = {"LoginServlet"},urlPatterns ="/*",initParams ={@WebInitParam(name = "logonStrings",value = "Login.jsp;index.jsp",description = "对登录页面不进行过滤"),@WebInitParam(name = "includeStrings",value = ".java;.jsp",description = "只对指定过滤参数后缀进行过滤"),@WebInitParam(name = "redirectPath",value = "/Login.jsp",description = "未通过跳转到登录界面"),@WebInitParam(name = "disabletestfilter",value = "N",description = "Y:过滤无效")} )
public class LoginFilter implements Filter {/*判断用户是否登录,未登录则退出系统*/public FilterConfig config;/*
FilterConfig 接口
1、与普通的 Servlet 程序一样,Filter 程序也很可能需要访问 Servlet 容器。Servlet 规范将代表 ServletContext 对象和 Filter 的配置参数信息都封装到一个称为 FilterConfig 的对象中。
2、FilterConfig 接口则用于定义 FilterConfig 对象应该对外提供的方法,以便在 Filter 程序中可以调用这些方法来获取 ServletContext 对象,以及获取在 web.xml 文件中为 Filter 设置的友好名称和初始化参数。
3、FilterConfig接口定义的各个方法:
getFilterName 方法,返回 <filter-name> 元素的设置值。
getServletContext 方法,返回 FilterConfig 对象中所包装的 ServletContext 对象的引用。
getInitParameter 方法,用于返回在 web.xml 文件中为 Filter 所设置的某个名称的初始化的参数值。
getInitParameterNames 方法,返回一个 Enumeration 集合对象。*/public void init(FilterConfig config) throws ServletException {this.config=config;}public void destroy() {this.config=null;}public static boolean isContains(String container, String[] regx) {boolean result = false;for (int i = 0; i < regx.length; i++) {if (container.indexOf(regx[i]) != -1) {return true;}}return result;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {HttpServletRequest httpServletRequest=(HttpServletRequest)request;//通过继承HttpServletResponseWrapper ,重写getOutputStream和getWriter方法,可以获取除静态资源之外(.jsp之类的)响应包的内容。HttpServletResponseWrapper wrapper=new HttpServletResponseWrapper((HttpServletResponse) response);String logonStrings=config.getInitParameter("logonStrings");// 登录登陆页面String includeStrings = config.getInitParameter("includeStrings");    // 过滤资源后缀参数String redirectPath = httpServletRequest.getContextPath() + config.getInitParameter("redirectPath");// 没有登陆转向页面String disabletestfilter = config.getInitParameter("disabletestfilter");// 过滤器是否有效if(disabletestfilter.toUpperCase().equals("Y")){ // 过滤无效chain.doFilter(request, response);return;}String[] logonList=logonStrings.split(";");//不进行过滤String[] includeList = includeStrings.split(";");//指定参数后缀过滤//判断请求的URL中是否包含指定后缀if(!this.isContains(httpServletRequest.getRequestURI(),includeList)) {// 只对指定过滤参数后缀进行过滤System.out.println("请求URI:"+httpServletRequest.getRequestURI());chain.doFilter(request, response);System.out.println("响应URI:"+httpServletRequest.getRequestURI());return;}if (this.isContains(httpServletRequest.getRequestURI(), logonList)) {// 对登录页面不进行过滤System.out.println("登录请求:"+httpServletRequest.getRequestURI());chain.doFilter(request, response);System.out.println("登录响应:"+httpServletRequest.getRequestURI());return;}String name=(String) httpServletRequest.getSession().getAttribute("uname");//判断用户是否登录if(name==null){wrapper.sendRedirect(redirectPath);//重定向,如果用户未登录,则跳到登录页面}else{chain.doFilter(request, response);return;}}
}

listener中,通过用户名和ip地址统计在线用户人数。OnLinePersonListener.java:

package cn.imu.listener;import cn.imu.entity.User;
import cn.imu.entity.UserCount;
import cn.imu.util.SessionUtil;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.net.http.HttpRequest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*
通过获取session中对于的IP,使用listener统计在线人数,存放在ServletContext中*/
@WebListener
public class OnLinePersonListener implements ServletRequestListener,ServletContextListener, HttpSessionListener,HttpSessionAttributeListener {//用List来存储sessionid,ip以及fistTimeprivate static List<UserCount> userCountList=new ArrayList<>();HttpServletRequest request;//number进行数量统计private int number;public OnLinePersonListener() {}@Overridepublic void requestInitialized(ServletRequestEvent sre) {request=(HttpServletRequest) sre.getServletRequest();//获取request//Cookie[] cookies=request.getCookies();}@Overridepublic void contextInitialized(ServletContextEvent sce) {/* This method is called when the servlet context is initialized(when the Web application is deployed). */}@Overridepublic void contextDestroyed(ServletContextEvent sce) {/* This method is called when the servlet Context is undeployed or Application Server shuts down. */}/*** 当有人访问时,就会有一个session被创建,监听到session创建,number就+1*/@Overridepublic void sessionCreated(HttpSessionEvent se) {/* Session is created. */}/*    //获取在线人数public static int getOline(){return userCountList.size();}*/@Overridepublic void sessionDestroyed(HttpSessionEvent se) {/* Session is destroyed. */number--;se.getSession().getServletContext().setAttribute("number",number);//list是存储在域对象ServletContext中,用于记录用户的的日志信息List<UserCount> list=(ArrayList<UserCount>) se.getSession().getServletContext().getAttribute("userList");//根据sessionid删除将要退出的用户信息SessionUtil.removeBySessionId(list,se.getSession().getId());se.getSession().getServletContext().setAttribute("userList",list);}@Overridepublic void attributeAdded(HttpSessionBindingEvent se) {System.out.println("添加user到session中:"+this);//如果在servlectcontext域对象中没有 userCountList,则创建userCountList=(List<UserCount>)se.getSession().getServletContext().getAttribute("userList");if(userCountList==null){userCountList=new ArrayList<>();}number++;//当session 创建的时候,监听统计在线人数 并且获取当前session的ipHttpSession session=se.getSession();User user=(User)se.getSession().getAttribute("user");System.out.println(user);String fisrtTimeString=new SimpleDateFormat("yyyy-MM--dd HH:mm:ss").format(new Date());String ip=request.getRemoteAddr();//获取客户端ipString sid=session.getId();//获取sessionIdif(SessionUtil.getUserConutBySessionId(userCountList,sid)==null){//通过sessionId,查找用户//该用户不存在,新增用户UserCount userCount=new UserCount();if(SessionUtil.IsExist(userCountList,ip,user)){//判断ip和用户是否已经存在//该ip和user均不存在,则新增ip和useruserCount.setSessionIdString(sid);userCount.setUser(user);userCount.setIpString(ip);userCount.setFistTimeString(fisrtTimeString);userCountList.add(userCount);session.getServletContext().setAttribute("userList",userCountList);//在线用户的数量存储到域对象ServletContext的number中session.getServletContext().setAttribute("number",number);}}}@Overridepublic void attributeRemoved(HttpSessionBindingEvent se) {System.out.println("从session中移除user:"+this);}
}

servlet容器中,LoginServlet负责登录成功后进行逻辑判断。LoginOutServlet负责退出登录后进行逻辑判断。
LoginServlet.java:

package cn.imu.servlet;import cn.imu.dao.LoginDao;
import cn.imu.entity.User;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;@WebServlet(name = "LoginServlet", urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {///控制器层:接受view请求,并分发给Model进行处理@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//处理登录request.setCharacterEncoding("utf-8");String name=request.getParameter("uname");String pwd=request.getParameter("upwd");User user=new User(name,pwd);response.setCharacterEncoding("utf-8");//响应编码response.setContentType("text/html;charset=UTF-8");//展示时的编码//将用户名添加到Cookie中Cookie cookie=new Cookie("uname",name);cookie.setMaxAge(360);//秒为单位//调用model层的登录功能int result= LoginDao.login(user);response.addCookie(cookie);request.setAttribute("users",user);if(result>0){//登录成功System.out.println("登录成功!!!!");//登录成功后,将username放入到session中,同时监听session的属性变化request.getSession().setAttribute("user",user);request.getRequestDispatcher("LoginSuccess(main).jsp").forward(request,response);System.out.println("请求转发成功!!!!");//response.sendRedirect("LoginSuccess(main).jsp");}else if(result<0){System.out.println("系统异常!!!");}else{System.out.println("登录失败,用户名或密码错误!!!!");response.sendRedirect("Login.jsp");}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}
}

LoginOutServlet:

package cn.imu.servlet;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;@WebServlet(name = "LoginOutServlet", value = "/LoginOutServlet")
public class LoginOutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//消除sessionHttpSession session=request.getSession();//删除自己放到session中的数据session.removeAttribute("user");session.invalidate();/*  //清除cookie,并退出Cookie[] cookies=request.getCookies();for(Cookie cookie:cookies){cookie.setMaxAge(0);response.addCookie(cookie);}*/System.out.println("访问到LoginOutServlet。。。。");response.sendRedirect("Login.jsp");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}

SessionUtil帮助类:

package cn.imu.util;import cn.imu.entity.User;
import cn.imu.entity.UserCount;import java.util.Iterator;
import java.util.List;public class SessionUtil {/** 根据sessionID查找用户*/public static UserCount getUserConutBySessionId(List<UserCount> list,String id){Iterator<UserCount> iterator=list.iterator();while(iterator.hasNext()){//hasNext():判断是否存在下一个元素//如果存在,则调用next实现迭代UserCount userCount=iterator.next();if(userCount.getSessionIdString().equals(id)){return userCount;}}return null;}/** 根据sessionID删除用户*/public static void removeBySessionId(List<UserCount> list,String id){for(UserCount userCount:list){if(userCount.getSessionIdString().equals(id)){list.remove(userCount);}}}/** 判断ip地址和user是否已经存在* 可以多个user使用一个ip* 但是如果已经存在一组user和ip,则显示已经存在,不能继续添加*/public static boolean IsExist(List<UserCount> list, String ip, User user){Iterator<UserCount> iterator=list.iterator();while(iterator.hasNext()){//hasNext():判断是否存在下一个元素//如果存在,则调用next实现迭代UserCount userCount=iterator.next();if(userCount.getIpString().equals(ip)&&userCount.getUser().getName().equals(user.getName())){return false;}}return true;}
}

运行结果:

https://live.csdn.net/v/158116

[JavaWeb]基于litener的在线人数统计,通过统计ip地址和用户名信息,来获取用户在线人数相关推荐

  1. 统计两个IP地址之间的IP个数

    问题 求两个IP地址之间的IP个数,例如192.18.16.1~192.18.16.5,2001:DB8:0000:0023:0008:0800:200C:417C~2001:DB8:0:23:8:8 ...

  2. 【大数据开发】SparkCore——统计广告topN、基站停留时间topN、ip地址统计练习

    文章目录 材料准备 一.统计广告TopN 1.1统计每⼀个省份点击TOP3的⼴告ID 1.2统计每一个省份每一个小时的TOP3广告ID 二.基站停留时间TopN 三.ip地址统计 材料准备 新建一个o ...

  3. php 本地mysql 代码_基于本地数据库的 IP 地址查询 PHP 源码

    * 纯真 IP 数据库查询 * * 参考资料: * - 纯真 IP 数据库 http://www.cz88.net/ip/ * - PHP 读取纯真IP地址数据库 http://ju.outofmem ...

  4. 【Elasticsearch】基于 Elasticsearch + kibana 实现 IP 地址分布地图可视化

    1.概述 转载:基于 Elasticsearch + kibana 实现 IP 地址分布地图可视化 1.需求 有一批特定用途(文末揭晓)的 IP 地址. 想通过地图形式可视化展示 IP 地址对应的经纬 ...

  5. 基于纯真本地数据库的 IP 地址查询 PHP 源码

    <?php /*** 纯真 IP 数据库查询 * * 参考资料:* - 纯真 IP 数据库 http://www.cz88.net/ip/* - PHP 读取纯真IP地址数据库 http://j ...

  6. linux 代码统计工具,Shell脚本实现的基于SVN的代码提交量统计工具

    最近没啥事,就用bash写了一个基于svn的代码统计小工具. 可以指定统计的目录,默认递归统计子目录. 目前还没有屏蔽指定目录的功能.哈 代码比较粗糙.不过先晒出来. #!/bin/bash - #& ...

  7. 基于 Jenkins + JaCoCo 实现功能测试代码覆盖率统计

    首发于 Jenkins 中文社区 使用 JaCoCo 统计功能测试代码覆盖率? 对于 JaCoCo,有所了解但又不是很熟悉. "有所了解"指的是在 CI 实践中已经使用 JaCoC ...

  8. 基于Flink的电影数据实时统计平台(一):项目展示

    文章目录 一.项目介绍 二.项目演示 2.1 前端观影/电影首页 2.2 前端观影/播放电影 2.3 数据查询/电影筛选 2.4 数据查询/评分细查 2.5 数据查询/可视化数据 三.相关博客 一.项 ...

  9. R 语言 基于关联规则与聚类分析的消费行为统计

    <金融数据挖掘案例分析> 课程设计报告 题 目: 基于关联规则与聚类分析的消费行为统计 学生姓名: 序号: 学生姓名: 序号: 学生姓名: 序号: 学生姓名: 序号: 指导教师: 信息工程 ...

最新文章

  1. LeetCode简单题之数组形式的整数加法
  2. HTML5 模板推荐
  3. iOS开发之使用XMPPFramework实现即时通信(二)
  4. earning Multi-Domain Convolutional Neural Networks for Visual Tracking
  5. LeetCode 21 合并两个有序链表
  6. 95-872-055-源码-CEP-Pattern API
  7. Processing编程学习指南1.5 颜色透明度
  8. libvlc media player in C# (part 1)
  9. “表达式必须包含 bool 类型(或可转换为 bool)”
  10. PowerDesigner 设计数据表(笔记)
  11. 设计模式(9)——模板方法模式
  12. (结构型模式)FlyWeight——享元模式
  13. 《java就业培训教程》读书笔记
  14. 音乐播放微信小程序基于node.js后台
  15. Delphi android 开发视频教程
  16. .md文件简单的转化为pdf文件
  17. 『IT视界』 [原创评论]揪出"程序员"身上的"六宗罪"
  18. 【Linux】FirefoxBrowser 火狐浏览器安装 FlashPlayer 插件
  19. 数据库架构(一) 插入数据库
  20. 事件的互不相容和独立的区别

热门文章

  1. Eclipse安装使用emmet插件
  2. 【JavaScript String对象方法】字符串片段提取:slice()、substring()、substr()
  3. C# 多线程一: Thread 的简单理解与运用
  4. MMS规范翻译(MMS Architecture Overview)
  5. 联通突然从4g变成3g了_联通4G跳到3G无法上网,如何恢复4G上网?
  6. 如何快速减小图片的体积?一招教你在线压缩图片大小
  7. ChatGPT API 正式开放,价格直接打骨折!100万个单词才18元
  8. fanuc机械手臂与基恩士视觉的通讯设定
  9. 澳大利亚黑客技术如何变成人类福音?
  10. 《HTML+CSS+JavaScript》之第18章 图片样式