zoukankan      html  css  js  c++  java
  • 监听器实现案例----自定义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、实现结果

  • 相关阅读:
    linux 命令——48 watch (转)
    linux 命令——47 iostat (转)
    linux 命令——46 vmstat(转)
    linux 命令——45 free(转)
    linux 命令——44 top (转)
    linux 命令——43 killall(转)
    linux 命令——42 kill (转)
    linux 命令——41 ps(转)
    linux 命令——40 wc (转)
    Java for LeetCode 068 Text Justification
  • 原文地址:https://www.cnblogs.com/feiwenstyle/p/10579135.html
Copyright © 2011-2022 走看看