JavaFX ListView控制器通信问题及MySQL数据存储、列表填充求解
问题解答
一、JavaFX列表不更新、对象覆盖问题修复
你现在的核心错误是在添加学生的副控制器中重新加载了Main.fxml,拿到的是全新的主控制器实例,不是当前正在运行的主窗口的控制器,所以修改不会反应到原有界面上,打印语句能执行是因为你确实调用了新实例的方法,只是这个实例没有对应展示的窗口。
修复步骤如下:
- 修改主控制器
Events的窗口跳转方法,把当前主控制器实例传给副控制器
public void switchToStudentAdd(ActionEvent e) throws IOException { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("AddStud.fxml")); Parent root = (Parent) fxmlLoader.load(); // 获取副控制器实例,传入当前主控制器 AddStudEvents addController = fxmlLoader.getController(); addController.setMainController(this); Stage stage = new Stage(); stage.setScene(new Scene(root)); stage.show(); }
- 修改副控制器
AddStudEvents,不要重复加载主界面
public class AddStudEvents{ @FXML private TextField firstName; @FXML private TextField lastName; @FXML private Button addStudent; // 新增成员变量存储主控制器引用 private Events mainController; // 新增set方法接收主控制器 public void setMainController(Events mainController) { this.mainController = mainController; } public void addNameToList(ActionEvent e) throws IOException { String name = firstName.getText(); String lastname = lastName.getText(); Student student = new Student(name, lastname); // 直接用传入的主控制器调用方法 mainController.addToNames(student); // 添加完成后关闭当前添加窗口 ((Stage) addStudent.getScene().getWindow()).close(); } }
- 修正主控制器的
addToNames方法,你当前固定添加了字符串xd,替换成学生的真实姓名
public void addToNames(Student student) { nameslist.getItems().add(student.getName() + " " + student.getSurname()); // 同步存入你定义的学生数组 for (int i = 0; i < Students.length; i++) { if (Students[i] == null) { Students[i] = student; break; } } System.out.println(student.getName() + " " + student.getSurname()); }
二、MySQL存储学生数据(含成绩数组)实现
1. 表结构调整
MySQL 5.7及以上版本原生支持JSON类型,你可以直接给student表新增JSON类型的字段存储成绩数组,在SQL Workbench中执行以下SQL即可:
-- 如果还没有建student表执行这个 CREATE TABLE ia.student ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键唯一标识', name VARCHAR(50) NOT NULL COMMENT '姓名', surname VARCHAR(50) NOT NULL COMMENT '姓氏', scores JSON NULL COMMENT '学生成绩数组' ); -- 如果已经建了表只需要加字段执行这个 ALTER TABLE ia.student ADD COLUMN scores JSON NULL COMMENT '学生成绩数组';
2. 改造数据库操作类
import com.alibaba.fastjson2.JSON; // 引入JSON转换工具,也可以用Jackson、Gson等 import java.sql.*; import java.util.ArrayList; import java.util.List; public class DatabaseControl { static String url = "jdbc:mysql://localhost:3306/ia?useUnicode=true&characterEncoding=utf8"; static String username = "root"; static String password = "sifra123"; // 插入单条学生数据的公共方法 public static int insertStudent(Student student) throws SQLException, ClassNotFoundException { Class.forName("com.mysql.jdbc.Driver"); // try-with-resources自动关闭连接,避免资源泄漏 try(Connection connection = DriverManager.getConnection(url, username, password)) { String sql = "INSERT INTO ia.student (name, surname, scores) VALUES (?, ?, ?)"; PreparedStatement ps = connection.prepareStatement(sql); ps.setString(1, student.getName()); ps.setString(2, student.getSurname()); // 把成绩数组转成JSON字符串存入数据库 ps.setString(3, JSON.toJSONString(student.getScores())); return ps.executeUpdate(); } } // 查询所有学生数据的公共方法,用来填充ListView public static List<Student> queryAllStudents() throws SQLException, ClassNotFoundException { List<Student> studentList = new ArrayList<>(); Class.forName("com.mysql.jdbc.Driver"); try(Connection connection = DriverManager.getConnection(url, username, password)) { String sql = "SELECT name, surname, scores FROM ia.student"; ResultSet rs = connection.createStatement().executeQuery(sql); while (rs.next()) { Student student = new Student(rs.getString("name"), rs.getString("surname")); // 把数据库存储的JSON字符串转回Java成绩数组 List<Integer> scores = JSON.parseArray(rs.getString("scores"), Integer.class); student.setScores(scores); // 对应你Student类的setScores方法 studentList.add(student); } } return studentList; } }
3. 实现先存库再加载数据到列表的逻辑
修改副控制器的添加逻辑:
public void addNameToList(ActionEvent e) throws IOException, SQLException, ClassNotFoundException { String name = firstName.getText(); String lastname = lastName.getText(); Student student = new Student(name, lastname); // 先把学生数据存入数据库 DatabaseControl.insertStudent(student); // 调用主控制器方法重新加载全量学生数据刷新列表 mainController.refreshStudentList(); ((Stage) addStudent.getScene().getWindow()).close(); }
在主控制器中新增刷新列表的方法,主界面初始化时也可以调用这个方法加载历史存储的学生数据:
public void refreshStudentList() throws SQLException, ClassNotFoundException { nameslist.getItems().clear(); List<Student> allStudents = DatabaseControl.queryAllStudents(); for (Student stu : allStudents) { nameslist.getItems().add(stu.getName() + " " + stu.getSurname()); } // 同步更新本地的学生数组 Students = allStudents.toArray(new Student[0]); }
补充说明
JSON是一种轻量级的结构化数据格式,数组形式为[90,88,95],把成绩数组转成JSON字符串存储,既可以方便地和Java数组互转,也可以直接用MySQL自带的JSON函数对成绩做统计、查询操作,不需要单独拆分成绩表的情况下是存储数组属性的最优方案。
内容的提问来源于stack exchange,提问作者Tomislav
相关产品推荐
相关产品推荐

