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