我们将创建一个 “学生信息管理系统”,因为它足够简单,可以清晰地展示核心功能,同时又能扩展到更复杂的业务场景。

最终效果预览
项目结构 (MVC 分层)
一个良好的项目结构是可维护和可扩展的基础,我们将项目分为三个主要部分:
StudentManagementSystem/
├── model/ // 模型层:数据和业务逻辑
│ ├── Student.java // 学生实体类
│ └── StudentModel.java // 数据模型,负责数据的增删改查
│
├── view/ // 视图层:用户界面
│ ├── MainFrame.java // 主窗口
│ ├── StudentForm.java // 添加/编辑学生的表单对话框
│ ├── StudentTable.java // 显示学生列表的自定义表格
│ └── components/ // 自定义UI组件 (可选,用于美化)
│
└── controller/ // 控制器层:连接模型和视图
└── StudentController.java // 处理用户事件,调用模型,更新视图
核心代码实现
1. Model (模型层)
Student.java - 学生实体类 这是一个简单的 POJO (Plain Old Java Object),用于存储单个学生的信息。
// model/Student.java
package model;
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
private String studentId;
private String gender;
private int age;
public Student(int id, String name, String studentId, String gender, int age) {
this.id = id;
this.name = name;
this.studentId = studentId;
this.gender = gender;
this.age = age;
}
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getStudentId() { return studentId; }
public void setStudentId(String studentId) { this.studentId = studentId; }
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; }
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", studentId='" + studentId + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
StudentModel.java - 数据模型 这个类负责管理所有的学生数据,它不关心 UI,只提供数据操作接口。
// model/StudentModel.java
package model;
import java.util.ArrayList;
import java.util.List;
public class StudentModel {
private final List<Student> students;
private int nextId = 1;
public StudentModel() {
this.students = new ArrayList<>();
// 初始化一些测试数据
addStudent(new Student(nextId++, "张三", "2025001", "男", 20));
addStudent(new Student(nextId++, "李四", "2025002", "女", 21));
addStudent(new Student(nextId++, "王五", "2025003", "男", 19));
}
public void addStudent(Student student) {
student.setId(nextId++);
students.add(student);
}
public void updateStudent(Student student) {
for (int i = 0; i < students.size(); i++) {
if (students.get(i).getId() == student.getId()) {
students.set(i, student);
break;
}
}
}
public void deleteStudent(int id) {
students.removeIf(student -> student.getId() == id);
}
public Student getStudentById(int id) {
for (Student student : students) {
if (student.getId() == id) {
return student;
}
}
return null;
}
public List<Student> getAllStudents() {
return new ArrayList<>(students); // 返回副本,保证数据安全
}
}
2. View (视图层)
MainFrame.java - 主窗口 这是应用程序的主界面,包含菜单栏、工具栏和学生列表表格。

// view/MainFrame.java
package view;
import controller.StudentController;
import model.StudentModel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainFrame extends JFrame {
private StudentTable studentTable;
private StudentController controller;
public MainFrame(StudentModel model) {
this.controller = new StudentController(model, this);
initUI();
}
private void initUI() {
setTitle("学生信息管理系统");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // 居中显示
// 创建菜单栏
createMenuBar();
// 创建工具栏
createToolBar();
// 创建表格
studentTable = new StudentTable(controller);
JScrollPane scrollPane = new JScrollPane(studentTable);
add(scrollPane, BorderLayout.CENTER);
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("文件");
JMenu editMenu = new JMenu("编辑");
JMenuItem exitItem = new JMenuItem("退出");
JMenuItem addItem = new JMenuItem("添加学生");
JMenuItem editItem = new JMenuItem("编辑学生");
JMenuItem deleteItem = new JMenuItem("删除学生");
exitItem.addActionListener(e -> System.exit(0));
addItem.addActionListener(e -> controller.showAddStudentDialog());
editItem.addActionListener(e -> controller.showEditStudentDialog());
deleteItem.addActionListener(e -> controller.deleteStudent());
fileMenu.add(exitItem);
editMenu.add(addItem);
editMenu.add(editItem);
editMenu.add(deleteItem);
menuBar.add(fileMenu);
menuBar.add(editMenu);
setJMenuBar(menuBar);
}
private void createToolBar() {
JToolBar toolBar = new JToolBar();
JButton addButton = new JButton("添加");
JButton editButton = new JButton("编辑");
JButton deleteButton = new JButton("删除");
addButton.addActionListener(e -> controller.showAddStudentDialog());
editButton.addActionListener(e -> controller.showEditStudentDialog());
deleteButton.addActionListener(e -> controller.deleteStudent());
toolBar.add(addButton);
toolBar.addSeparator();
toolBar.add(editButton);
toolBar.addSeparator();
toolBar.add(deleteButton);
add(toolBar, BorderLayout.NORTH);
}
public StudentTable getStudentTable() {
return studentTable;
}
}
StudentTable.java - 自定义表格
为了方便地获取选中的行数据,我们创建一个继承自 JTable 的自定义表格。
// view/StudentTable.java
package view;
import controller.StudentController;
import model.Student;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.util.List;
public class StudentTable extends JTable {
private StudentTableModel tableModel;
private StudentController controller;
public StudentTable(StudentController controller) {
this.controller = controller;
this.tableModel = new StudentTableModel(controller.getStudentModel().getAllStudents());
setModel(tableModel);
}
public void refreshData(List<Student> students) {
tableModel.setStudents(students);
tableModel.fireTableDataChanged(); // 通知模型数据已更改
}
public Student getSelectedStudent() {
int rowIndex = getSelectedRow();
if (rowIndex != -1) {
return tableModel.getStudentAt(rowIndex);
}
return null;
}
// 表格模型
private static class StudentTableModel extends AbstractTableModel {
private final List<Student> students;
private final String[] columnNames = {"ID", "姓名", "学号", "性别", "年龄"};
public StudentTableModel(List<Student> students) {
this.students = students;
}
public void setStudents(List<Student> students) {
this.students.clear();
this.students.addAll(students);
}
public Student getStudentAt(int rowIndex) {
return students.get(rowIndex);
}
@Override
public int getRowCount() {
return students.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Student student = students.get(rowIndex);
switch (columnIndex) {
case 0: return student.getId();
case 1: return student.getName();
case 2: return student.getStudentId();
case 3: return student.getGender();
case 4: return student.getAge();
default: return null;
}
}
}
}
StudentForm.java - 添加/编辑表单 这是一个模态对话框,用于输入或修改学生信息。
// view/StudentForm.java
package view;
import model.Student;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class StudentForm extends JDialog {
private JTextField nameField, studentIdField, ageField;
private JComboBox<String> genderCombo;
private JButton saveButton, cancelButton;
private Student studentToEdit;
public StudentForm(Frame owner, String title, boolean modal) {
super(owner, title, modal);
initUI();
}
private void initUI() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = GridBagConstraints.WEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
// 表单字段
gbc.gridx = 0; gbc.gridy = 0; add(new JLabel("姓名:"), gbc);
gbc.gridx = 1; gbc.gridy = 0; nameField = new JTextField(20); add(nameField, gbc);
gbc.gridx = 0; gbc.gridy = 1; add(new JLabel("学号:"), gbc);
gbc.gridx = 1; gbc.gridy = 1; studentIdField = new JTextField(20); add(studentIdField, gbc);
gbc.gridx = 0; gbc.gridy = 2; add(new JLabel("性别:"), gbc);
gbc.gridx = 1; gbc.gridy = 2; genderCombo = new JComboBox<>(new String[]{"男", "女"}); add(genderCombo, gbc);
gbc.gridx = 0; gbc.gridy = 3; add(new JLabel("年龄:"), gbc);
gbc.gridx = 1; gbc.gridy = 3; ageField = new JTextField(20); add(ageField, gbc);
// 按钮
gbc.gridx = 0; gbc.gridy = 4; gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
JPanel buttonPanel = new JPanel();
saveButton = new JButton("保存");
cancelButton = new JButton("取消");
buttonPanel.add(saveButton);
buttonPanel.add(cancelButton);
add(buttonPanel, gbc);
// 按钮事件
saveButton.addActionListener(e -> {
if (validateInput()) {
saveStudent();
dispose();
}
});
cancelButton.addActionListener(e -> dispose());
pack();
setLocationRelativeTo(getOwner());
}
private boolean validateInput() {
if (nameField.getText().trim().isEmpty() || studentIdField.getText().trim().isEmpty() || ageField.getText().trim().isEmpty()) {
JOptionPane.showMessageDialog(this, "所有字段都必须填写!", "错误", JOptionPane.ERROR_MESSAGE);
return false;
}
try {
Integer.parseInt(ageField.getText());
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "年龄必须是数字!", "错误", JOptionPane.ERROR_MESSAGE);
return false;
}
return true;
}
private void saveStudent() {
String name = nameField.getText();
String studentId = studentIdField.getText();
String gender = (String) genderCombo.getSelectedItem();
int age = Integer.parseInt(ageField.getText());
if (studentToEdit == null) {
// 新增
controller.addStudent(new Student(0, name, studentId, gender, age));
} else {
// 编辑
studentToEdit.setName(name);
studentToEdit.setStudentId(studentId);
studentToEdit.setGender(gender);
studentToEdit.setAge(age);
controller.updateStudent(studentToEdit);
}
}
public void setStudent(Student student) {
this.studentToEdit = student;
if (student != null) {
nameField.setText(student.getName());
studentIdField.setText(student.getStudentId());
genderCombo.setSelectedItem(student.getGender());
ageField.setText(String.valueOf(student.getAge()));
setTitle("编辑学生信息");
} else {
clearForm();
setTitle("添加学生信息");
}
}
private void clearForm() {
nameField.setText("");
studentIdField.setText("");
genderCombo.setSelectedIndex(0);
ageField.setText("");
}
// 为了让表单能调用控制器,需要设置控制器
public void setController(controller.StudentController controller) {
this.controller = controller;
}
// 注意:这里需要声明 controller 变量
private controller.StudentController controller;
}
3. Controller (控制器层)
StudentController.java - 控制器 这是整个系统的核心,它接收来自视图的用户操作,调用模型进行数据处理,然后通知视图更新。
// controller/StudentController.java
package controller;
import model.Student;
import model.StudentModel;
import view.MainFrame;
import view.StudentForm;
public class StudentController {
private final StudentModel model;
private final MainFrame view;
private StudentForm studentForm;
public StudentController(StudentModel model, MainFrame view) {
this.model = model;
this.view = view;
// 初始化表单对话框
this.studentForm = new StudentForm(view, "学生信息", true);
this.studentForm.setController(this); // 将控制器设置给表单
}
public void showAddStudentDialog() {
studentForm.setStudent(null); // 清空表单,准备新增
studentForm.setVisible(true);
}
public void showEditStudentDialog() {
Student selectedStudent = view.getStudentTable().getSelectedStudent();
if (selectedStudent != null) {
studentForm.setStudent(selectedStudent); // 填充表单,准备编辑
studentForm.setVisible(true);
} else {
JOptionPane.showMessageDialog(view, "请先选择一个学生!", "提示", JOptionPane.INFORMATION_MESSAGE);
}
}
public void deleteStudent() {
Student selectedStudent = view.getStudentTable().getSelectedStudent();
if (selectedStudent != null) {
int confirm = JOptionPane.showConfirmDialog(view,
"确定要删除学生 " + selectedStudent.getName() + " 吗?",
"确认删除",
JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION) {
model.deleteStudent(selectedStudent.getId());
refreshStudentTable();
}
} else {
JOptionPane.showMessageDialog(view, "请先选择一个学生!", "提示", JOptionPane.INFORMATION_MESSAGE);
}
}
public void addStudent(Student student) {
model.addStudent(student);
refreshStudentTable();
}
public void updateStudent(Student student) {
model.updateStudent(student);
refreshStudentTable();
}
private void refreshStudentTable() {
view.getStudentTable().refreshData(model.getAllStudents());
}
public StudentModel getStudentModel() {
return model;
}
}
入口类 (App.java)
我们创建一个主类来启动应用程序。
// App.java
import controller.StudentController;
import model.StudentModel;
import view.MainFrame;
import javax.swing.*;
public class App {
public static void main(String[] args) {
// 设置 Swing 的外观风格,使其更现代化
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 在事件调度线程中创建和显示 GUI,这是 Swing 的标准做法
SwingUtilities.invokeLater(() -> {
StudentModel model = new StudentModel();
MainFrame view = new MainFrame(model);
StudentController controller = new StudentController(model, view);
view.setVisible(true);
});
}
}
如何运行
- 创建项目: 在你的 IDE (如 IntelliJ IDEA, Eclipse) 中创建一个新的 Java 项目。
- 创建包: 按照上面的项目结构创建
model,view,controller包。 - 复制代码: 将上面的 Java 代码分别复制到对应的文件中。
- 运行: 运行
App.java文件。
扩展与改进建议
这个基础系统已经具备了核心功能,你可以在此基础上进行扩展:
- 数据持久化: 目前数据存储在内存中,程序关闭后数据会丢失。
- 方案: 使用 Java 序列化将
StudentModel对象保存到文件中,或者在程序启动时从文件读取,更高级的方案是连接数据库(如 MySQL, SQLite)。
- 方案: 使用 Java 序列化将
- 搜索与筛选: 在工具栏添加一个搜索框,可以根据姓名或学号进行实时搜索。
- 分页显示: 如果学生数据量很大,可以实现分页功能,避免一次性加载所有数据。
- UI 美化:
- 使用第三方库如 FlatLaf 提供更现代的界面外观。
- 使用图标来美化按钮和菜单。
- 功能增强:
- 添加“统计”功能,例如按性别、年龄段统计学生人数。
- 添加“导出”功能,将学生列表导出为 Excel 或 CSV 文件。
- 更复杂的 MVC: 对于更庞大的系统,可以将
Controller进一步细分,或者引入观察者模式,让模型在数据变化时主动通知视图,实现更松散的耦合。
这个项目为你提供了一个非常棒的 Java Swing 学习和实践模板,它涵盖了从基础组件到高级设计模式的方方面面,祝你学习愉快!
