关于同一用户不能同时登录问题的探讨(2/2)

前言

这是一些理论的东西,大概包括httpsession监听的执行时机,以及相对应的attribute监听的机制调用,并写一些相应的实现sample.

正文

监听器概述:

1.Listener是Servlet的监听器

2.可以监听客户端的请求、服务端的操作等。

3.通过监听器,可以自动激发一些操作,如监听在线用户数量,当增加一个HttpSession时,给在线人数加1。

4.编写监听器需要实现相应的接口

5.编写完成后在web.xml文件中配置一下,就可以起作用了

6.可以在不修改现有系统基础上,增加web应用程序生命周期事件的跟踪

常用的监听接口:

1.ServletContextAttributeListener

监听对ServletContext属性的操作,比如增加/删除/修改;

2.ServletContextListener

监听ServletContext,当创建ServletContext时,激发contextInitialized (ServletContextEvent sce)方法;当销毁ServletContext时,激发contextDestroyed (ServletContextEvent sce)方法。

3.HttpSessionListener

监听HttpSession的操作。当创建一个Session时,激发session Created(SessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法(但是,如果用户关闭浏览器的话,不会马上调用sessionDestroyed方法,只有等到session过期才会调用,默认为30分)。

4.HttpSessionAttributeListener

监听HttpSession中的属性的操作。当在Session增加一个属性时,激发attributeAdded (HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved (HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced (HttpSessionBindingEvent se) 方法。

实现sample: 

1. 由Context监听器管理共享数据库连接,生命周期事件的一个实际应用由context监听器管理共享数据库连接。

在web.xml中如下定义监听器:

<listener>
<listener-class>XXX.MyConnectionManager</listener-class>
</listener>

创建监听器的实例,接受事件并自动判断实现监听器接口的类型。要记住的是由于监听器是配置在部署描述符web.xml中,所以不需要改变任何代码就可以添加新的监听器

import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyConnectionManager implements ServletContextListener {

    public void contextInitialized(ServletContextEvent e) {
        Connection con = null;// create connection;
        e.getServletContext().setAttribute("con", con);
    }

    public void contextDestroyed(ServletContextEvent e) {
        Connection con = (Connection) e.getServletContext().getAttribute("con");
        try {
            con.close();
        } catch (SQLException ignored) {
        } // close connection

    }
}

监听器保证每新生成一个servlet context都会有一个可用的数据库连接,并且所有的连接对会在context关闭的时候随之关闭。

2.HttpSessionListener监听

在web.xml中如下定义监听器:

  <listener>
    <listener-class>org.bromon.test.SessionCount</listener-class>
  </listener>

代码:

package org.bromon.test;

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

public class SessionCount implements HttpSessionListener {
    private static int count = 0;

    public void sessionCreated(HttpSessionEvent se) {
        count++;
        System.out.println("session创建:" + new java.util.Date());
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        count--;
        System.out.println("session销毁:" + new java.util.Date());
    }

    public static int getCount() {
        return (count);
    }
}

这里需要注意的是:sessionDestroyed是在session超时或调用session.invalidate就会执行,也就是说当浏览器异常关闭时,session不会马上消失的,而是要等过期或者调用了invalidate方法后才会调用sessionDestoryed方法。

3.HttpSessionAttributeListener监听

设置web.xml文件:

  <listener>
    <listener-class>com.horizon.test.OnlineList</listener-class>
  </listener>

 代码:

package com.horizon.test;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class OnlineList implements HttpSessionAttributeListener {

    private static Map<String, String> map = new HashMap<String, String>();

    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("login");
    }

    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("logout");
    }

    public void attributeReplaced(HttpSessionBindingEvent se) {
    }

    public static Map<String, String> getMap() {
        return (map);
    }
}

4.servlet与ajax:
jsp片段代码:

<script type="text/javascript" src="js/jquery-1.8.0.min.js"></script>
<script type="text/javascript">
    $(function() {
        setInterval(sub, 500);
    });
    function sub() {
        $.ajax({
            type : "post",//请求方式
            url : "SysServlet",//发送请求地址
            data : {//发送给数据库的数据
                method : "out"
            },
            //请求成功后的回调函数有两个参数
            success : function(data, textStatus) {
                $("#resText").append("<br/>" + data);
            },
            error : function(){
                $("#resText").append("<br/>" + "服务器已经断开");
            }
        });
    }
</script>

servlet代码:

package com.horizon.action;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.horizon.test.OnlineList;

public class SysServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public SysServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        HttpSession session = request.getSession();
        String method = request.getParameter("method");
        if ("login".equals(method)) {
            login(request, response);
        } else if ("logout".equals(method)) {
            System.out.println(session.getAttribute("username"));
            logout(request, response);
        } else {
            System.out.println(session.getAttribute("username"));
            session.setMaxInactiveInterval(1);

            System.out.println("start............");

            PrintWriter out = response.getWriter();
            out.write(">>>>>>>>>>>");
            out.flush();
            out.close();
        }
    }

    protected void login(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        String username = request.getParameter("username");
        session.setAttribute("username", username);
        String uname = OnlineList.getMap().get(username);
        if ("name".equals(uname)) {
            response.sendRedirect("error.jsp");
            return;
        }
        OnlineList.getMap().put(username, "name");
        response.sendRedirect("main.jsp");
        session.setMaxInactiveInterval(1);
    }

    protected void logout(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        HttpSession sessions = request.getSession(false);// 防止创建Session
        OnlineList.getMap().remove(sessions.getAttribute("username"));
        sessions.removeAttribute("username");
        response.sendRedirect("index.jsp");
    }

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

 写的就这些了,望各位看官,交流意见......其中理论部分有网上查的东西....

原文地址:https://www.cnblogs.com/tv151579/p/3403113.html