Listener实现单态登陆

MyEclipse中新建Web Project项目,完整目录如下:

需要的jar包为commons-logging-xxx.jar

1、singleton.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
   <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
   <jsp:directive.page import="com.wang.singleton.PersonInfo"/>
   <%
    String action = request.getParameter("action");
    String account = request.getParameter("account");
    if("login".equals(action) && account.trim().length()>0){
        PersonInfo personInfo = new PersonInfo();
        personInfo.setAccount(account);
        personInfo.setIp(request.getRemoteAddr());
        personInfo.setLoginDate(new java.util.Date());  

        session.setAttribute("personInfo",personInfo);  

        response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
        return;
    }
    else if("logout".equals(action)){
        session.removeAttribute("personInfo");
        response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
        return;
    }  

   %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  

<title>Insert title here</title>
</head>
<body>  

    <c:choose>
        <c:when test="${ personInfo != null}">
            欢迎您,${personInfo.account}<br/>
            您的登录ip为,${personInfo.ip}<br>
            登录时将为,<fmt:formatDate value="${personInfo.loginDate}" pattern="yyyy-MM-dd HH:mm"/><br/>
            <a href="${pageContext.request.requestURI}?action=logout">退出</a>
    <!-- 每五秒钟刷新一次页面 -->
        <script>setTimeout("location=location;", 5000);</script>
        </c:when>
        <c:otherwise>
            ${msg}
            <c:remove var="msg" scope="session"/>
            <form action="${pageContext.request.requestURI}?action=login" method="post">
                账号:<input name="account">
                <input type="submit" value="登录">
            </form>  

        </c:otherwise>
    </c:choose>
</body>
</html>

2、PersonInfo.java

package com.wang.singleton;  

import java.io.Serializable;
import java.util.Date;  

public class PersonInfo implements Serializable{
    private static final long serialVersionUID = 1L;
    private String account;
    private String ip;
    private Date loginDate;  

    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public Date getLoginDate() {
        return loginDate;
    }
    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof PersonInfo)){
            return false;
        }
        return account.equalsIgnoreCase(((PersonInfo) obj).getAccount());
    }
}  

3、LoginSessionListener.java

package com.wang.singleton;  

import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;  

public class LoginSessionListener implements HttpSessionAttributeListener {  

   Log log= LogFactory.getLog(this.getClass());  

   Map<String,HttpSession> map = new HashMap<String,HttpSession>();
    public LoginSessionListener() {
        // TODO Auto-generated constructor stub
    }  

    public void attributeRemoved(HttpSessionBindingEvent event)  {
         // 删除属性前被调用
        String name  = event.getName();
        if(name.equals("personInfo")){
            PersonInfo personInfo = (PersonInfo) event.getValue();
            map.remove(personInfo.getAccount());
            log.info("账号"+personInfo.getAccount()+"注销");
        }
    }  

    public void attributeAdded(HttpSessionBindingEvent event)  {
         // 添加session时被调用
        String name = event.getName();
        if(name.equals("personInfo")){
            PersonInfo personInfo = (PersonInfo) event.getValue();
            if(map.get(personInfo.getAccount()) != null){
                HttpSession session = map.get(personInfo.getAccount());  

                PersonInfo oldPersonInfo = (PersonInfo) session.getAttribute("personInfo");
                log.info("账号"+oldPersonInfo.getAccount()+"在"+oldPersonInfo.getIp()+"已经登录,该登录将被迫下线!");
                session.removeAttribute("personInfo");
                session.setAttribute("msg", "您的账号已经在其他机器上登录,您被迫下线!");  

            }
            map.put(personInfo.getAccount(), event.getSession());
            log.info("账号"+personInfo.getAccount()+"在"+personInfo.getIp()+"登录");  

        }
    }  

    public void attributeReplaced(HttpSessionBindingEvent event)  {
         // 修改属性时被调用
        String name = event.getName();
        if(name.equals("personInfo")){
            PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
            //移除旧的登录信息
            map.remove(oldPersonInfo.getAccount());
            //新的登录信息
            PersonInfo personInfo = (PersonInfo) event.getSession().getAttribute("personInfo");
            //也要检查新的账号是否在别的机器上登录
            if(map.get(personInfo.getAccount()) != null){
                HttpSession session = map.get(personInfo.getAccount());  

                session.removeAttribute("personInfo");
                session.setAttribute("msg", "您的账号已经在其他机器上登录,您被迫下线!");  

            }
            map.put(personInfo.getAccount(), event.getSession());
            log.info("账号"+personInfo.getAccount()+"在"+personInfo.getIp()+"登录");  

        }
    }  

}  

实现效果

1、在谷歌浏览器随便输入一串英文

2、显示如下

3、换个IE浏览器,输入相同一串英文,原来登录的就被挤掉了

参考:《javaweb王者归来》

时间: 2024-10-02 20:21:15

Listener实现单态登陆的相关文章

利用session+application+cookie 实现单态登陆,且解决浏览器意外关闭的问题

最近在帮朋友做一个购物网站,里面涉及到了登陆的问题.其中包括后台管理员的登陆和用户的登陆. 在这个网站中,设计了后台管理员单态登陆,即一个账号只能有一个登陆实例.很容易想到的就是用application实现,在application中放置一个hashmap,储存登陆的管理员信息.同时为了实现登陆超时,也在session中存放登陆对象,通过设置session的listener监控session的消亡,移除application中的对象.那么问题来了,如果用户因为断电或者任性,非法关闭了浏览器,再打

第7章 监听器Listener

Listener概述 Listener的使用 使用Listener需要实现相应的Listener接口. public class SessionListenerTest implements HttpSessionListener { public void sessionCreated(HttpSessionEvent se) { HttpSession session = se.getSession(); System.out.println("新创建了一个session: " +

Android开发中MVP模式浅析

目前为止,MVP的使用还没有一个标准,在此先记录一下目前学习到的一些Android中使用MVP的知识. 按传统的方式开发,经常会使Activity中混杂着UI交互,业务逻辑等流程.而MVP模式能巧妙的解决这个问题.先直接上一个小例子吧. /** * 定义一个对UI组件进行操作的接口,让Activity实现这个接口 * @author Quinn * @date 2015-5-9 */ public interface LoginView { public void showProgress();

Struts2+DAO层实现实例03——添加监听器跟踪用户行为

实例说明 根据上两次的成品进行二次加工. 加入Listener,监听用户的登陆注销情况. 所用知识说明 采用SessionBindingListener对Session进行监听. 同时,Action中获取Application,Session,request的方法(在此只列出一种)更多方法 public class LoginAction { private Map request; private Map session; private Map application; public Str

关于一次oracle sqlplus可登陆,但监听起不来的解决。由于listener.log文件超过4G

1.在oracle服务器上cmd 执行 lsnrctl 执行start 过了好久,提示监听程序已经启动. 再执行status 过来好久,才提示命令执行成功. 最好找到原因是因为C:\Oracle\diag\tnslsnr\hwh-PC\listener\trace 目录下的listener.log文件超过4G 导致的. 果断把监听日志停止掉 lsnrctl set log_status off;

web.xml 中的listener、filter、servlet加载及一些配置

在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰. 首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的结论是:listener -> filter -> servlet 同时还存在着这样一种配置节:context-param,它用于向 Servlet

Android 中实现分享和第三方登陆---以新浪微博为例

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38781957 第三方登陆和分享功能在目前大部分APP中都有,分享功能可以将自己觉得有意义的东西分享给身边的朋友,而第三方登陆可以借助已经有巨大用户基础的平台(如QQ和新浪微博)的账号,让用户在使用自己APP的时候不用注册,直接使用第三方账号登陆,从而避免了注册的过程(其实是服务器端帮你注册),这对于吸引更多的用户非常有意义.下面我们就以新浪微博为例,讲解如何实现分享功能和第三方登陆.首先你

(转载)web.xml 中的listener、 filter、servlet 加载顺序及其详解

首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.  但不会因为 filter 写在 listener 的前面而会先加载 filter.  最终得出的结论是:listener -> filter -> servlet 同时还存在着这样一种配置节:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息.我们的 listener, filter 等在初始化时会用到这些上下文中的信息,那么 context-param 配置节是不是

电脑IP改变后oracle em无法登陆的解决办法(亲测)

以下方法为本人亲测 情况:假设电脑初次安装oracle时的ip是192.168.133.110 那么进入em的地址就是http://192.168.133.110:1158/em/console/logon/logon 假设电脑的IP改变为192.168.88.66 那么进入em的地址应该是http://192.168.88.66:1158/em/console/logon/logon 但是测试后,输入上述地址无法进入em,原因是电脑ip改变了,oracle需要修改配置文件才可以访问,一般修改配