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()>){
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;", );</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王者归来》

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

  1. 第7章 监听器Listener

    Listener概述 Listener的使用 使用Listener需要实现相应的Listener接口. public class SessionListenerTest implements Http ...

  2. web.xml配置解释

    web.xml中配置的加载优先级:首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的 ...

  3. Oracle维护:每天的工作

    Oracle维护:每天的工作 检查数据库状态 确认所有的INSTANCE状态以及listener状态正常,登陆到所有数据库或例程,检测ORACLE后台进程: $ ps –ef|grep ora $ l ...

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

    实例说明 根据上两次的成品进行二次加工. 加入Listener,监听用户的登陆注销情况. 所用知识说明 采用SessionBindingListener对Session进行监听. 同时,Action中 ...

  5. 【WIP】客户端JavaScript 事件处理

    创建: 2017/10/15 完成: 2017/10/15   更新: 2017/11/04 加粗事件的参数 更新: 2017/12/12 增加事件处理时获取事件对象的方法 更新: 2019/05/2 ...

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

    1.在oracle服务器上cmd 执行 lsnrctl 执行start 过了好久,提示监听程序已经启动. 再执行status 过来好久,才提示命令执行成功. 最后找到原因是因为C:\Oracle\di ...

  7. Android通过Http连接MySQL 实现登陆/注册(数据库+服务器+客户端)

    写在最前: 在实际开发中,相信每个项目都会有用户登陆注册功能,这个实现的方法很多,下面是我实现的方法,供大家交流. 新人发帖,万分紧张,怎么样才能装作一副经常发帖的样子不被别人看出来呢-,- ? 好了 ...

  8. RAC 10.2.0.5,客户端登陆间断遭遇ORA-12545

    实验环境: 服务端:OEL 5.7 + Oracle 10.2.0.5 RAC  客户端:Windows 7 + Oracle 11.2.0.1 Client   1.客户端登陆间断遭遇ORA-125 ...

  9. servlet/filter/listener/interceptor区别与联系

    转自:http://www.cnblogs.com/doit8791/p/4209442.html servlet.filter.listener是配置到web.xml中(web.xml 的加载顺序是 ...

随机推荐

  1. 图解MySQL5.5详细安装与配置过程

    MySQL是一个开源的关系型数据库管理系统,原由瑞典MySQL AB公司开发,目前属于Oracle公司旗下.MySQL是目前世界上开源数据库中最受欢迎的产品之一,是应用最为广泛的开源数据库.MySQL ...

  2. XML特殊符号

    在XML中"<" 字符和"&"字符是严格禁止使用的.要使用这几种字符需要使用它们的实体, 下面是五个在XML文档中预定义好的实体:< < ...

  3. 单据UI代码开发

    1.构造UI项目后,打开生成的UI项目代码,在Model文件下,如初始化一些字段的值 2.订单明细行中行号设置.订单基本操作按钮提示UFIDA.U9.Base.BaseBP.Agent.dll(代理) ...

  4. C# java MD5加密方不一致问题

    说来惭愧,做开发几年了,一直在吸取,今天也写写自已关于技术的一点点理解,不正之处,请大家多多指点. 由于之前开发的项目使用的是C#,用户信息使用的C#的MD5加密码方式,而现在需要切换到Java平台下 ...

  5. window.onload和window.onscroll

    之前我的一个页面里写了引入了2个js,一个是包含置顶的侧面客服,一个是定位导航.2个开始都用了window.onload,发现第一个js的定位导航没有显示,被第2个js覆盖了,当我去掉第2个js的wi ...

  6. html中css、div命名规范

    html中css.div命名规范 1.类class的命名规范示例 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column ...

  7. 安装idea开发工具

    1.网上去下载一个安装包,有的是需要注册码的(可以网上搜索注册码) 2.设置快捷键,可以直接选择使用eclipse的快捷键 3.配置maven 4.配置Git 5.配置tomcat

  8. 自己建二维obj

    经常用到啊 在项目流程管理里面用到

  9. Tomcat部署web应用程序

    对Tomcat部署web应用的方式总结,常见的有以下四种: 1.[替换ROOT目录] 最简单的一种方法,webapps目录下面ROOT文件夹的文件为你的文件,然后输入localhost:8080/首页 ...

  10. 《精通C#》第十七章

    进程简单的说就是一个正在运行的程序,包含了运行该程序所需要的一切资源以及内存分配.线程是进程的基本执行单元,在进程的入口点(类似main())创建的第一个线程称之为主线程.只有一个主线程的进程是线程安 ...