• 监听器实现案例----自定义session扫描器和统计在线用户人数及用户信息


    一、案例一:自定义Session扫描器
    1、案例说明
    当一个Web应用创建的Session很多时,为了避免Session占用太多的内存,我们可以选择手动将这些内存中的session销毁,那么此时也可以借助监听器技术来实现。对于拿到 每个session 对象, 判断session的最后一次访问时间 与当前时间 的间隔是否超过 5 分钟, 如果超过就手动销毁

    2、实现代码
    SessionScanner:session对象的监听器

    MyTimerTask:定时器timer的任务对象

    SessionScanner监听器,使用servlet3.0新特性,使用注解@WebListener完成注册

    (1)SessionScanner类
    package sessionScanner;

    import java.util.Collections;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Timer;

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;

    /*
    * 自定义session扫描器的实现
    * 手动的 自己去管理 session 对象, 如果某个session,5分钟没有被访问过,那么就销毁
    *
    *
    * 1、监听session对象的修改时间,要设置监听器:HttpSessionListener(session产生和销毁时)
    * 注意:定义一个容器,用来装session对象,在session产生时,添加到容器中;
    * 在session销毁时,从容器中移除;由此进行管理
    * 2、设置一个定时器(timer),每隔5分钟进行检查一次,看看哪些session是超过5分钟没有被访问过,
    * 如果没有,则销毁
    * 3、定时器timer有个任务对象,我们需要自己去创建这个任务对象:遍历检查session中超过5分钟的情况
    * 而这个任务对象(TimerTask)是Runnable接口的实现类,所以只需实现Runnable的接口即可
    * 4、定时器的启动需要进行设置,因此还要设置一个监听器:ServletContextListener;
    * 目的:设置监听器,web应用启动时开始工作,然后每隔5分钟检查一次
    *
    *小结:
    * 1. 增删频繁的时候, 使用 LinkedList 性能好
    * 2. 如何将一个list 变为一个线程安全的list,使用Collections.synchronizedList
    * 3. 定时器的使用 --- Timer 类
    * 4. 遍历list集合的时候, 同时还要从list中去移除 元素, 避免 并发修改的异常(用ListIterator,而不是Iterator)
    * 5. 如何实现两段不同的代码 互斥,锁的使用
    */

    /*
    *
    * (1)实现HttpSessionListener监听器,实现两个方法
    * public void sessionCreated(HttpSessionEvent se) {}
    * public void sessionDestroyed(HttpSessionEvent se) {}
    *
    * (2)实现ServletContextListener监听器,实现两个方法
    * public void contextInitialized(ServletContextEvent sce) {}
    * public void contextDestroyed(ServletContextEvent sce) {}
    */

    //监听器(观察者)
    @WebListener
    public class SessionScanner implements HttpSessionListener,
    ServletContextListener {// 自定义session扫描器的实现

    // 定义一个容器, 将 每次 创建的session 对象放到 容器中去
    // private List<HttpSession> list=new LinkedList<HttpSession>();//线程不安全
    private List<HttpSession> list = Collections
    .synchronizedList(new LinkedList<HttpSession>());// 线程安全

    public Object lock = new Object();// 定义一个锁,用于解决线程安全问题

    // 主要解决:本对象的sessionCreated方法添加session,而MyTimerTask对象中方法销毁对象时,使用的是同一个session容器,
    // 这样,对同一个容器做不同的操作,肯能产生线程安全问题,所以要定义锁:lock,去解决这个线程安全问题

    @Override
    // 事件对象(封装 session事件源 )
    public void sessionCreated(HttpSessionEvent se) {
    System.out.println("执行了,说明新创建了一个session对象。。。");

    HttpSession session = se.getSession();// 获取事件对象
    // 定义锁,解决线程安全问题
    synchronized (lock) {
    list.add(session);// 穿件的session放到容器中去
    }

    // long lastAccessedTime = session.getLastAccessedTime();//最后一次修改时间
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
    System.out.println("执行了,说明销毁了一个session对象。。。");
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {

    System.out.println("contextInitialized..............");
    // 定义一个定时器,并且在web应用启动时开始工作
    Timer timer = new Timer();

    // 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行
    // task:安排的任务
    // delay:举例开始的指定的延时时间
    // period:重复时间

    //立刻 启动 定时器, 每隔 5 分钟 重复 执行
    timer.schedule(new MyTimerTask(list,lock), 0, 1000 * 60 * 5);// 1000毫秒*60*5=5分钟
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    System.out.println("contextDestroyed......");
    }

    }
    (2)MyTimerTask类
    package sessionScanner;

    import java.util.List;
    import java.util.ListIterator;
    import java.util.TimerTask;

    import javax.servlet.http.HttpSession;

    //任务对象
    class MyTimerTask extends TimerTask {

    private List<HttpSession> list;// session容器
    private Object lock;//锁,从SessionScanner中 传递而来

    public MyTimerTask(List<HttpSession> list,Object lock) {
    this.list = list;// 获取session容器
    this.lock=lock;//锁,从SessionScanner中 传递而来
    }

    @Override
    public void run() {
    // 定义锁,解决线程安全问题
    synchronized (lock) {
    // 遍历session容器
    ListIterator<HttpSession> it = list.listIterator();
    while (it.hasNext()) {
    HttpSession session = it.next();
    // 遍历 list , 拿到 每个session 对象, 判断session的最后一次访问时间 与当前时间 的间隔是否超过 5 分钟, 如果超过就手动销毁

    if (session.getLastAccessedTime() - 1000 * 60 * 5 > 0) {
    session.invalidate();// 销毁session
    list.remove(session);// 从session容器中销毁session对象
    }
    }
    }
    }

    }
    二、案例二:统计在线用户人数及用户信息
    1、案例说明
     统计在线用户人数及用户信息

      1、在线用户的数量

      2、在线用户的信息:sessionId,ip地址,上一次访问时间

      做法:

      1、统计用户数量,通过HttpSessionListener完成             并且定义number来存储数量(通过ServletContext设置,获取)

    2、统计用户信息,通过ServletRequestListener完成    

    并且定义List容器来存储所有用户信息(通过ServletContext设置,获取)

      备注:使用时,需要自己打开不同的浏览器,才会有测试效果

    2、实现代码
    User:用户的数据封装对象

    Count:统计在线用户数量

    CountInfo:统计在线用户信息

    Util:工具类,用于判断所有用户中,是否存在当前用户的访问信息

    index.jsp页面:在线用户人数和在线用户信息显示

    (1)User
    package countUser;

    /*
    * 统计在线用户人数及用户信息
    * 1、在线用户的数量
    * 2、在线用户的信息:sessionId,ip地址,上一次访问时间
    *
    * 做法:
    * 1、统计用户数量,通过HttpSessionListener完成 --定义number来存储数量(通过ServletContext设置,获取)
    * 2、统计用户信息,通过ServletRequestListener完成 --定义List容器来存储所有用户信息(通过ServletContext设置,获取)
    *
    * 备注:使用时,需要自己打开不同的浏览器,才会有测试效果
    */
    public class User {

    private String sessionId;
    private String ip;
    private String firstTime;
    public String getSessionId() {
    return sessionId;
    }
    public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
    }
    public String getIp() {
    return ip;
    }
    public void setIp(String ip) {
    this.ip = ip;
    }
    public String getFirstTime() {
    return firstTime;
    }
    public void setFirstTime(String firstTime) {
    this.firstTime = firstTime;
    }

    }
    (2)Count
    package countUser;

    import java.util.ArrayList;

    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;

    //Servlet3.0 新特性
    //1、统计用户数量,通过HttpSessionListener完成 --定义number来存储数量(通过ServletContext设置,获取)

    @WebListener
    public class Count implements HttpSessionListener {

    private int num=0;//统计用户在线人数
    @Override
    public void sessionCreated(HttpSessionEvent se) {

    num++;
    //设置到ServletContext域中
    se.getSession().getServletContext().setAttribute("num",num);
    System.out.println(" add....");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {

    num--;
    //设置到ServletContext域中
    se.getSession().getServletContext().setAttribute("num",num);
    System.out.println(" remove....");

    //注意,此处还要进行设置
    //从session列表中移除session
    ArrayList<User> list=null;
    list=(ArrayList<User>) se.getSession().getServletContext().getAttribute("list");

    if(Util.getByUserId(list, se.getSession().getId())!=null){
    list.remove(Util.getByUserId(list, se.getSession().getId()));
    }
    }

    }
    (3)CountInfo
    package countUser;

    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;

    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    //2、统计用户信息,通过ServletRequestListener完成 --定义List容器来存储所有用户信息(通过ServletContext设置,获取)

    @WebListener
    public class CountImfo implements ServletRequestListener {

    private ArrayList<User> list;//存储访问用户的信息



    @Override
    public void requestInitialized(ServletRequestEvent sre) {
    //获得ServletContext域中的list
    list=(ArrayList<User>) sre.getServletContext().getAttribute("list");

    // if(list.isEmpty())
    if(list==null){
    list=new ArrayList<User>();
    }
    //为了获得session对象,进行强制类型转换
    HttpServletRequest request=(HttpServletRequest)sre.getServletRequest();
    HttpSession session = request.getSession();
    String sessionId = session.getId();//sessionId

    //session的列表中没有当前的sessionId,即:以前的所有访问用户中,没有当前的访问用户,所以把当前的访问用户信息加入
    if(Util.getByUserId(list,sessionId)==null){
    User user=new User();
    user.setSessionId(sessionId);
    user.setIp(request.getRemoteAddr());
    //设置时间
    user.setFirstTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    // user.setFirstTime(System.currentTimeMillis()+"");
    list.add(user);
    }
    // request.getServletContext().setAttribute("list", list);//保存所有用户信息到list中
    sre.getServletContext().setAttribute("list", list);//保存所有用户信息到list中
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {

    }

    }
    (4)Util           
    package countUser;

    import java.util.ArrayList;

    public class Util {

    //用于判断所有用户中,是否存在当前用户的访问信息
    public static Object getByUserId(ArrayList<User> list, String sessionId) {

    // if(!list.isEmpty()){
    for(int i=0;i<list.size();i++){
    User user = list.get(i);
    if(user.getSessionId().equals(sessionId)){
    return user;//所有用户中有,已经存在当前用户的访问信息
    }
    }
    // }
    return null;//所有用户中有,不存在当前用户的访问信息
    }
    }
    (5)index.jsp页面
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    </head>

    <body>
    当前在线用户人数:${num }<br/>
    <!-- 当前用户在线人数: ${num}<br /> -->


    所有访问者的信息列表<br/>
    <c:if test="${ empty list}">
    当前不存在访问者
    </c:if>

    <c:if test="${ not empty list}">
    <c:forEach var="user" items="${list }">
    sessionId:${user.sessionId }  
    ip:${user.ip }  
    firstTime:${user.firstTime }  
    <br/>
    </c:forEach>
    </c:if>


    <!--
    <br/>遍历方式二:<br/>
    <%
    ArrayList<countUser.User> userList = (ArrayList<countUser.User>)request.getServletContext().getAttribute("list");
    if(userList!=null){
    for(int i = 0 ; i < userList.size() ; i++){
    countUser.User user = userList.get(i);
    %>
    IP:<%=user.getIp() %>,FirstTime:<%=user.getFirstTime() %>,SessionId:<%=user.getSessionId() %> <br/>
    <%}} %>


    -->
    </body>
    </html>
    3、实现结果

  • 相关阅读:
    PHP配置文件处理类
    PHP中实现图片上传的类库
    在PHP中实现StringBuilder类
    微软官方及第三方SDK http://msdn.microsoft.com/zhcn/jj923044
    在PHP中模拟asp的response类
    Atitit.并发测试解决方案(2) 获取随机数据库记录 随机抽取数据 随机排序 原理and实现
    atitit. access token是什么??微信平台公众号开发access_token and Web session保持状态机制
    atitit.二进制数据无损转字符串网络传输
    atitit.重装系统需要备份的资料总结 o84..
    atitit.web ui 结构建模工具总结
  • 原文地址:https://www.cnblogs.com/feiwenstyle/p/10579135.html
Copyright © 2020-2023  润新知