zoukankan      html  css  js  c++  java
  • [转]用HttpSessionListener与HttpSessionBindingListener实现在线人数统计

    原文链接:http://www.cnblogs.com/shencheng/archive/2011/01/07/1930227.html

    下午比较闲(其实今天都很闲),想了一下在线人数统计方面的实现,上网找了下这方面的知识,最初我的想法是,管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退出,如:未注销,关闭浏览器等,这个用户的session是管理不到的,最后决定用HttpSessionListener接口或HttpSessionBindingListener接口来实现,通过监听session的新建和销毁来控制,详细如下。

    先添加登陆的页面index.jsp

    <%@ page contentType="text/html;charset=utf-8"%>
    <html>
    <head>
    <title>test</title>             
    </head>
    <body>
    <form action="login.jsp" method="post">
        用户名:<input type="text" name="username" />
        <br />
        <input type="submit" value="登录" />
    </form>
    </body>
    </html>

    点击登陆后跳转的login.jsp(为了方便,用jsp做servlet,同学们用的时候记得改过来)

    <%@ page contentType="text/html;charset=utf-8"%>
    <%@ page import="java.util.*"%>
    <%
        request.setCharacterEncoding("UTF-8");
        // 取得登录的用户名
        String username = request.getParameter("username");
        // 把用户名保存进session
        session.setAttribute("username", username);
        // 把用户名放入在线列表
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        // 第一次使用前,需要初始化
        if (onlineUserList == null) {
            onlineUserList = new ArrayList();
            application.setAttribute("onlineUserList", onlineUserList);
        }
        onlineUserList.add(username);
        // 成功
        response.sendRedirect("result.jsp");
    %>

    登陆成功跳转到显示页面result.jsp

    <%@ page contentType="text/html;charset=utf-8"%>
    <%@ page isELIgnored="false"%>
    <%@page import="java.util.List"%>
    
    <h3>您好:${username} [<a href="logout.jsp">注销</a>]</h3>
    当前在线用户:
    <table>
    <%
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        for (int i = 0; i < onlineUserList.size(); i++) {
        String onlineUsername = (String) onlineUserList.get(i);
    %>
        <tr>
            <td><%=onlineUsername%></td>
        </tr>
    <%
    }
    %>
    </table>

    点击注销页面logout.jsp页面

    <%@ page contentType="text/html;charset=utf-8"%>
    <%@ page import="java.util.*"%>
    <%
        // 取得登录的用户名
        String username = (String) session.getAttribute("username");
        // 销毁session
        session.invalidate();
        // 从在线列表中删除用户名
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        onlineUserList.remove(username);
        // 成功
        response.sendRedirect("index.jsp");
    %>

    OK,登陆、查看、注销页面都有了,下面开始新建监听器

    1、HttpSessionListener

    添加类OnlineUserListener,继承HttpSessionListener,HttpSessionListener中有两个方法sessionCreated(HttpSessionEvent event)与sessionDestroyed(HttpSessionEvent event),前者是监听session的新建,后者是监听session的销毁。

     OnlineUserListener代码如下:

    package com.test;
     
    import java.util.List;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    /**
     * @author 版本
     */
    public class OnlineUserListener implements HttpSessionListener {
     
        public void sessionCreated(HttpSessionEvent event) {
            System.out.println("新建session:"+event.getSession().getId());
        }
        public void sessionDestroyed(HttpSessionEvent event) {
            HttpSession session = event.getSession();
            ServletContext application = session.getServletContext();
            // 取得登录的用户名
            String username = (String) session.getAttribute("username");
            // 从在线列表中删除用户名
            List onlineUserList = (List) application.getAttribute("onlineUserList");
            onlineUserList.remove(username);
            System.out.println(username+"已经退出!");
        }
    }

    web.xml配置:

    <listener>
      <listener-class>com.test.OnlineUserListener</listener-class>
    </listener>

    一旦监听器发现调用了sessionDestoryed方法就会把其用户从在线人数中delete,在下面两种情况下会发生sessionDestoryed事件

    a.执行session.invalidate()方法时

    logout.jsp中调用了 session.invalidate()方法

    b.session会话超时

    session的默认超时事件是30分钟,30分钟后自动销毁session

    2、HttpSessionBindingListener

    HttpSessionBindingListener虽然叫做监听器,但使用方法与HttpSessionListener完全不同。我们实际看一下它是如何使用的。

    新建类OnlineUserBindingListener,实现HttpSessionBindingListener接口,构造方法传入username参数,HttpSessionBindingListener内有两个方法valueBound(HttpSessionBindingEvent event)和valueUnbound(HttpSessionBindingEvent event),前者为数据绑定,后者为取消绑定

    所谓对session进行数据绑定,就是调用session.setAttribute()把HttpSessionBindingListener保存进session中。

    在login.jsp中做这一步:

    <%@page import="com.test.OnlineUserBindingListener"%>
    <%@ page contentType="text/html;charset=utf-8"%>
    <%@ page import="java.util.*"%>
    <%
        request.setCharacterEncoding("UTF-8");
        // 取得登录的用户名
        String username = request.getParameter("username");
           // 把用户名放入在线列表
        session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));
        // 成功
        response.sendRedirect("result.jsp");
    %>

    这就是HttpSessionBindingListener和HttpSessionListener之间的最大区别:HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。HttpSessionBindingListener必须实例化后放入某一个session中,才可以进行监听。

    从监听范围上比较,HttpSessionListener设置一次就可以监听所有session,HttpSessionBindingListener通常都是一对一的。

    正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。

    HttpSessionBindingListener代码如下:

    package com.test;
     
    import java.util.ArrayList;
    import java.util.List;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionBindingEvent;
    import javax.servlet.http.HttpSessionBindingListener;
     
    public class OnlineUserBindingListener implements HttpSessionBindingListener {
        String username;
         
        public OnlineUserBindingListener(String username){
            this.username=username;
        }
        public void valueBound(HttpSessionBindingEvent event) {
            HttpSession session = event.getSession();
            ServletContext application = session.getServletContext();
            // 把用户名放入在线列表
            List onlineUserList = (List) application.getAttribute("onlineUserList");
            // 第一次使用前,需要初始化
            if (onlineUserList == null) {
                onlineUserList = new ArrayList();
                application.setAttribute("onlineUserList", onlineUserList);
            }
            onlineUserList.add(this.username);
        }
     
        public void valueUnbound(HttpSessionBindingEvent event) {
            HttpSession session = event.getSession();
            ServletContext application = session.getServletContext();
     
            // 从在线列表中删除用户名
            List onlineUserList = (List) application.getAttribute("onlineUserList");
            onlineUserList.remove(this.username);
            System.out.println(this.username + "退出。");
     
        }
     
    }

    这里可以直接使用listener的username操作在线列表,不必再去担心session中是否存在username。

    valueUnbound的触发条件是以下三种情况:

    a.执行session.invalidate()时。

    b.session超时,自动销毁时。

    c.执行session.setAttribute("onlineUserListener", "其他对象");或session.removeAttribute("onlineUserListener");将listener从session中删除时。

    因此,只要不将listener从session中删除,就可以监听到session的销毁。

    总结:

    HttpSessionListener 还是不是太好用,当session invalid(还没destroy), 此时未调用sessionDestroyed(), 但此时调用session.getAttribute()就会收获一个IllegalStateException(目前笔者的方法是try catch,但不做任何操作,因为你根本不知道session会在何时invalid),java api并不提供一个sessionInvalid()方法。

      

  • 相关阅读:
    leetcode108 Convert Sorted Array to Binary Search Tree
    leetcode98 Validate Binary Search Tree
    leetcode103 Binary Tree Zigzag Level Order Traversal
    leetcode116 Populating Next Right Pointers in Each Node
    Python全栈之路Day15
    Python全栈之路Day11
    集群监控
    Python全栈之路Day10
    自动部署反向代理、web、nfs
    5.Scss的插值
  • 原文地址:https://www.cnblogs.com/hzm112567/p/3226808.html
Copyright © 2011-2022 走看看