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
相关产品推荐
相关产品推荐

