B/S程序控制某一个用户在同一时间唯其如此登录一台机器的讨论

B/S程序控制某一个用户在同一时间只能登录一台机器的讨论

       今天又有一个客户提出了这种奇葩式的需求,领导为了满足客户要求必须要实现,这让人巨头疼,各种很难实现的理由提出之后,被客户至上的要求一一否决(中国特色)...总之,必须要实现,哪怕是假的。没办法,只能硬着皮头去做。

1、实现思路

       初步的想法是用户在第一次登录系统的时候,将这次session会话根据用户ID保存在application会话中,那么用同一个用户再次登录系统,首先根据用户ID获取application中的session会话,如果获取的是null,或者session是invalidate的,就可以登录,并重新将这次会话按照用户ID保存在application中,反之禁止用户重复登录。

2、实现步骤

2.1、登录service

      不画流程图了,直接上代码吧:

//获取application会话
ServletContext application = request.getSession().getServletContext();
//获取上一次登录session
HttpSession oldSessionId = (HttpSession)application.getAttribute(userName);
try {
	if(oldSessionId == null || oldSessionId.getAttribute("user") == null) {
		application.setAttribute(userName, request.getSession());
	} else {
		return new Message("-2", "对不起,用户"+user.getTt_username()+"已经在另一台机器上登录!");
	}
} catch (IllegalStateException e) {
	application.setAttribute(userName, request.getSession());
}

 

 

       这段代码中判断session的invalidate的状态是通过捕获异常来处理的,因为request.isRequestedSessionIdValid()方法只能判断当前新的session,而且因为时间关系,我也没找到session对象本身有判断失效的方法。不知道还有没有其他方式,如有还请不吝赐教。

2.2、控制session失效

       这种方式依然会遇到大家老生常谈的问题:控制session失效。特别是在浏览器关闭的时候,当然,正常关闭浏览器的方式是比较好控制的,但是由于各种灾害、各种强制性关闭的情况下,控制session失效就成了无解!为此,在这种情况下只能走偏门了,给系统管理员做一个在线用户管理的功能,把那些由于“特殊需求”导致非正常关闭浏览器的用户提供一个后门式的控制session失效的(注销)的功能。

        用户通过注销来正常退出系统的功能就不细说了,先来看看正常关闭浏览器的处理吧,这里主要是用到了body标签的onbeforeunload的事件,废话少说,直接上代码:

function winCloseDetail() {
	if(event.clientY < 0 && event.clientX > 0 || event.altKey) {
		var a = new AppAjax("loginout.do",function(data){
		});
		a.submit();
	}
}

 

<body onbeforeunload="winCloseDetail()">

       在浏览器关闭之前触发onbeforeunload,然后让他通过ajax去执行类似注销的action,使session失效。注意,这里的event.clientX可能在某些浏览器中失效。

 

       至此,以上在用户正常进行系统退出操作情况下的处理,已经基本可以满足功能需求,那么由于用户的特殊原因导致的不正常关闭系统的情况下,又该如何处理呢?

       在这种情况下靠程序自动去处理session失效的方式,除了所谓的监听有可能办到外,恐怕也没有其他办法了,网上也有很多人说,自己写计时器,不断去扫描...oh!My God!求实现,为了这点功能。即使去这样做,你如何判断某一session在没有失效的情况下已经没有客户端在连接了呢?

       由于时间关系,我无法去深入研究网上大神提出的各种方式了,只能做一个在线用户管理的功能,靠管理员人工干预了,或者让用户等到session失效(领导说可以这样让用户去等!oh,我的神啊,你的客户至上呢?)

       这个功能的实现只说说思路了,有两种:

 第一种:因为Java Servlet API的版本 2.1中,已经取消了通过sessionid获取session了(如果可以,前面放入application里的应该是sessionid)。所以可以自己做一个SessionContext,然后实现HttpSessionListener接口去获取所有在线用户。网上一搜有很多例子。

第二种:在application会话里存放一个session集合。

3、小结

       我的这种方法同样也有很多局限性,包括浏览器的兼容啊等等,但是没办法,客户至上以及领导的淫威战胜了一切。如果各位大神还有其他更好的思路,或者此种思路有弊端,还请批评指正。