`

简单实现用户单例登录需求

    博客分类:
  • J2EE
阅读更多

    最近一直忙于系统测试,应客户的需求,要求在现有系统中增加一个控制同一用户不能重复登录的功能。

    经过思考,打算在Servlet容器初始化时实例化一个私有静态成员ConcurrentMap变量,用来记录已登录用户的用户名(唯一标识)和用户的sessionId,若用户用相同用户名在同一机器登录或者其他机器登录时,判断此ConcurrentMap中是否已存在相同的用户名来阻止用户重复登录,而实现用户单例登录。


     由于系统测试基本完成,而客户要求必须加入单例登录控制,那么,出于最小改动的前提下,我决定自定义一个Listener,通过实现HttpSessionAttributeListener、HttpSessionListener、ServletContextListener来满足我的需求;


     在我的Listener中定义private static ConcurrentMap<String, String> onlineUsers成员变量, 用来记录已登录用户的用户名(唯一标识)和用户的sessionId;并通过实现ServletContextListener接口的public void contextInitialized(ServletContextEvent event) 和 public void contextDestroyed(ServletContextEvent event)方法来满足我对onlineUsers成员变量的初始化和销毁;


    同时,通过实现HttpSessionAttributeListener的public void attributeAdded(HttpSessionBindingEvent event) 和 public void attributeRemoved(HttpSessionBindingEvent event) 的方法,来满足用户成功登录或退出系统,在后台保存或删除用户登录信息的时候,来记录或移除用户登录的用户名和sessionId;


    此外,在用户登录后超过web.xml设置的session有效期后(默认20分钟)后,系统在session销毁时应自动移除ConcurrentMap中记录的用户登录标识,这里的可通过实现HttpSessionListener接口中的public void sessionDestroyed(HttpSessionEvent event)方法可以做到。


    以上只是我们用来记录用户已登录标识的实现,我们还需要提供一个方法来判断用户是否已经登录系统,在用户登录验证的时候去调用。


    以下是代码,实现比较简单,不完善。并不完善,如果有错误请指出,我虚心请教;

   

public class MultiLoginListener implements HttpSessionAttributeListener,
		HttpSessionListener, ServletContextListener {
	
	private static ConcurrentMap<String, String> onlineUsers = null;

	public void contextInitialized(ServletContextEvent event) {
		onlineUsers = new ConcurrentHashMap<String, String>();
	}
	
	public void contextDestroyed(ServletContextEvent event) {
		onlineUsers = null;
	}
	
	public void sessionCreated(HttpSessionEvent event) {
		
	}

	public void sessionDestroyed(HttpSessionEvent event) {
		HttpSession session = event.getSession();
		if (session != null) {
			GuiYuan guiYuan = (GuiYuan)session.getAttribute("guiYuan");
			if (guiYuan != null) {
				String guiyuanhao = guiYuan.getGuiyuanhao();
				if (onlineUsers.containsKey(guiyuanhao)) {
					onlineUsers.remove(guiyuanhao);
				}
			}
		}
	}

	public void attributeAdded(HttpSessionBindingEvent event) {
		String name = event.getName();
		Object value = event.getValue();
		if (name != null && value != null) {
			if (name.equals("guiYuan") && (value instanceof GuiYuan)) {
				String guiyuanhao = ((GuiYuan)value).getGuiyuanhao();
				if (!onlineUsers.containsKey(guiyuanhao)) {
					String sessionId = event.getSession().getId();
					onlineUsers.put(guiyuanhao, sessionId);
				}
			}
		}
	}
	
	public void attributeRemoved(HttpSessionBindingEvent event) {
		String name = event.getName();
		Object value = event.getValue();
		if (name != null && value != null) {
			if (name.equals("guiYuan") && (value instanceof GuiYuan)) {
				String guiyuanhao = ((GuiYuan)value).getGuiyuanhao();
				if (onlineUsers.containsKey(guiyuanhao)) {
					onlineUsers.remove(guiyuanhao);
				}
			}
		}

	}

	public void attributeReplaced(HttpSessionBindingEvent arg0) {
		
	}
	
	/**
	 * <h3>检测重复登录</h3>
	 * @param guiyuanhao 登录柜员号
	 * @return true:重复; false:不重复
	 */
	public static boolean checkIsMultiLogin (String guiyuanhao) {
		if (onlineUsers != null && onlineUsers.containsKey(guiyuanhao)) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * <h3>重置单例登录</h3>
	 * @param guiyuanhao 柜员号
	 */
	public static void resetSingleLogin (String guiyuanhao) {
		if (onlineUsers != null && onlineUsers.containsKey(guiyuanhao)) {
			onlineUsers.remove(guiyuanhao);
		}
	}
}

 

   除此之外,由于用户时常会点击IE浏览器的关闭按钮来直接退出系统,这样会锁死用户登录,对此我增加了JS对浏览器关闭事件的处理,并且在管理员模块加了紧急情况管理员解锁的功能;以下是浏览器关闭事件的处理:

 

// 单击浏览器关闭按钮,提交至logoff.html清除session(除去登录页面,其他所有页面都响应)
window.onbeforeunload = function(){
	var n = window.event.screenX - window.screenLeft;    
    var b = n > document.documentElement.scrollWidth-20;
    if(b && window.event.clientY < 0 || window.event.altKey)    
    {    
           //alert("关闭而非刷新");
           window.location.href = 'logoff.html';
    }    
}

 用户关闭浏览器时,调用后台"logoff.html"来remove掉session,此时之前实现的attributeRemoved(HttpSessionBindingEvent event)会监听到,并实现移除ConcurrentMap记录的用户登录标识;


  如有错误,请大家多多指教。

 

 

分享到:
评论
2 楼 code_xiaoke 2016-06-17  
那我们在user表中 定义一个stauts状态,表示此用户是否登录。在没有提出的前提下  stauts的值是1.只有正常退出,才回去dao层把用户的stauts状态值给改变。
1 楼 code_xiaoke 2016-06-17  
我本来还想说 从dao层查出一个user实体。然后把数据赋值给这个单例类的user.发现好像不怎么好做

相关推荐

    SwiftKeychainWrapper:一个简单的iOS钥匙串包装器,可让您以类似于“用户默认设置”的方式使用它。 写在斯威夫特

    SwiftKeychainWrapper iOS / tvOS钥匙串的简单包装,可让您以类似于“用户默认值”的方式使用它。 用Swift编写。 提供设置为可满足大多数需求的单例实例。 使用KeychainWrapper.standard访问单例实例。 如果您需要...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    Django实现用户登录与前端交互 Django路由介绍 Django知识点整理 作业 第19周 今日内容概要 上课内容概要 今日Django工程的创建 Django获取多个数据以及文件上传 Django的CBV和FBV Django模板语言循环字典 Django...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    综上所述,“认我测”在线认证检测系统,率先填补了认证检测领域移动端的空缺,提供了Web浏览器+移动端的双端访问模式,给用户提供了多种访问途径,真正实现了用户和检测机构的随时随地在线下单检测。 关键词:...

    php网络开发完全手册

    5.7.2 单例模式(Singleton Pattern) 81 5.7.3 工厂模式(Factory Pattern) 83 5.8 接口与抽象类 86 5.8.1 接口的定义 86 5.8.2 单一接口的实现 87 5.8.3 多重接口的实现 87 5.8.4 抽象类 88 5.9 小结 90 第6章 ...

    AsyncSocketDemo

    AsyncSocketDemo用socket可以...一般来说,一个用户只需要建立一个socket长连接,所以可以用单例类方便使用。###定义单列类:LGSocketServeLGSocketServe.h//// LGSocketServe.h// AsyncSocketDemo//// Created by liga

    超级有影响力霸气的Java面试题大全文档

    HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。 HashMap允许将null作为一个entry的key或者...

    Java高并发高性能分布式框架从无到有微服务架构设计(1).doc

    当 应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务 可以根据实际需求独立进行扩展.互联网高并发相关名词页面浏览数〔page views 〕唯一身份浏览量〔Unique PageViews〕独立访问者...

    java 面试题 总结

    HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。 HashMap允许将null作为一个entry的key或者...

    java面试题

    2:继承:子类继承父类,子类可以拥有父类中已定义的方法,并且子类可以修改父类中的方法使其更适合特殊需求。 3:多台:不同对象对统一消息作出不同响应称之为多态 4:抽象:忽略与当前主题无关的那些方面,将...

    java卡牌游戏源码-HTTPServer:基于Netty、JSON-RPC的分布式弱联网游戏服务端

    目前该项目还是一个简单框架,可能未来发展还会加入更多新鲜元素,尽请期待! 关键技术 Maven、Netty、JSON-RPC、MySQL、Mybatis、Redis、Jedis、Base64、AES、MD5、JMX、slf4j、口令验证、反向代理、路由分发、双重...

    二十三种设计模式【PDF版】

    设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...

    (全)传智播客PHP就业班视频完整课程

    9-23 4.session③-购物车 cookie禁用后如何使用session session防用户非法登录 9-23 5.session④-验证码防恶意攻击 9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-...

    史上最全韩顺平传智播客PHP就业班视频,10月份全集

    9-23 4.session③-购物车 cookie禁用后如何使用session session防用户非法登录 9-23 5.session④-验证码防恶意攻击 9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-...

    韩顺平PHP JS JQUERY 所有视频下载种子 货真价实

    9-23 4.session③-购物车 cookie禁用后如何使用session session防用户非法登录 9-23 5.session④-验证码防恶意攻击 9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-...

    史上最全传智播客PHP就业班视频课,8月份视频

    9-23 4.session③-购物车 cookie禁用后如何使用session session防用户非法登录 9-23 5.session④-验证码防恶意攻击 9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-...

    史上最全韩顺平传智播客PHP就业班视频,9月份全集

    9-23 4.session③-购物车 cookie禁用后如何使用session session防用户非法登录 9-23 5.session④-验证码防恶意攻击 9-23 6.session⑤-session配置 session的gc机制 自定义session处理器 9-24 0.回顾 9-24 1.回顾2 9-...

Global site tag (gtag.js) - Google Analytics