java web中实现同一帐号同一时间只能一个地点登陆(类似QQ登录的功能)

在java web中如何实现像QQ登录的功能,同一帐号不能同时在两台电脑上登录。

一、该功能有什么作用

     大家想想吧。反正总会有这样的需求的。这年头什么需求不会有。。呵呵。有时候也不一定是需求,很有可能为了安全也会这么做。例如考试系统,在线聊天系统,很有必要做成这样的吧。

二、实现过程

     a.问题分析

    在系统中,我们一般都是把登录信息绑定到session中,看来从这入手是可能找到解决办法。说白了,也就是当用户登录时,判断一下这个用户有没有登录,如果登录了,就把以前的那个session清除掉就OK了。。看似很简单是不?其实你细想你会发现有以下问题:如何得到之前这个用户有没有登录过,也就是如何访问到所有登录的session信息呢?

  b.具体实现

   大家知道,在j2ee api好像是没有具体的方法直接得到所有session信息的。但是我们可以通过配制监听器,监控所有的session创建和消毁过程,以及可以监控session中的属性的创建,删除和替换过程。

        其实我们只要做以下处理即可:

              在保存用户登录信息到session时,对应的也就是session一个属性的创建过程(attributeAdded),可以把当前这个session记录到一个ArrayList中。

              其实在保存到list中时你要首先遍历一下这个list中有没有已经存在该用户的登录信息。如果存在就消毁掉这个list中存在的session信息,并且从list中移除,不存在就把该session信息放到list中。

              在session的登录信息消毁时,直接把该sesseion从list中移除掉。

              还有就是当用户登录后没有退出直接登录这个时候是一个session属性的替换过程。也要做处理判断新的用户是否已经在除了当前session的其它session中是否存在。存在则删除。

        具体代码如下:

  
  
package com.weirhp;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class RecordSessionListener implements HttpSessionAttributeListener,
HttpSessionListener {
private static List < SessionAndUser > sessions;
public static String loginFlag = " loginUser " ;

static {
if (sessions == null ) {
sessions
= Collections.synchronizedList( new ArrayList < SessionAndUser > ());
}
}

public void attributeAdded(HttpSessionBindingEvent e) {
HttpSession session
= e.getSession();

System.
out .println( " -------------*start added*----------------------- " );
String attrName
= e.getName();

// 登录
if (attrName.equals(loginFlag)) {
User nowUser
= (User) e.getValue();
User sUser
= (User)session.getAttribute(loginFlag);
// 遍历所有session
for ( int i = sessions.size() - 1 ; i >= 0 ; i -- ) {
SessionAndUser tem
= sessions. get (i);
if (tem.getUserID().equals(nowUser.getName())) {
tem.getSession().invalidate();
// 自动调用remove
break ;
}
}

SessionAndUser sau
= new SessionAndUser();
sau.setUserID(nowUser.getName());
sau.setSession(session);
sau.setSid(session.getId());
sessions.add(sau);

}

}

public void attributeRemoved(HttpSessionBindingEvent e) {
HttpSession session
= e.getSession();
System.
out .println( " -------------*start Removed*----------------------- " );
String attrName
= e.getName();
// 登录
if (attrName.equals(loginFlag)) {
User nowUser
= (User) e.getValue();
// 遍历所有session
for ( int i = sessions.size() - 1 ; i >= 0 ; i -- ) {
SessionAndUser tem
= sessions. get (i);
if (tem.getUserID().equals(nowUser.getName())) {
sessions.remove(i);
break ;
}
}

}
}

public void attributeReplaced(HttpSessionBindingEvent e) {
HttpSession session
= e.getSession();
System.
out .println( " -------------*start replace*----------------------- " );
String attrName
= e.getName();
int delS =- 1 ;
// 登录
if (attrName.equals(loginFlag)) {
// User nowUser = (User) e.getValue(); // old value
User nowUser = (User)session.getAttribute(loginFlag); // 当前session中的user
// 遍历所有session
for ( int i = sessions.size() - 1 ; i >= 0 ; i -- ) {
SessionAndUser tem
= sessions. get (i);
if (tem.getUserID().equals(nowUser.getName()) &&! tem.getSid().equals(session.getId())) {
System.
out .println( " Remove:invalidate 1! " );
delS
= i;
}
else if (tem.getSid().equals(session.getId())){
tem.setUserID(nowUser.getName());
}
}

if (delS !=- 1 ) {
sessions.
get (delS).getSession().invalidate(); // 失效时自动调用了remove方法。也就会把它从sessions中移除了
}

}
}

public void sessionCreated(HttpSessionEvent e) {
}

public void sessionDestroyed(HttpSessionEvent e) {
}

}

在web.xml中的配制

  
  
1 < listener >
2 < display-name > recordSession </ display-name >
3 < listener-class > com.weirhp.RecordSessionListener </ listener-class >
4 </ listener >

三、具体代码测试

  源代码下载

四、可能存在的问题

       整个个程序可能有的点没有想到。可能存在一些bug,用于具体项目需谨慎,欢迎大家拍砖,也希望给点建议。我再改进。

五、后来的一些思考

  如果两台机器使用同一帐号在同一时刻登录系统,是不是两个帐号都可以登录成功呢。。(还有就是这个session List很大时,在遍历的时间段中两台机器使用同一帐号在同一时刻登录系统也可能会成功登录的)。很是纠结。。应该怎么控制呢?

(解决办法:经测试Listener在系统中是一个单例,在它的方法上加上synchronize关键字就可以保证list的线程安全了。)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个Java Swing模拟实现QQ登录界面的示例代码: ```java import javax.swing.*; import java.awt.*; import java.awt.event.*; public class QQLogin extends JFrame { private JTextField usernameField; private JPasswordField passwordField; public QQLogin() { // 设置窗口标题 setTitle("QQ登录"); // 设置窗口大小 setSize(300, 200); // 设置窗口居 setLocationRelativeTo(null); // 设置窗口关闭时退出程序 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 创建用户名、密码输入框和登录、取消按钮 JLabel usernameLabel = new JLabel("用户名:"); usernameField = new JTextField(20); JLabel passwordLabel = new JLabel("密 码:"); passwordField = new JPasswordField(20); JButton loginButton = new JButton("登录"); JButton cancelButton = new JButton("取消"); // 创建一个面板来放置输入框和标签 JPanel inputPanel = new JPanel(new GridLayout(2, 2)); inputPanel.add(usernameLabel); inputPanel.add(usernameField); inputPanel.add(passwordLabel); inputPanel.add(passwordField); // 创建一个面板来放置按钮 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); buttonPanel.add(loginButton); buttonPanel.add(cancelButton); // 将面板添加到窗口 setLayout(new BorderLayout()); add(inputPanel, BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); // 为登录按钮添加事件监听器 loginButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String username = usernameField.getText(); char[] passwordChars = passwordField.getPassword(); String password = new String(passwordChars); // TODO: 在这里编写登录逻辑 JOptionPane.showMessageDialog(QQLogin.this, "登录成功!"); } }); // 为取消按钮添加事件监听器 cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); } public static void main(String[] args) { QQLogin qqLogin = new QQLogin(); qqLogin.setVisible(true); } } ``` 这个示例代码创建了一个窗口,包含一个用户名输入框、一个密码输入框和两个按钮:登录和取消。当用户点击登录按钮时,程序将获取用户名和密码,并在控制台输出。您可以在这里添加登录逻辑,比如将用户名和密码发送到后端进行验证。当用户点击取消按钮时,程序将退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值