Session管理之超时设置和强制下线

    关于Session,在Java Web开发中,为咱们提供了不少方便,Session是由浏览器和服务器之间维护的。好吧,闲话很少说,下面让咱们一步一步来实现它们。javascript

    (一)首先来讲下Session超时时间设置的三种方式,这些相对来讲比较简单:前端

    (1)在web.xml中设置session-configjava

<session-config>
  <session-timeout>2</session-timeout>
 </session-config>

    即交互间隔时间最长为2分钟(该处时间单位为分钟),2分钟后session.getAttribute()获取的值为空。web

    (2)在Tomcat的/conf/web.xml中session-config,默认值为:30分钟ajax

<session-config>
     <session-timeout>30</session-timeout>
</session-config>

    同上,时间单位为分钟。浏览器

    (3)在Servlet中设置服务器

HttpSession session = request.getSession();
session.setMaxInactiveInterval(60);

    即在你的程序代码中手动设置(该处时间单位为秒)。session

    优先级:Servlet中设置 >web.xml设置 > Tomcat/conf/web.xml设置app

    (二)同一用户强制下线jsp

    你们都知道在目前不少的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:

您的帐号已在另外一处登陆!

    此时,刷新第一个浏览器用户登陆界面,便会发现已经退出跳转到登陆页了,大功告成!!!

相关文章
相关标签/搜索