You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX跨场景传递登录用户数据的技术问询

图书馆系统登录用户信息传递方案

问题背景

开发带登录功能的图书馆系统,需在所有场景获取当前登录用户信息,要将LoginController从数据库获取的登录详情,通过SceneController传递给MainController。

解决方案步骤

1. 创建User实体类

先封装用户信息为实体类,便于统一传递:

public class User {
    private int id;
    private String name;
    private String username;

    public User(int id, String name, String username) {
        this.id = id;
        this.name = name;
        this.username = username;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getUsername() {
        return username;
    }
}

2. 修改SceneController,支持传递用户信息

重载switchScene方法,添加User参数,加载FXML时获取目标控制器并注入用户信息:

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import java.io.IOException;

public class SceneController {

    private double xOffset = 0;
    private double yOffset = 0;

    // 带用户参数的场景切换方法
    public void switchScene(Stage stage, String file, User user) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource(file));
        Parent root = loader.load();
        
        // 针对主视图传递用户信息
        if ("main-view.fxml".equals(file)) {
            MainController mainController = loader.getController();
            mainController.setCurrentUser(user);
        }

        // 保留窗口拖拽逻辑
        root.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                xOffset = event.getSceneX();
                yOffset = event.getSceneY();
            }
        });

        root.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                stage.setX(event.getScreenX() - xOffset);
                stage.setY(event.getScreenY() - yOffset);
            }
        });

        stage.setScene(new Scene(root));
        stage.show();
    }

    // 保留原方法兼容无用户参数的场景切换
    public void switchScene(Stage stage, String file) throws IOException {
        switchScene(stage, file, null);
    }
}

3. 修改LoginController,获取并传递用户信息

在登录验证成功后,从数据库结果集中提取用户信息,封装成User对象后传递给SceneController:

import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.event.ActionEvent;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ResourceBundle;
import javafx.stage.Stage;

public class LoginController implements Initializable {
    @FXML
    private Button cancelButton;
    @FXML
    private Button loginButton;
    @FXML
    private Label loginMessageLabel;
    @FXML
    private TextField usernameField;
    @FXML
    private TextField passwordField;

    public void initialize(URL url, ResourceBundle resourceBundle){
    }

    public void loginButtonOnAction(ActionEvent event){
        if(!usernameField.getText().isBlank() && !passwordField.getText().isBlank()){
            validateLogin();
        }else{
            loginMessageLabel.setText("Datele introduse nu sunt corecte!");
        }
    }

    public void cancelButtonOnAction(ActionEvent event){
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
    }

    public void validateLogin(){
        DatabaseConnection connectionNew = new DatabaseConnection();
        Connection connectDB = connectionNew.getConnection();

        // 修改SQL,补充查询username字段
        String verifyLogin = "SELECT count(1), id, name, Username FROM users WHERE Username= '"+usernameField.getText()+"' AND Password ='"+passwordField.getText()+"'";
        System.out.println(verifyLogin);
        try{
            Statement statement = connectDB.createStatement();
            ResultSet queryResult = statement.executeQuery(verifyLogin);

            while(queryResult.next()){
                if(queryResult.getInt(1) == 1){
                    // 提取用户信息并封装
                    int userId = queryResult.getInt("id");
                    String userName = queryResult.getString("name");
                    String userUsername = queryResult.getString("Username");
                    User currentUser = new User(userId, userName, userUsername);

                    Stage stage = (Stage) loginButton.getScene().getWindow();
                    SceneController sceneController = new SceneController();
                    // 调用带用户参数的场景切换方法
                    sceneController.switchScene(stage, "main-view.fxml", currentUser);
                }else{
                    loginMessageLabel.setText("Datele introduse nu sunt corecte!");
                }
            }
        }catch (Exception e){
            throw new RuntimeException("unhandled", e);
        }
    }
}

4. 修改MainController,接收并使用用户信息

添加成员变量存储当前用户,增加set/get方法,并在需要的业务逻辑中使用用户信息:

import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.event.ActionEvent;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ResourceBundle;
import javafx.stage.Stage;

public class MainController implements Initializable {

    private static String paneName;
    private static String defaultImagePath = "C:\\Users\\costi\\Desktop\\LibraryImages\\";
    private static String defaultImageName = "default.png";
    // 存储当前登录用户
    private User currentUser;
    public TableView<Book> tableViewSearch, tableViewHome;
    public TableColumn<Book,String> colSearchTitle, colHomeTitle, colSearchPublicatedOn, colHomePublicatedOn, colSearchPublishingHouse, colHomePublishingHouse, colSearchSummary, colHomeSummary;
    public TableColumn<Book,Integer> colSearchPrice, colHomePrice, colSearchId, colHomeId;
    @FXML
    private Button cancelButton, menuHomeButton, menuSearchButton, borrowBookButton;
    @FXML
    private Pane paneHome, paneSearch, paneBookDetails;
    @FXML
    private TextField searchField, titleField, publishingHouseField, priceField, bookIdField, userIdField;
    @FXML
    private DatePicker publishedOnField;
    @FXML
    private TextArea summaryTextArea;
    @FXML
    private FlowPane flowPaneCoverImage;

    public void initialize(URL url, ResourceBundle resourceBundle) {
        paneHome.toFront();
        setPaneName("paneHome");
        setMainData();
        // 初始化时可显示用户信息(如用户ID)
        if(currentUser != null){
            userIdField.setText(String.valueOf(currentUser.getId()));
        }
    }

    // 设置当前用户
    public void setCurrentUser(User user) {
        this.currentUser = user;
    }

    // 获取当前用户,供其他场景调用
    public User getCurrentUser() {
        return currentUser;
    }

    public void setMainData(){
        colHomeId.setCellValueFactory(new PropertyValueFactory<>("Id"));
        colHomeTitle.setCellValueFactory(new PropertyValueFactory<>("Title"));
        colHomePublicatedOn.setCellValueFactory(new PropertyValueFactory<>("PublicatedOn"));
        colHomePublishingHouse.setCellValueFactory(new PropertyValueFactory<>("PublishingHouse"));
        colHomeSummary.setCellValueFactory(new PropertyValueFactory<>("Summary"));
        colHomePrice.setCellValueFactory(new PropertyValueFactory<>("Price"));
        HomeController homeController = new HomeController();
        tableViewHome.setRowFactory( tv -> {
            TableRow<Book> row = new TableRow<>();
            row.setOnMouseClicked(event -> {
                if (event.getClickCount() == 2 && (! row.isEmpty()) ) {
                    paneBookDetails.toFront();
                    Book rowData = row.getItem();

                    String date = rowData.getPublicatedOn();
                    var dateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
                    var dateTime = LocalDate.parse(date, dateTimeFormatter);

                    bookIdField.setText(Integer.toString(rowData.getId()));
                    titleField.setText(rowData.getTitle());
                    publishingHouseField.setText(rowData.getPublishingHouse());
                    priceField.setText(Integer.toString(rowData.getPrice()));
                    publishedOnField.setValue(dateTime);
                    summaryTextArea.setText(rowData.getSummary());

                    InputStream stream = null;
                    try {
                        stream = new FileInputStream(defaultImagePath + rowData.getCover());
                    } catch (Exception e) {
                        try {
                            stream = new FileInputStream(defaultImagePath + defaultImageName);
                        } catch (Exception ex) {
                        }
                    }

                    Image image = new Image(stream);
                    ImageView imageView = new ImageView(image);
                    imageView.setFitHeight(flowPaneCoverImage.getHeight());
                    imageView.setFitWidth(flowPaneCoverImage.getWidth());
                    flowPaneCoverImage.getChildren().clear();
                    flowPaneCoverImage.getChildren().add(imageView);
                }
            });
            return row ;
        });

        tableViewHome.setItems(homeController.getBooks());
    }

    public void searchButtonOnAction(ActionEvent event) {
        colSearchId.setCellValueFactory(new PropertyValueFactory<>("Id"));
        colSearchTitle.setCellValueFactory(new PropertyValueFactory<>("Title"));
        colSearchPublicatedOn.setCellValueFactory(new PropertyValueFactory<>("PublicatedOn"));
        colSearchPublishingHouse.setCellValueFactory(new PropertyValueFactory<>("PublishingHouse"));
        colSearchSummary.setCellValueFactory(new PropertyValueFactory<>("Summary"));
        colSearchPrice.setCellValueFactory(new PropertyValueFactory<>("Price"));
        tableViewSearch.setRowFactory( tv -> {
            TableRow<Book> row = new TableRow<>();
            row.setOnMouseClicked(ev -> {
                if (ev.getClickCount() == 2 && (! row.isEmpty()) ) {
                    paneBookDetails.toFront();
                    Book rowData = row.getItem();

                    String date = rowData.getPublicatedOn();
                    var dateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
                    var dateTime = LocalDate.parse(date, dateTimeFormatter);

                    bookIdField.setText(Integer.toString(rowData.getId()));
                    titleField.setText(rowData.getTitle());
                    publishingHouseField.setText(rowData.getPublishingHouse());
                    priceField.setText(Integer.toString(rowData.getPrice()));
                    publishedOnField.setValue(dateTime);
                    summaryTextArea.setText(rowData.getSummary());

                    InputStream stream = null;
                    try {
                        stream = new FileInputStream(defaultImagePath + rowData.getCover());
                    } catch (Exception e) {
                        try {
                            stream = new FileInputStream(defaultImagePath + defaultImageName);
                        } catch (Exception ex) {
                        }
                    }

                    Image image = new Image(stream);
                    ImageView imageView = new ImageView(image);
                    imageView.setFitHeight(flowPaneCoverImage.getHeight());
                    imageView.setFitWidth(flowPaneCoverImage.getWidth());
                    flowPaneCoverImage.getChildren().clear();
                    flowPaneCoverImage.getChildren().add(imageView);
                }
            });
            return row ;
        });
        SearchController searchController = new SearchController();
        tableViewSearch.setItems(searchController.getBooks(searchField.getText()));
    }

    public void cancelButtonOnAction(ActionEvent event){
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
    }

    public void menuButtonOnAction(ActionEvent event){
        if(event.getSource() == menuHomeButton){
            setPaneName("paneHome");
            paneHome.toFront();
            setMainData();
        }else if(event.getSource() == menuSearchButton){
            setPaneName("paneSearch");
            paneSearch.toFront();
        }
    }

    public void backButtonOnAction(ActionEvent event){
        var lastPannelName = getPaneName();

        System.out.println(lastPannelName);

        if(lastPannelName.equals("paneHome")){
            paneHome.toFront();
        }else if(lastPannelName.equals("paneSearch")){
            paneSearch.toFront();
        }
    }

    public void borrowBookOnAction(ActionEvent event){
        HomeController homeController = new HomeController();
        var currentBookId = Integer.valueOf(bookIdField.getText());
        // 使用当前登录用户的ID替代硬编码值
        try {
            homeController.borrowBook(currentUser.getId(), currentBookId);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        System.out.println(currentBookId);
    }

    public static String getPaneName() {
        return paneName;
    }

    public void display(String ceva){
        System.out.println(ceva);
    }

    public static void setPaneName(String paneName) {
        MainController.paneName = paneName;
    }
}

额外优化建议

  • 避免SQL注入:当前LoginController中的SQL拼接存在注入风险,建议使用PreparedStatement替代Statement
  • 全局用户管理:如果需要在多个控制器中获取用户信息,可以考虑使用单例类存储当前登录用户,避免多次传递

内容的提问来源于stack exchange,提问作者Kratos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:55:23