关于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:
您的帐号已在另外一处登陆!
此时,刷新第一个浏览器用户登陆界面,便会发现已经退出跳转到登陆页了,大功告成!!!