2012-09-03 48 views
0

我有一个需要登录用户的应用程序。数据存储在Derby数据库中。下面的表格根据用户名和密码字段查询它,并设置一个用户会话,该会话应该填充用户数据。有和没有线程的并发

但是,即使db正在对用户进行身份验证,会话也会返回空值。我怎么能把一个system.out.println放在这个类的主要方法中,它会根据db查询返回会话数据,而不是立即执行代码并返回null?

注意:数据库工作正常。我可以根据sql语句中的用户名和密码字段获得结果。

public class LoginForm{ 

    private static JTextField userName; 
    private static JTextField password; 
    private static JButton submit; 
    private static int attempts; 
    private static JFrame main; 

    private Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 

    final int MAX_ATTEMPTS = 5; 

    private UserSession session; 

    public LoginForm(){ 

     Handler handle = new Handler();        //inner class 
     LoginFormFocusListener fl = new LoginFormFocusListener(); //inner class 

     main = new JFrame(); 

     main.setUndecorated(true); 
     main.setBounds((dim.width/2) - (500/2),(dim.height/2) - (150/2),500, 75); 
     main.setVisible(true); 
     main.setAlwaysOnTop(true); 
     main.setResizable(false); 
     main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     userName = new JTextField(10); 
     password = new JTextField(10); 
     main.setLayout(new GridLayout(0,1)); 

     JPanel panel = new JPanel(); 
     main.add(panel); 

     panel.add(new JLabel("Username: ")); 
     panel.add(userName); 
     panel.add(new JLabel("Password: ")); 
     panel.add(password); 
     panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(4), "Please Login")); 

     submit = new JButton("Submit"); 
     panel.add(submit); 

     if(attempts > 0){ 
      panel.add(new JLabel("" + (MAX_ATTEMPTS - attempts) + " attempts remaining...")); 
     } 

     main.addWindowFocusListener(fl); 
     submit.addActionListener(handle); 
    } 



    public UserSession getSession(){ 
     return this.session; 
    } 

    /** 
    * creates the session that's returned to main/POSsystem via getSession 
    * @author Matt 
    * 
    */ 
    private class Handler implements ActionListener 
    { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      String user = userName.getText(); 
      String pass = password.getText(); 

      session = new UserSession(); 
      if(session.authenticate(user, pass)){ 
       System.out.println("User has been authenticated"); 
       JOptionPane.showMessageDialog(null,"Login Successful! ","",JOptionPane.PLAIN_MESSAGE); 
      }else{ 
       System.out.println("Login Failed!"); 
       JOptionPane.showMessageDialog(null,"Login Failed!","", JOptionPane.WARNING_MESSAGE); 
       attempts++; 
       if(attempts < MAX_ATTEMPTS){ 
        new LoginForm(); 
       }else{ 
        JOptionPane.showMessageDialog(null, "Max attempts reached. " + 
                 "Please Contact the administrator of this system. ", 
                 "User Locked", 
                 JOptionPane.ERROR_MESSAGE); 
       } 
      } 
     } 
    } 

    /** 
    * Inner Class 
    * custom focus events for the login form 
    * the user may click away from this pop-up to close it. 
    * @author Matt 
    * 
    */ 
    public class LoginFormFocusListener implements WindowFocusListener{ 

     @Override 
     public void windowGainedFocus(WindowEvent wEvt) {} 

     @Override 
     public void windowLostFocus(WindowEvent wEvt) { 
      ((JFrame) wEvt.getSource()).dispose(); 
     } 
    }  

    //test 
    public static void main(String args[]){ 

     SwingUtilities.invokeLater(new Runnable(){ 
       public void run(){ 
       LoginForm lf = new LoginForm(); 
       System.out.println("Session: " + lf.getSession()); <---NULL!!! 
       } 
      }); 


    } 

} 

回答

2

如果你真的想要得到的输出到控制台,那么不要把System.out.println代码放在​​main方法中,你应该把它作为actionPerformed方法的最后一行。

如果你真的,真的,真的想在main方法的代码,那么你应该创建实施,允许取回所创建的LoginForm的

这样Runnable接口的类:

final class InitThread implements Runnable { 
LoginForm lf; 

public LoginForm getLfForSystemOut() { 
    while (lf == null) { 
     try { 
      Thread.sleep(500); 
     } catch (final InterruptedException e) { 
      return null; 
     } 
    } 
    synchronized (lf) { 
     try { 
      lf.wait(); 
      return lf; 
     } catch (final InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    return null; 
} 

@Override 
public void run() { 
    lf = new LoginForm(); 
} 
} 

然后在主方法改变为这样:

public static void main(final String args[]) { 

    final InitThread init = new InitThread(); 
    SwingUtilities.invokeLater(init); 

    System.out.println("Session: " + init.getLfForSystemOut().getSession()); 

} 

,最后在actionPerformed方法在该块结束:

synchronized (LoginForm.this) { 
    LoginForm.this.notifyAll(); 
} 
+0

这是一个非常有用的解释,并且帮助我更好地理解了线程。我的主要目标是简单地将当前User对象分配给会话,但正如您所看到的,我无法获取数据。当然,主要只是一个测试用例。我想将一个User obj分配给Session obj,但需要等待数据变为可用。这导致我还有另一个问题......在更新数据时,我可以/应该从另一个类调用InitThread吗?还是有另一种方式,我应该通过表单从数据库中获取数据? – Matt

+0

如果您需要的是您从应用程序创建LoginForm以获取UserSession的场景,那么我建议您稍微改变一下设计。 你想要接收UserSession的地方应该有一个BlockingQueue [这里](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html)对象和LoginForm在创建时应通过构造函数接收BlockingQueue。 然后主线程通过调用它的_take_方法等待BlockingQueue,直到LoginForm创建一个UserSession对象并使用_put_方法将其放入队列。 – norbitheeviljester

+0

谢谢你的建议。我一定会考虑使用BlockingQueue。我想我的设计可能不得不改变。再次感谢。 – Matt

1

您遇到的问题是因为您要在用户有机会填写表单并按提交按钮之前获取会话。

当提交按钮被按下时,处理程序将被异步调用,在创建窗体后直接调用main中的println。您必须等到会话不再为空或在处理程序中使用经过身份验证的会话。

+0

感谢您的回复。我发现我可以从处理程序打印会话。我希望能够从可用的表单中分配数据。 – Matt