2017-05-23 3 views
0

JavaFX에서 약간의 진행률 표시 줄로 로그인 페이지를 만들려고합니다. 하지만 매번 자격 증명을 확인하려고 할 때마다 작업이 실패하고 setOnFailed() 메서드가 throw됩니다. 나는 그것이 무엇이 주 (state)인지 또는 그것이 작동하도록 만드는 방법을 바꾸는지를 모른다. 데이터베이스에서 데이터를 가져 오는 때 항상 validatePassword 방법에 실패JavaFX 작업이 로그인 정보를 가져올 때마다 상태가 실패로 바뀝니다.

public class Login extends Base_controller implements Initializable{ 
    private ProgressBar pb = new ProgressBar(); 
    private TextField username; 
    private PasswordField password; 

    public void start(Stage primaryStage) throws Exception { 

     // Setting structure and components 
     Label username_lbl = new Label(); 
     Label password_lbl = new Label(); 
     username_lbl.setText("Username:"); 
     password_lbl.setText("Password:"); 

     username = new TextField(); 
     password = new PasswordField(); 

     //some code 

     VBox root = new VBox(); 
     root.setAlignment(Pos.CENTER); 
     root.getChildren().addAll(container0, container1, container2, container3); 
     root.setSpacing(30); 


     // button action listener 
     test.setOnAction(e->{ 
      Platform.runLater(() -> { 
       root.getChildren().add(pb); 
      }); 

      Task<Void> validatePassword = new Task<Void>(){ 
       @Override 
       protected Void call() throws Exception { 
        validatePassword(password, username); 
        return null; 
       } 
      }; 

      validatePassword.setOnSucceeded(ee->{ // when it finishes successfully 
       try { 
        root.getChildren().remove(pb); // remove the progress bar 
       } catch (Exception e1) { 
        e1.printStackTrace(); 
       } 

       User = dbHandler.getPersonByUsername(username.getText()); // Set up global variable 
       Role = dbHandler.getPersonRole(User.getEmail()); 
       MainStage = (Stage) anchorPane.getScene().getWindow(); 
       Parent parent = null; 
       try { 
        parent = FXMLLoader.load(getClass().getResource("/menu.fxml")); 
       } catch (IOException e1) { 
        e1.printStackTrace(); 
       } 
       Scene scene = new Scene(parent); 
       MainStage.setScene(scene); 
       MainStage.setTitle("Menu | Administration of Musical Courses"); 
       MainStage.show(); 
      }); 

      validatePassword.setOnFailed(eee->{ // if it fails (that will be indicated by the returned alert message) 
       System.out.println("Failed"); 
       try { 
        root.getChildren().remove(pb); // remove it anyway but inform your user 
        Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK); 
        alert.showAndWait(); 
       } catch (Exception e1) { 
        e1.printStackTrace(); 
       } 
      }); 

      new Thread(validatePassword).start(); // add the task to a thread and start it 
     }); 

     Scene scene = new Scene(root, 600,400); 
     primaryStage.setScene(scene); 
     primaryStage.setTitle("Login | Administration of Musical Courses"); 

     primaryStage.show(); 
    } 

    // validate here in this method 
    public void validatePassword(TextField password, TextField username) 
     if (checkLogin()) { 
      new Alert(Alert.AlertType.ERROR); 
     } 
    } 

    public boolean checkLogin(){ 
     return BCrypt.checkpw(password.getText(), dbHandler.getLoginByUsername(username.getText()).getPassword()); 
    } 
} 

:

여기에 지금까지 내 코드입니다. 어떻게 든 데이터베이스를 호출하면 작업이 실패 할 가능성이 있습니까? 코드가 작동하도록 변경하려면 어떻게합니까?

답변

3

call() 메서드에서 예외가 throw 된 경우에만 작업이 실패한 상태가됩니다.

validatePassword.setOnFailed(eee->{ // if it fails (that will be indicated by the returned alert message) 
    System.out.println("Failed"); 
    validatePassword.getException().printStackTrace(); 
    try { 
     root.getChildren().remove(pb); // remove it anyway but inform your user 
     Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK); 
     alert.showAndWait(); 
    } catch (Exception e1) { 
     e1.printStackTrace(); 
    } 
}); 

난 정말 당신의 validatePassword() 방법을 이해하지 않는다 : 당신은 당신이 다음 read to see what went wrong 수있는 예외의 스택 트레이스를 볼 수 onFailed 핸들러에서 validatePassword.getException().printStackTrace()을 넣을 수 있습니다

if (checkLogin()) { 
    new Alert(...); 
} 

checkLogin() true를 돌려줍니다 , 이것은 Alert을 만들지 만 실제로 사용하지는 않을 것입니다 (당신이 정말로 여기에서 의도하는 것은 무엇입니까?). 이 메서드는 백그라운드 스레드에서 호출되므로 (작업의 call() 메서드에서 호출되기 때문에) FX 응용 프로그램 스레드가 아닌 경우 Alert을 만드는 것은 올바르지 않습니다. 그래서 이것은 예외가 throw 된 것으로 의심됩니다. 이것은 onFailed 핸들러로 당신을 보냅니다 : 스택 추적을 확인하면 이것을 확인합니다.

더 자연스러운 접근 방식은 작업이 로그인하면 다음 onSucceeded 핸들러에서 처리 할 수있는, 성공 여부를 나타내는 Boolean을 반환해야하는 것입니다 :

test.setOnAction(e->{ 
    Platform.runLater(() -> { 
     root.getChildren().add(pb); 
    }); 

    Task<Boolean> validatePassword = new Task<Boolean>(){ 
     @Override 
     protected Boolean call() throws Exception { 
      return checkLogin(); 
     } 
    }; 

    validatePassword.setOnSucceeded(ee->{ // when it finishes successfully 
     // this cannot throw an exception, there is no need for a try-catch; 
     root.getChildren().remove(pb); // remove the progress bar 

     if (validatePassword.getValue()) { 
      User = dbHandler.getPersonByUsername(username.getText()); // Set up global variable 
      Role = dbHandler.getPersonRole(User.getEmail()); 
      MainStage = (Stage) anchorPane.getScene().getWindow(); 
      Parent parent = null; 
      try { 
       parent = FXMLLoader.load(getClass().getResource("/menu.fxml")); 
      } catch (IOException e1) { 
       e1.printStackTrace(); 
      } 
      Scene scene = new Scene(parent); 
      MainStage.setScene(scene); 
      MainStage.setTitle("Menu | Administration of Musical Courses"); 
      MainStage.show(); 
     } else { 
      // handle failed login... this is on the FX Application Thread so 
      // you can show an Alert... 
      Alert alert = new Alert(Alert.AlertType.ERROR, "Wrong Password", ButtonType.OK); 
      alert.show(); 
     } 
    }); 

    validatePassword.setOnFailed(eee->{ 
     // exception was thrown trying to validate password 
     validatePassword.getException().printStackTrace(); 
     // inform user something went wrong... 
     Alert alert = new Alert(Alert.AlertType.ERROR, "Something went wrong", ButtonType.OK); 
     alert.show(); 
    }); 

    new Thread(validatePassword).start(); // add the task to a thread and start it 
}); 
+0

및 James_D 감사합니다, 난 그냥 배우고 멀티 스레딩과 나는 Task 클래스가 다르게 작동한다고 생각했다. 코드를 변경했는데 이제 작동합니다. –

+0

@ TomášZajda 라이프 사이클에 대한 설명은 [수퍼 클래스의 문서, Worker'] (http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Worker.html)를 참조하십시오. –

관련 문제