前一段时间碰到一个需求:一个账号只能登录一次,不能重复登录问题。
在网上找了下,大概有两种解决方案:
1、通过数据库状态位判断该用户是否已经登录。
2、利用session监听器监听每一个登录用户的登录情况。
个人想了下,第一种解决方案很简单,但需要考虑用户非正常退出的情况,如直接关闭浏览器等等,可用性较低。
接下来,主要介绍第二种方案的具体实现:
A.用户登录后,先去数据库查询该登录名是否存在、是否锁定,在登录名存在且非锁定的情况下,从application内置作用域对象中取出所有的登录信息,查看该登录名是否已经登录,如果登录了,就友好提示下;反之表示可以登录,将该登录信息保存在application中。
主要代码如下:
03 | Map<String, String> loginUserMap = (Map<String, String>) super .getApplicationAttr(Constant.LOGIN_USER_MAP); |
04 | boolean isExist = false ; |
05 | String sessionId = super .getSessionId( false ); |
07 | if (loginUserMap== null ){ |
08 | loginUserMap = new HashMap<String, String>(); |
11 | for (String username : loginUserMap.keySet()) { |
12 | //判断是否已经保存该登录用户的信息,是否为同一个用户进行重复登录 |
13 | if (!username.equals(user.getFuUserName()) || loginUserMap.containsValue(sessionId)){ |
25 | loginUserMap.put(result.getFuUserName(), sessionId); |
B.登录考虑完之后,来考虑考虑退出。
用户正常退出时,我们需要将该用户的登录信息从session中移除。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。
主要代码如下:
02 | public void sessionDestroyed(HttpSessionEvent event) { |
04 | //在session销毁的时候 把loginUserMap中保存的键值对清除 |
05 | User user = (User)event.getSession().getAttribute( "loginUser" ); |
07 | Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute( "loginUserMap" ); |
08 | loginUserMap.remove(user.getFuUserName()); |
09 | event.getSession().getServletContext().setAttribute( "loginUserMap" ,loginUserMap); |
另外,还有一个问题,如果说登录的用户突然关闭了浏览器而没有点击退出按钮。那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。
预览源代码 打印
03 | $(window).bind( 'beforeunload' , function (){ |
05 | url: "${ctx}/system/user/user!logout.action" , |
这样基本就实现了需求了。