每次我想要获取登录信息时,JavaFX 任务都会将状态更改为失败

标签 java multithreading javafx task

我正在尝试在 JavaFX 中制作一个带有小进度条的登录页面。但每次我想检查凭据时,任务都会失败并将我扔到 setOnFailed() 方法中。我不知道是什么让它改变它的状态或如何让它工作。

这是迄今为止我的代码:

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());
    }
}

从数据库获取数据时,validatePassword 方法总是失败。调用数据库是否有可能导致任务失败?如何更改代码以使其正常工作?

最佳答案

当且仅当 call() 方法抛出异常时,任务才会进入失败状态。您可以将 validatePassword.getException().printStackTrace() 放入 onFailed 处理程序中以查看异常的堆栈跟踪,然后您可以read to see what went wrong :

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() 方法:

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

如果checkLogin()返回true,这将创建一个Alert,但不会实际使用它(你在这里真正的意图是什么......?)。请注意,此方法是从后台线程调用的(因为它是从任务的 call() 方法调用的),如果您不这样做,则创建 Alert 是非法的在 FX 应用程序线程上。所以我怀疑这会导致抛出异常,从而将您发送到 onFailed 处理程序:检查堆栈跟踪将确认这一点。

更自然的方法是让任务返回一个 Boolean 表示登录是否成功,然后您可以在 onSucceeded 处理程序中处理该值:

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
});

关于每次我想要获取登录信息时,JavaFX 任务都会将状态更改为失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44143340/

相关文章:

javafx - 当移动其中的物体时,如何防止一个组自行移动?

java - 无法在intellij idea上使用javafx

java - 如何为 GetSolr 设置 StandardSSLContextService

java - 如何在java中生成满足泊松分布的随机时间戳

c# - 如何使用多线程 C# 执行控制台应用程序

c++ - QThread在c++中的基本使用

java - 如何在 BorderPane 中重新定位 VBox?

java - 我可以使用 JAXB 将所有 namespace 定义放入顶级元素吗

java - 将值列表从 jsp 传递到 Struts 2 中的 Action 类

java - 如何在 Java 中使用 TwoTuple 集合设置变量?