关于这个问题,我也看了很多的帖子,但是,基本都是那种零零散散的,不知道那位高手对这种有何看法。如果好的话,我还会加分,再100分。希望高手踊跃发言啊。

解决方案 »

  1.   

    无非是状态记录而已
    一,把Session的状态记录下来(内存),如登陆为1,未登陆为0,然后在每人登陆的时候进行判断,下线的时候也进行内存移出
    二,把Session的状态记录下来(文件),如登陆为1,未登陆为0,然后在每人登陆的时候进行判断,下线的时候也进行判断,文件清除
    上面都需要用到Session监听器,你可以看看统计在线人数怎么做的,其实原理一样
    还有一个就是用数据库记录
    也是同一个实现方式
      

  2.   

    登陆时判断ServletContext中是否有该用户帐号,有则拒绝,没有就把该用户帐号放入ServletContext,实现一个HttpSessionListener
    在session过期时把该用户帐号从ServletContext中删除,注意一下并发访问
      

  3.   

    给用户信息增加一个used的标志,
    1 每次登录时,将标志更新为 true
    2 每次退出登录时,将标志更新为 false;
    3 每隔一段时间(比如10分钟)查看用户是否在线? 具体怎么判断,那是另一个讨论话题了
    4 如果不在线,则更新标志为false
      

  4.   

    可以把sessionid放到数据库里,同一个人每次登陆的时候去数据库中把现在的sessionid更新到数据库,然后页面上的每一个和服务器交互的操作都要去验证现在的sessionid和数据库里自己用户名对应的sessionid是不是一样,如果一样就说明这个用户名就一个人在登录,一切操作正常,如果不一致说明已经又有人用这个用户名登录了,那现在的这个页面就不能用了,你让它跳转到登陆页面。这种做法就是最后登录的人有效!!!我们有个项目就是这样作的  但是不知道这样做好不好,如果楼主有什么没有明白的可以再联系我,我一般时都在
      

  5.   

    acegi有一个concurrent session,设置成1就只能登录一个人咯。
      

  6.   

    Application 里维护一个全局变量就可以了
      

  7.   

    Application 里维护一个全局变量就可以了,因为Application每个服务器或者web程序职能有一个,在Application范围维护一个全局变量,当第一次登陆就把这个变量置为true,再次登陆判断一下,如果是true就表明已经登陆了一个,就不可以登陆了,很简单吗
      

  8.   

    明确告诉你,为了你的程序的可用性,你不可能知道用户的准确在线信息。除非你安装插件比如 flash/applet/activeX让他们不停的访问服务器,告诉服务器我还活着..... 不过你的服务器得足够好才行
      

  9.   

    明确告诉你,为了你的程序的可用性,你不可能知道用户的准确在线信息。除非你安装插件 比如 flash/applet/activeX 让他们不停的访问服务器,告诉服务器我还活着..... 不过你的服务器得足够好才行可不可以说明白点啊。如果一个用户一下线不可能马上知道它下线是否下线,只有通过插件吗。是这样吗。我想了解一下,
    可以不可以说明白点啊
      

  10.   

    很简单 {后来的顶掉前面的}每个登陆用户有一个SESSION(其中放置登陆用户ID [USERID]) 每个SESSION有一个 SESSION_ID(这个应该是唯一的)建立一个全局变量字典 
    每个新登陆成功的用户 在字典中建立或者覆盖 USERID/SESSION_ID(一个用户登陆第2次 后来的必定覆盖前面的信息)然后 用户在SERVLET或者JSO执行时 在全局字典中 查询 当前的USERID 获取的SESSION_ID是否是 当前SESSION的SESSION_ID
    不一样 就证明已经 被其他地方登陆掉了 则不执行 任何命令
      

  11.   

    这个问题我曾经弄过我在blog上写了两篇相关文章,你可以参考一下
    《同一时间同一帐号只能登陆一个》
    http://heisetoufa.ggblog.com/296626.html----------------------------------------------------------------后登陆的用户会把先登陆的用户踢下线具体实现:sessionCheck:package test;import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpSession;import org.apache.struts.action.ActionMapping;public class sessionCheck 
    {
     
     private static sessionCheck sessioncheck;
     public sessionCheck(HttpServlet servlet) 
     {
     }
     public static sessionCheck getInstance(HttpServlet servlet) 
     {
      if (sessioncheck==null)
      {
       sessioncheck=new sessionCheck(servlet);
      }
      return sessioncheck;
     } 
     public void setSession(String userName,HttpServlet servlet,HttpSession session,ActionMapping mapping) 
     {
            final ServletContext sc = servlet.getServletContext();//取得容器,容器中根据用户唯一标识userID存放session
            System.out.println(sc);
            System.out.println(session);
            if (sc.getAttribute(userName) != null) 
            {
             // 第二次登陆后第一次无效
                ((HttpSession) sc.getAttribute(userName)).invalidate();// 清除第一次登陆的session
                System.out.println(session);
            }
            sc.setAttribute(userName, session);//放入当前最新session
            mapping.findForward("sessionDestroy") ;
        }}UserLoginForm:sessionCheck.getInstance(this.getServlet()).setSession(userName, servlet, session, mapping);jsp:<body ="sessionDestroy()">< language="java" type="text/java">
    sessionDestroy()
    {
      alert("连接超时,或帐号已在别处登陆,请查证后重新登陆");
      location.href = "UserLogin.jsp" ;
    }
    </> 
    这样在两台电脑上后登陆的人用户就会把先登陆的给踢掉,但是暂时还没实现在同一台电脑上后登陆的用户把先登陆的踢掉的功能上面是在后台实现的,如果要在JSP中做,直接appliction.getAttribute(userId),appliction.setAttribute(userId,   session)就行,application的我还没有去测试,有时间去试一下去
      

  12.   

    给数据库存储userid的表加一个登陆标志字段,每次登陆进行一下过滤不就行了吗。
      

  13.   

    session有一个监听器,当session销毁时它可以知道。
    继承这个监听器,并配置。
    在调用时,把用户信息从session中取出,将数据库中对应用户的状态修改。
      

  14.   

    知道有个东西叫SSO  ,有很多单点登陆的开源产品,也可以自己架设。可以打通多域名网站 ,也可以控制像你说的那样
      

  15.   

    无非是状态记录而已  
    一,把Session的状态记录下来(内存),如登陆为1,未登陆为0,然后在每人登陆的时候进行判断,下线的时候也进行内存移出  
    二,把Session的状态记录下来(文件),如登陆为1,未登陆为0,然后在每人登陆的时候进行判断,下线的时候也进行判断,文件清除  
    上面都需要用到Session监听器,你可以看看统计在线人数怎么做的,其实原理一样  
    还有一个就是用数据库记录  
    也是同一个实现方式 
      

  16.   

    我也做过这样一个项目,我的解决方法是这样的:(相互学习)
    建一个用户在线表,用户登陆就判断在线表中是否有此用户,如果有,提示不能重复登陆,没有则成功登陆.
    这就要解决用户退出的问题,就是说用户退出删除表中用户的问题.
    有几种情况
    1,用户点击系统指定退出按钮,系统从数据库中删除在线表中的用户.这个实现很简单就不说了.
    2,用户点窗口上的关闭(X)来关闭页面.在JAVASCRIPT里面写一个window.onbeforeunload函数.
    window.onbeforeunload = function () {
    if (event.clientX > document.body.clientWidth && event.clientY < 0 || event.altKey) {
    window.document.forms[0].submit();
    alert("\u4f60\u5df2\u5b89\u5168\u9000\u51fa!");
    }
    }
    执行一个form提交,去数据库中删除在线用户.
    3,如果用户直接关闭电脑,就是说非正常关机,这个就不好处理了.要用SESSION来判断,如果SESSION失效,则系统自动从数据库中去删除用户,但WEB中的SESSION是服务器端的,不能实时处理用户退出问题,就只有设置SESSION失效时间.
    写一个Listener继承HttpSessionListener在sessionDestroyed()方法中执行数据库删除操作.
    以上基本可以满足一般系统要求,当然还有一点就是,当服务器启动则执行在线表的清空操作.客户不喜欢每次重启服务器都要手工去表中删除未清空的在线用户.
    写一个SERVLET让其在容器启时自动启动,设置WEB.XML中的<load-on-startup>为一数字即可.
    还有什么没有写到的地方望大家赐教.
      

  17.   

    不好意思,刚才是从代码中拷的.
    那个ALERT("")里面的意思是"您已安全退出!"
      

  18.   

    1、状态记录意义不大,因为HTTP本质上是无状态的,你不知道谁在线,因此只能实现后面的有效登入踢掉前面的登入,那么,所谓的后面和前面需要更多的信息来判断,仅仅一个状态毫无意义,一般的处理是以登入机器的特征,比如IP,Cookie等的演算,判断新的登入与先前的登入演算码是否一致
    2、由上,新的登入之后,最节省识别方式可能是在浏览器和WEB Svr 之间互通一个登入随机数(新登入时产生),该数可以存储在任何合理的地方,传输通道最合理的应该是session cookie,也可以是请求参数
      

  19.   

    这个问题我也曾经碰到过,有人说加个字段来标识是否登录,也有人用HashTable来存,还有人用监听器来监听SESSION,更有人让服务器每秒刷新来判断SESSION是否还存活……
    但这些方法都不能完全解决你的问题。因为,如果遇到突然断电或者直接关闭浏览器窗口之类的事件,不仅不会更改数据库,更不会被监听到...其实我也是说大话,至今也不知道解决的好办法。
    不过,一般的WEB程序要求都不至于这样严格,把密码之类的安全性做高点就OK了
      

  20.   

    一起来建设我们的Software   Coffee   House(SCH) 
    CSDN群 招募中……
      

  21.   

    这个问题也真的是不怎么好回答。
    我也只学JSP一个月
    我个人的观点
    JSP不是有COOKIE的功能吗。
    不能说是功能,
    如果他登陆 我可以更新他的
    以下借用的啊:
    给用户信息增加一个used的标志, 
    1 每次登录时,将标志更新为 true 
    2 每次退出登录时,将标志更新为 false; 
    3 如果不在线,则更新标志为false 
    以下自己的观点:
    如果他点浏览器关闭 我会话肯定不是原来的了
    但是我可以用过滤器过滤 得到他的COOKIE中保存的信息 进行验证
    为TRUE的话 我可以给他创建会话。
    当他点退出的时候
    我可以把他COOKIE的内容给销毁掉
    不知道是不是答非所问了
      

  22.   

    HTTP的特性决定不可能完全准确的判断用户何时离线。所以不现实也没必要精确地刷新在线的用户信息,有一定的时间冷却是可以接受的。而冷却时间要看你的服务器了。
      

  23.   

    其实,那些说容易的人根本就连楼主的问题都没有搞明白最本质的原因在于http协议在一定能够的程度上可以说是一种残疾的协议
    只能由客服端单纯的“拉”取数据,而不能想像tcp/ip一样实现三次握手
    服务端也不能“推”数据,他是一种无状态的协议,,我们很难判别浏览器
    在什么时候推出,异常的结束会话!这也是问题的关系!
    acegi我还没有研究过,
    但是我有种思路就是
    1)设置用户合法注销,给出链接,至于是去在数据库还是application里面加状态字,随情况定
    2)用户点击关闭按钮的时候,发送ajax请求,请求后端注销账号
    但是,不能应付用户在任务管理器种关闭进程的方式
    期望高手给出完美解决方案
      

  24.   

    ls的这么多解决方案还不能解决你的问题吗?如果服务器好的话,用session比较简单
    或者用插件。
      

  25.   

    补充一下
    如果服务器足够健壮的话
    我们可以考虑在客服端设置一个一定时间间隔的触发器
    每次都像后台发送“userid”这个字段,后台可以根据time>时间间隔
    的情况判断用户是否”生存“,加控件的话,不好的地方在于我们大多数要求
    我们的程序能够跨越浏览器生存
      

  26.   

    在JAVA中,你能用SESSION来判断,SESSION在登陆的时候,会监听到新SESSION的创建,这样,你可以用ARRAYLIST来保存这个登陆成功的用户ID,SESSION设置超时1小时清除。
    如果有人在其他地方登陆,那么首先读ARRAYLIST保存的用户ID,如果ID存在,则证明此ID已被他人登陆中,提示不能重复登陆。
    具体代码:public class User implements HttpSessionBindingListener {   private int userid;
    //GETTS,SETTS METHODS ADD IN HERE
    public void valueBound(HttpSessionBindingEvent arg0) {
    // TODO Auto-generated method stub
    System.out.println("add some one");
    System.out.println("userid:"+userid);
    boolean isExists=userList.contains(Integer.toString(userid));
    if(isExists==false)
    userList.addUser(Integer.toString(userid));
    }
    public void valueUnbound(HttpSessionBindingEvent arg0) {
    // TODO Auto-generated method stub
    System.out.println("remove some one");
    System.out.println("userid:"+userid);
    boolean isExists=userList.contains(Integer.toString(userid));
    if(isExists==true)
    userList.removeUser(Integer.toString(userid));
    }
    }
    完整代码比较长,要涉及你的登陆系统怎么来做的,但上面是最关键核心的代码,结合我的描述,你实现出来应该不难
      

  27.   

    个人感觉新的定旧的不错,新登入的直接覆盖掉旧的,至于旧的请求可以根据sessionID来判断是不是最新,不是就提示,并要求重新登入。这样感觉是最简单的。还有就是旧的不能顶新的,上面已经有很多人提供方法了,关键就是退出的问题,其实没有必要管理这个退出,只要当前判断当前用户正在使用(方法上面已经说了很多了),就不让新的用户登陆就是,然后在设置一个选项,强制登陆,在强制登陆的情况下 ,就会覆盖掉旧的。这样应该能适合一些情况吧。或者加个选项不允许强制登陆,使强制登陆失效,但这样情况下,可以为系统设置一个检测时间,如:30分钟内该用户没有响应就自动掉线,或者失效。这2个方法结合应该能稍微能改善点吧
      

  28.   

    假设用户A先使用帐号s登陆,用户B后使用帐号s登陆。
    处理情况分两种:
    一、不允许B登陆
      1、数据库创建标记位。
      2、创建map表存储userName-->sessionId。
      两种方法,缺点:当用户A在未正常退出---session失效的时间内,帐号s无法使用。即使可以监听到用户关闭浏览器,也无法监听到用户从任务管理器关闭浏览器、
                      浏览器错误甚至机器断电。所以不建议使用此方法。二、踢掉用户A
      1、数据库记录sessionId。
      2、创建map表存储userName-->sessionId。
      原理:以map表为例,当用户A登陆时,读取userName对应的sessionId,如果存在则覆盖之,不存在,则添加到map表,map表数据如:s-->sessionIdA.
            当用户B登陆时,做同样操作,map表数据如:s-->seesionIdB。当A再次发出请求时(非登陆请求),读取userName对应的sessionId,
            sessionIdA(A的请求携带的)!=sessionIdB(map表中读取的),设置sessionIdA无效,跳回登陆页,要求登陆。
            只需要建一个filter过滤登陆请求,一个filter过滤非登陆请求。
      

  29.   

    请求走的本来就是无状态协议
    如果想做的实时精度高的
    看看server push
    http://topic.csdn.net/t/20000704/10/13930.html
    不断线,服务端向客户端推的技术吧
      

  30.   


    可以使用Session啊,登录了就记在Session中,下次有用户登录就与Session中存的比较,有相同的就不允许登录,否则就可以登录
    用户一退出就马上注销Session,这样就不存在这样的问题了
      

  31.   


    这位仁兄貌似有点没搞清楚状况,站着说话不腰疼,知道大家都在讨论什么不
    用户一退出就马上注销session,你以为在玩c/s呢
      

  32.   

    没有必要那么麻烦,那样做的话可能会给系统带来额外的开销,还不如,在用户登陆之前,看一浏览一下session有没有username,如果有让她销毁,然后你这个就可以使用,好像QQ也就是这么做的
      

  33.   

    如果在另外一台机器上登陆的话,session就不管用了吧!
      

  34.   


    46楼分析的很有道理第一种情况的实现是:
             1.当用户访问该登陆页时Session建立,当用户登陆后我们才知道此帐号UserID
            2.这时我们可以在登陆的逻辑代码中 将Session和UserID 一并保存到Application或SverletContext的在线用户列表当中.
            (这里如果用Session监听器HttpSessionListener是不行的,只能用HttpSessionBindingListener在登陆时绑定监听)
            3.当其他用户B使用此帐号登陆时 就可以查找用户列表中是否有UserID  有则将B用户转向失败提示页面。
            4.当Session销毁时 将Session和UserID 从Application或SverletContext的用户列表当中移除。 
    上面所谈到的缺点也正式这两种Session监听器,在监听Session销毁时的一个弱点
    HttpSessionListener两种情况下执行sessionDestroyed(HttpSessionEvent e)(会话销毁)
    1:执行session.invalidate()方法时。
    2:如果用户长时间没有访问服务器,超过了会话最大超时时间,服务器就会自动销毁超时的session。
    倘是第一种情况 一般是属于正常session销毁,而第二种则是属于非正常销毁  要等待一段时间,session超时销毁。而这段时间此UserID 其他用户无法再登陆。
    HttpSessionBindingListener三种情况下执行valueUnbound(HttpSessionBindingEvent e)
    1.2相同。 
    3:执行session.setAttribute("Listener", "其他对象");或session.removeAttribute("Listener");将listener从session中删除时。
    所以不够理想。二、踢掉用户A  1.当用户访问该登陆页时Session建立,当用户登陆后我们才知道此帐号UserID
            2.这时我们可以在登陆的逻辑代码中 将Session和UserID 一并保存到Application或SverletContext的在线用户列表当中.
            (这里如果用Session监听器HttpSessionListener是不行的,只能用HttpSessionBindingListener在登陆时绑定监听)
            3.当其他用户B使用此帐号登陆时 就可以查找用户列表中是否有UserID  有则将B用户Session和UserID替换掉原有的ID。
            4.当Session销毁时 将Session和UserID 从Application或SverletContext的用户列表当中移除。
    三 两种Session监听器的比较         1.绑定方式上不同 : HttpSessionListener发挥作用,我们将它添加到web.xml中,只需要设置到web.xml中就可以监听整个应用中的所有session。
                   <listener>
                    <listener-class>pkg.xxxxListener</listener-class>
                 </listener>
    而HttpSessionBindingListener发挥作用,必须实例化后放入某一个session中,才可以进行监听。如在登陆时候:
                   session.setAttribute("xxxxxBindingListener", new xxxxxxxBindingListener(userID));
    HttpSessionBindingListener通常都是一对一.正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个userID,这样就不需要每次再去session中读取userID,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。
     
             2.销毁方式刚讲过了!         3.两个不同的接口实现。
      

  35.   

    今天看到一個多任務框桇,叫Quartz,非常強大,它其中的一個監聽功能,可以達到普通監聽器的功能,而且讓服務器每秒檢測用戶是否在線,我想推薦的原因是:它不僅可以解決你的問題,而且這個框桇不太耗性能。
    你可以到網上去下載相關資料,在網上找不到的Q我,我這里有,這兩天兒我也開始學習它
      

  36.   

    数据库表加个字段 不错的方法!!
    就是检查用户是否在线麻烦!! 
    session机制不太好!!用户直接关闭浏览器session不能自动取消!!还得等session到期!!
      

  37.   

    我以前也提过这个问题。当时我是不让第二个用户登录。在服务启动时初始化一个hashmap,里面放登录的用户。如果登录时里
    面有这个用户存在就不让登录。登出时remove掉这个用户。在登出及点击ie X时remove用户。在监听器监听到session失效时
    也remove。后来只有一个问题没解决,就是在ie url地址栏直接输入地址,然后转向这个事件捕捉不到。
      

  38.   

    最简单的方法就是用户登陆后,在数据库表中有个标记位,判断他,当session失效的时候也去改变他就是了
      

  39.   

    我看主要的问题是:用户退出判断,大约有这么几种吧:点击“退出”按钮、关闭浏览器、断电。1 要是用户每次都能点击退出按钮的话倒是简单的多了,但是这种情况简直不可能,写把用户信息放到集合(如list)里,写到数据库里,都行。
    2 要是关闭浏览器得话,就麻烦点了。怎么监听关闭浏览器呢,先看看关闭方法:直接点击关闭、任务栏中关闭、任务管理器中关闭,用什么来监听好呢,unload方法肯定不行了,这样页面就不能刷新了。
    3 断电,这是最麻烦的。以上的方案恐怕都不行了,要是把状态写到数据库里。那用户在修改数据库之前永远不能登陆了。写到集合里,也是不能登陆,应该等到web服务器重启,这样也不太好。基本上很少重启。如果后登陆的踢掉先登录的,那后登陆的要是非法用户不麻烦了。你得在登陆了,要是有重要信息的话,你们两个就需要不断的互相踢出登陆了。如果写个监听器,那倒是好,放到哪都无所谓了,但就是耗费多点服务器资源。如果这个单点登陆非做不可的话,那我感觉最好的是:把用户信息写到list里或者写到数据库里,再写个监听程序,放在服务器上定时监听30秒(自己视情况而定)执行一次把非正常退出的用户信息删除。java里面有timerTask,用它吧。或者自己写线程控制也行。我前些天也打算做这个来着,但是碍于我们开发的系统安全性没这么高,做起来又繁琐,就放弃了这种方案。