Session管理之超时设置和强制下线
Session管理之超时设置和强制下线
海岸线的曙光 发表于4周前
Session管理之超时设置和强制下线
  • 发表于 4周前
  • 阅读 4247
  • 收藏 140
  • 点赞 6
  • 评论 13
【腾讯云】新注册用户域名抢购1元起>>>   
摘要: Session,强制下线
    关于Session,在Java Web开发中,为我们提供了很多方便,Session是由浏览器和服务器之间维护的。好吧,闲话不多说,下面让我们一步一步来实现它们。     (一)首先来说下Session超时时间设置的三种方式,这些相对来说比较简单:     (1)在web.xml中设置session-config <session-config> <session-timeout>2</session-timeout> </session-config>     即交互间隔时间最长为2分钟(该处时间单位为分钟),2分钟后session.getAttribute()获取的值为空。     (2)在Tomcat的/conf/web.xml中session-config,默认值为:30分钟 <session-config> <session-timeout>30</session-timeout> </session-config>     同上,时间单位为分钟。     (3)在Servlet中设置 HttpSession session = request.getSession(); session.setMaxInactiveInterval(60);     即在你的程序代码中手动设置(该处时间单位为秒)。     优先级:Servlet中设置 >web.xml设置 > Tomcat/conf/web.xml设置     (二)同一用户强制下线     大家都知道在目前很多的web项目中,大多数情况下都是可以让同一个用户账号在不同的登录入口登录的,但这样其实就显得不是很严谨了,毕竟信息修改等操作对于信息是否能完全即时同步还是个未知之数。所以,接下来,我要做的只是对于不同浏览器的同一个用户账号的强制下线处理,对于同一个浏览器暂不做考虑,先来看下面这张图。大概的了解一下:     从上面可以看出:同一个浏览器对于不同的账号,登录时会产生相同的sessionId,这也就导致了用户之间信息的覆盖;不同浏览器对于不同的账号登录时,登录时会产生不同的sessionId,这也就给了我们可操作的空间了,正是要利用这一点来进行判断和相应处理。     (1)添加监听器     为了方便这里使用Session监控的方式,创建SessionListener,如下: public class SessionListener implements HttpSessionBindingListener{ @Override public void valueBound(HttpSessionBindingEvent event){ // TODO Auto-generated method stub } @Override public void valueUnbound(HttpSessionBindingEvent event){ // TODO Auto-generated method stub } }     这里HttpSessionBindingListener和HttpSessionListener效果一样,大家可以任选其一。重载两个方法:session的创建和销毁。     当然,在web.xml中添加相应配置是必不可少的: <listener> <listener-class>com.yoki.util.SessionListener</listener-class> </listener>     由于sessionId和userId需要存储,方便后面的判断,我们在上面的类中添加两个Map,如下: //保存username和session的映射 public static HashMap<String,Session> MAP1 = new HashMap<String,Session>(); //保存sessionID和username的映射 public static HashMap MAP2 = new HashMap();     最后,用户登录验证成功时需要调用一个方法来判断是否强制下线: public static void userLogin(Session session,String sUserName){ //已登录 if(MAP2.containsValue(sUserName)){ Session l_session = MAP1.get(sUserName); //不同浏览器,同一用户(强制下线前一个) if(l_session != null && l_session.getId() != session.getId()){ MAP1.remove(sUserName); MAP2.remove(l_session.getId()); l_session.setAttribute("msg", "您的账号已在另一处登录!"); MAP2.put(session.getId(), sUserName); MAP1.put(sUserName, session); } //同一浏览器,同一用户(不做任何变动) }else{ //未登录 if(MAP2.containsKey(session.getId())){ //同一浏览器,不同用户(不做任何变动) }else{ //不同浏览器,不同用户(正常添加) MAP2.put(session.getId(), sUserName); MAP1.put(sUserName, session); } } }     解释一下:这里使用username和userId效果一样,看你们怎么方便怎么用了,方法中的逻辑是根据上面的图来编写的,首先判断用户是否登录了,因为MAP中保存了相关的session关联信息,所以可以通过这个来判断;由于此处只对不同浏览器相同用户进行处理,所以直接判断是否是同一个浏览器。方法的参数session是用户在当前浏览器登录时的信息,我们可以从MAP中得到之前保存过的相同用户的session信息,与之进行比较,里面的逻辑是:移除MAP中保存的之前的用户信息(对应的session此时未销毁),并给其session添加一个msg信息(后面用到,往下看),再添加新的用户信息。     上面的方法调用放在登录验证成功后,各自项目不同,但登录验证的类基本差不多: SessionListener.userLogin(session, USERNAME);     (2)添加前端页面调用的方法     在登录验证的类中添加如下方法: /* * 判断用户是否重复登录 */ @RequestMapping(value="/checkUserOnline") @ResponseBody public void checkUserOnline(HttpServletRequest request,HttpServletResponse response) throws IOException{ HttpSession session=request.getSession(); PrintWriter out = response.getWriter(); String msg = ""; if(session.getAttribute("msg") != null){ msg = session.getAttribute("msg").toString(); System.out.println(msg); } out.print(session.getAttribute("msg")); }     方法中获取之前添加到session中的msg,用来判断是否强制下线,继续。     (3)前端页面循环调用     选择一个页面,最好是所有页面都用到的,比如我用的index.jsp,如下: <script type="text/javascript"> $(document).ready(function(){ setInterval("checkUserOnline()",5000); //每隔5秒判断一次 } function checkUserOnline(){ var msg = ""; $.ajax({ type : "POST", url : "checkUserOnline", data : {}, async: false, success : function(data){ msg = data; } }); if (msg == 'null' || msg == '' || msg == 'undefined'){ return; }else{ //调用你的注销用户方法 var url="<%=path%>/logout.do"; $.get(url,function(data){}); } } </script>     js中调用setInterval方法,设置调用的方法和间隔时间,方法里通过ajax调用上面添加的类并返回msg,通过msg来判断是否调用注销方法(路径啥的自己注意,能调用到就ok)。     (4)注销     一般web项目登录进去后都会有个退出按钮,点击即返回到登录页,此时在里面添加一行代码,防止错误,可能会出现重新登录报session已被销毁的错误提示,但第二次便会成功,这里便是为了消除该错误: SessionListener.MAP2.remove(session.getId());     好了,基本的设置完成了,启动项目,打开两个不同的浏览器,先登录一个用户,成功后,在另一个浏览器中登录相同的用户,登录成功后,会在控制台上打印出msg: 您的账号已在另一处登录!     此时,刷新第一个浏览器用户登录界面,便会发现已经退出跳转到登录页了,大功告成!!!
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 21
博文 26
码字总数 28068
评论 (13)
营养快线送你520
我可以转载到我的博客吗
海岸线的曙光

引用来自“营养快线送你520”的评论

我可以转载到我的博客吗
可以
打破突破
可以详细说下为什么同一浏览器不同账号的访问会产生相同的sessenId么?
freezingsky

引用来自“打破突破”的评论

可以详细说下为什么同一浏览器不同账号的访问会产生相同的sessenId么?
主要原因是来自于浏览器与Web服务器通讯的过程。
如果当前浏览器没有sessionId,则后端会生成新的。如果当前浏览器已经有了,则默认使用。所以,经常会发生一个现象就是,同一个浏览器中,A用户登录,然后再B用户登录,这时候,你切换到A用户的Tab,实现上,流浏览器与服务器维护的信息,已经变成了B,则A用户的信息已经丢失了。
不过,有一些浏览器做了改造,不同Tab间的cookie信息是独立的,就可以解决这一块的情况。
穆哥哥
有没有办法实现跨浏览器的强制下线呢?
海岸线的曙光

引用来自“穆哥哥”的评论

有没有办法实现跨浏览器的强制下线呢?
回复@穆哥哥 : 这个就是不同浏览器的
MiniDoraemon
你好 同一用户强制下线 那个图上的不同浏览器相同用户,应该 sessionId 不同,userId是相同的吧
海岸线的曙光

引用来自“MiniDoraemon”的评论

你好 同一用户强制下线 那个图上的不同浏览器相同用户,应该 sessionId 不同,userId是相同的吧
感谢纠正,画图的时候写错了:+1:
穆哥哥

引用来自“海岸线的曙光”的评论

引用来自“穆哥哥”的评论

有没有办法实现跨浏览器的强制下线呢?
回复@穆哥哥 : 这个就是不同浏览器的
但是这个地方取的session可能会有不同步的问题。通过监听器的话,如果tomcat持久化了会话,再启动的时候,你会发现原来的登录信息,你的map里面没有,但是其实tomcat里面的这个是有的。:thumbsup:
海岸线的曙光

引用来自“海岸线的曙光”的评论

引用来自“穆哥哥”的评论

有没有办法实现跨浏览器的强制下线呢?
回复@穆哥哥 : 这个就是不同浏览器的

引用来自“穆哥哥”的评论

但是这个地方取的session可能会有不同步的问题。通过监听器的话,如果tomcat持久化了会话,再启动的时候,你会发现原来的登录信息,你的map里面没有,但是其实tomcat里面的这个是有的。:thumbsup:
嗯,这个在监听器的销毁方法里应该可以进行处理的
穆哥哥

引用来自“海岸线的曙光”的评论

引用来自“穆哥哥”的评论

有没有办法实现跨浏览器的强制下线呢?
回复@穆哥哥 : 这个就是不同浏览器的

引用来自“穆哥哥”的评论

但是这个地方取的session可能会有不同步的问题。通过监听器的话,如果tomcat持久化了会话,再启动的时候,你会发现原来的登录信息,你的map里面没有,但是其实tomcat里面的这个是有的。:thumbsup:

引用来自“海岸线的曙光”的评论

嗯,这个在监听器的销毁方法里应该可以进行处理的
这个我之前处理过,不过好像没有什么好办法,我之前处理的方式有两种 ,一种就是直接不让tomcat持久化session信息,换而言之,也就是tomcat重新启动后,所有的登录信息都需要重来一遍。第二个就是持久化到数据库,这个时候不要监听器了,直接查询数据库来判断。。。不知道你还有没有其他更好的办法。:+1:
海岸线的曙光

引用来自“海岸线的曙光”的评论

引用来自“穆哥哥”的评论

有没有办法实现跨浏览器的强制下线呢?
回复@穆哥哥 : 这个就是不同浏览器的

引用来自“穆哥哥”的评论

但是这个地方取的session可能会有不同步的问题。通过监听器的话,如果tomcat持久化了会话,再启动的时候,你会发现原来的登录信息,你的map里面没有,但是其实tomcat里面的这个是有的。:thumbsup:

引用来自“海岸线的曙光”的评论

嗯,这个在监听器的销毁方法里应该可以进行处理的

引用来自“穆哥哥”的评论

这个我之前处理过,不过好像没有什么好办法,我之前处理的方式有两种 ,一种就是直接不让tomcat持久化session信息,换而言之,也就是tomcat重新启动后,所有的登录信息都需要重来一遍。第二个就是持久化到数据库,这个时候不要监听器了,直接查询数据库来判断。。。不知道你还有没有其他更好的办法。:+1:
嗯,tomcat是否持久化根据自己需要来添加,暂时还没对这块深入研究:smile:
kaole
单机部署情况下,使用的是hashMap来保存对应关系,所有是有并发问题的
同时hashmap也解决不了多机部署的情况
×
海岸线的曙光
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: