项目概述
本项目是一个使用 Java Swing 作为图形用户界面库开发的桌面应用程序,它实现了对学生基本信息(如学号、姓名、性别、年龄、专业)的增、删、改、查功能,并将数据持久化存储在本地文件中。
主要技术栈:
- 编程语言: Java
- GUI库: Java Swing
- 数据存储: 本地文本文件 (CSV格式)
- 开发工具: IntelliJ IDEA / Eclipse / VS Code
项目结构
一个良好的项目结构是可维护和可扩展的基础。
StudentManagementSystem/
├── src/
│ ├── main/
│ │ └── java/
│ │ ├── Main.java # 程序入口
│ │ ├── model/
│ │ │ └── Student.java # 学生实体类 (Model)
│ │ ├── view/
│ │ │ ├── MainFrame.java # 主窗口
│ │ │ ├── AddStudentPanel.java # 添加学生面板
│ │ │ └── StudentTablePanel.java # 学生列表表格面板
│ │ └── controller/
│ │ └── StudentController.java # 业务逻辑控制器
│ └── resources/
│ └── students.csv # 数据存储文件
└── README.md # 项目说明文档
核心代码实现
我们将按照MVC(Model-View-Controller)设计模式来组织代码,使结构更清晰。
1. Model (模型层) - Student.java
这个类是数据模型,定义了学生的属性。
// src/main/java/model/Student.java
package model;
public class Student {
private String id;
private String name;
private String gender;
private int age;
private String major;
// 构造方法
public Student(String id, String name, String gender, int age, String major) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
this.major = major;
}
// Getter 和 Setter 方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getMajor() { return major; }
public void setMajor(String major) { this.major = major; }
@Override
public String toString() {
// 用于CSV文件格式化输出
return id + "," + name + "," + gender + "," + age + "," + major;
}
// 从CSV行字符串创建Student对象
public static Student fromString(String line) {
String[] parts = line.split(",");
if (parts.length == 5) {
return new Student(parts[0], parts[1], parts[2], Integer.parseInt(parts[3]), parts[4]);
}
return null;
}
}
2. Controller (控制器层) - StudentController.java
这是业务逻辑的核心,负责处理数据(读取、保存、增删改查)。
// src/main/java/controller/StudentController.java
package controller;
import model.Student;
import view.StudentTablePanel;
import javax.swing.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class StudentController {
private List<Student> students;
private static final String FILE_PATH = "resources/students.csv";
public StudentController() {
students = new ArrayList<>();
loadStudents();
}
// 从文件加载学生数据
private void loadStudents() {
File file = new File(FILE_PATH);
if (!file.exists()) {
try {
file.getParentFile().mkdirs(); // 创建resources目录
file.createNewFile(); // 创建空文件
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "无法创建数据文件!", "错误", JOptionPane.ERROR_MESSAGE);
}
return;
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
Student student = Student.fromString(line);
if (student != null) {
students.add(student);
}
}
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "读取数据文件失败!", "错误", JOptionPane.ERROR_MESSAGE);
}
}
// 保存学生数据到文件
public void saveStudents() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) {
for (Student student : students) {
writer.write(student.toString());
writer.newLine();
}
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "保存数据文件失败!", "错误", JOptionPane.ERROR_MESSAGE);
}
}
// 添加学生
public void addStudent(Student student) {
if (findStudentById(student.getId()) != null) {
JOptionPane.showMessageDialog(null, "学号已存在!", "警告", JOptionPane.WARNING_MESSAGE);
return;
}
students.add(student);
saveStudents();
}
// 删除学生
public void deleteStudent(String id) {
Student student = findStudentById(id);
if (student != null) {
students.remove(student);
saveStudents();
}
}
// 更新学生信息
public void updateStudent(Student updatedStudent) {
Student student = findStudentById(updatedStudent.getId());
if (student != null) {
// 更新信息
student.setName(updatedStudent.getName());
student.setGender(updatedStudent.getGender());
student.setAge(updatedStudent.getAge());
student.setMajor(updatedStudent.getMajor());
saveStudents();
}
}
// 根据ID查找学生
public Student findStudentById(String id) {
for (Student student : students) {
if (student.getId().equals(id)) {
return student;
}
}
return null;
}
// 获取所有学生列表
public List<Student> getAllStudents() {
return students;
}
}
3. View (视图层)
视图层负责显示用户界面。
StudentTablePanel.java - 显示学生列表的表格
// src/main/java/view/StudentTablePanel.java
package view;
import controller.StudentController;
import model.Student;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.List;
public class StudentTablePanel extends JPanel {
private JTable studentTable;
private DefaultTableModel tableModel;
private StudentController controller;
public StudentTablePanel(StudentController controller) {
this.controller = controller;
setLayout(new BorderLayout());
initUI();
refreshTable();
}
private void initUI() {
// 表格模型
String[] columnNames = {"学号", "姓名", "性别", "年龄", "专业"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false; // 所有单元格不可编辑
}
};
studentTable = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(studentTable);
add(scrollPane, BorderLayout.CENTER);
}
public void refreshTable() {
tableModel.setRowCount(0); // 清空现有数据
List<Student> students = controller.getAllStudents();
for (Student student : students) {
Object[] row = {
student.getId(),
student.getName(),
student.getGender(),
student.getAge(),
student.getMajor()
};
tableModel.addRow(row);
}
}
// 获取当前选中的学生
public Student getSelectedStudent() {
int selectedRow = studentTable.getSelectedRow();
if (selectedRow != -1) {
String id = (String) tableModel.getValueAt(selectedRow, 0);
return controller.findStudentById(id);
}
return null;
}
}
AddStudentPanel.java - 添加/编辑学生的表单
// src/main/java/view/AddStudentPanel.java
package view;
import controller.StudentController;
import model.Student;
import javax.swing.*;
import java.awt.*;
public class AddStudentPanel extends JPanel {
private JTextField idField, nameField, ageField, majorField;
private JComboBox<String> genderComboBox;
private StudentController controller;
private boolean isEditMode = false;
private String editingId = null;
public AddStudentPanel(StudentController controller) {
this.controller = controller;
setLayout(new GridBagLayout());
initUI();
}
private void initUI() {
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = GridBagConstraints.WEST;
// 学号
gbc.gridx = 0;
gbc.gridy = 0;
add(new JLabel("学号:"), gbc);
gbc.gridx = 1;
idField = new JTextField(15);
add(idField, gbc);
// 姓名
gbc.gridx = 0;
gbc.gridy = 1;
add(new JLabel("姓名:"), gbc);
gbc.gridx = 1;
nameField = new JTextField(15);
add(nameField, gbc);
// 性别
gbc.gridx = 0;
gbc.gridy = 2;
add(new JLabel("性别:"), gbc);
gbc.gridx = 1;
genderComboBox = new JComboBox<>(new String[]{"男", "女"});
add(genderComboBox, gbc);
// 年龄
gbc.gridx = 0;
gbc.gridy = 3;
add(new JLabel("年龄:"), gbc);
gbc.gridx = 1;
ageField = new JTextField(15);
add(ageField, gbc);
// 专业
gbc.gridx = 0;
gbc.gridy = 4;
add(new JLabel("专业:"), gbc);
gbc.gridx = 1;
majorField = new JTextField(15);
add(majorField, gbc);
}
public void clearForm() {
idField.setText("");
nameField.setText("");
genderComboBox.setSelectedIndex(0);
ageField.setText("");
majorField.setText("");
isEditMode = false;
editingId = null;
}
public void fillForm(Student student) {
idField.setText(student.getId());
nameField.setText(student.getName());
genderComboBox.setSelectedItem(student.getGender());
ageField.setText(String.valueOf(student.getAge()));
majorField.setText(student.getMajor());
isEditMode = true;
editingId = student.getId();
}
public Student getStudentFromForm() {
try {
String id = idField.getText().trim();
String name = nameField.getText().trim();
String gender = (String) genderComboBox.getSelectedItem();
int age = Integer.parseInt(ageField.getText().trim());
String major = majorField.getText().trim();
if (id.isEmpty() || name.isEmpty() || major.isEmpty()) {
throw new IllegalArgumentException("学号、姓名和专业不能为空!");
}
return new Student(id, name, gender, age, major);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "年龄必须为数字!", "输入错误", JOptionPane.ERROR_MESSAGE);
return null;
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(this, e.getMessage(), "输入错误", JOptionPane.ERROR_MESSAGE);
return null;
}
}
public boolean isEditMode() {
return isEditMode;
}
public String getEditingId() {
return editingId;
}
}
MainFrame.java - 主窗口
// src/main/java/view/MainFrame.java
package view;
import controller.StudentController;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainFrame extends JFrame {
private StudentController controller;
private StudentTablePanel tablePanel;
private AddStudentPanel addPanel;
public MainFrame() {
controller = new StudentController();
setTitle("学生信息管理系统");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
initUI();
}
private void initUI() {
// 使用JSplitPane分割面板
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setDividerLocation(500);
splitPane.setResizeWeight(0.7);
// 左侧:表格
tablePanel = new StudentTablePanel(controller);
splitPane.setLeftComponent(new JScrollPane(tablePanel));
// 右侧:添加/编辑表单
addPanel = new AddStudentPanel(controller);
splitPane.setRightComponent(addPanel);
add(splitPane, BorderLayout.CENTER);
// 底部:按钮
JPanel buttonPanel = new JPanel();
JButton addButton = new JButton("添加");
JButton updateButton = new JButton("修改");
JButton deleteButton = new JButton("删除");
JButton clearButton = new JButton("清空");
buttonPanel.add(addButton);
buttonPanel.add(updateButton);
buttonPanel.add(deleteButton);
buttonPanel.add(clearButton);
add(buttonPanel, BorderLayout.SOUTH);
// 添加事件监听器
addButton.addActionListener(new AddButtonListener());
updateButton.addActionListener(new UpdateButtonListener());
deleteButton.addActionListener(new DeleteButtonListener());
clearButton.addActionListener(e -> addPanel.clearForm());
}
private class AddButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Student student = addPanel.getStudentFromForm();
if (student != null) {
controller.addStudent(student);
tablePanel.refreshTable();
addPanel.clearForm();
JOptionPane.showMessageDialog(MainFrame.this, "添加成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
}
}
}
private class UpdateButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (!addPanel.isEditMode()) {
Student selected = tablePanel.getSelectedStudent();
if (selected == null) {
JOptionPane.showMessageDialog(MainFrame.this, "请先选择要修改的学生!", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
addPanel.fillForm(selected);
} else {
Student student = addPanel.getStudentFromForm();
if (student != null) {
controller.updateStudent(student);
tablePanel.refreshTable();
addPanel.clearForm();
JOptionPane.showMessageDialog(MainFrame.this, "修改成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
private class DeleteButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Student selected = tablePanel.getSelectedStudent();
if (selected == null) {
JOptionPane.showMessageDialog(MainFrame.this, "请先选择要删除的学生!", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
int confirm = JOptionPane.showConfirmDialog(MainFrame.this,
"确定要删除学号为 " + selected.getId() + " 的学生吗?",
"确认删除", JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
controller.deleteStudent(selected.getId());
tablePanel.refreshTable();
addPanel.clearForm();
JOptionPane.showMessageDialog(MainFrame.this, "删除成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
4. 程序入口 - Main.java
// src/main/java/Main.java
package main;
import view.MainFrame;
public class Main {
public static void main(String[] args) {
// 设置界面风格 (可选)
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 在事件分发线程中创建和显示GUI
SwingUtilities.invokeLater(() -> {
MainFrame mainFrame = new MainFrame();
mainFrame.setVisible(true);
});
}
}
功能演示
- 运行程序:编译并运行
Main.java。 - 主界面:会弹出一个窗口,左侧是学生列表表格,右侧是添加/编辑表单。
- 添加学生:在右侧表单中填写信息,点击“添加”按钮,成功后,左侧表格会刷新显示新学生。
- 修改学生:在左侧表格中点击选中一行,然后点击“修改”按钮,右侧表单会自动填充该学生的信息,修改后再次点击“修改”按钮保存更改。
- 删除学生:在左侧表格中选中一行,点击“删除”按钮,确认后即可删除。
- 数据持久化:关闭程序后,重新打开,之前添加的学生信息依然存在,因为数据保存在
students.csv文件中。
可能的扩展方向
这个基础版本已经实现了核心功能,但还有很多可以优化的地方:
-
数据库集成:
- 将
StudentController中的文件操作替换为数据库操作(如 MySQL, PostgreSQL)。 - 使用 JDBC 或 JPA (如 Hibernate) 来管理数据,这样数据管理更安全、更高效,也更适合大规模数据。
- 将
-
增强查询功能:
在主界面添加一个搜索框,支持按学号、姓名等关键字进行模糊查询。
-
界面美化:
- 使用
FlatLaf等第三方皮肤库来美化界面。 - 添加图标、使用更现代的布局管理器(如
MigLayout或GridBagLayout的高级用法)。
- 使用
-
功能扩展:
- 成绩管理:增加对课程和成绩的管理,一个学生可以有多门课程的成绩。
- 统计与报表:添加统计功能,如按专业统计人数、计算平均年龄等,并以图表形式展示(可以使用 JFreeChart 库)。
- 用户登录:增加一个简单的登录系统,区分管理员和普通用户角色,实现权限控制。
-
代码优化:
- 异常处理:更细致地处理各种异常情况。
- 日志记录:使用
java.util.logging或Log4j等框架记录程序运行日志,方便排查问题。 - 单元测试:为
StudentController等核心类编写 JUnit 测试用例,确保代码质量。
这个项目非常适合作为Java课程设计或个人练习,它涵盖了Java基础、Swing GUI、文件I/O和简单的MVC设计模式,是学习Java桌面应用开发的绝佳起点。
