2012-09-03 55 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