我们开始做一些带界面的功能,首先用到了Java自带的界面开发工具Swing

常见组件

  • JFrame:主窗口(整个软件的大框)
  • JButton:按钮(新增、删除、保存)
  • JTextField:单行输入框(输学号、姓名)
  • JLabel:文字标签(提示:学号、姓名)
  • JTable:表格(展示所有学生数据)
  • JOptionPane:弹窗提示(添加成功、确认删除)

V5.0 目标

  1. 弹出登录窗口(账号密码)
  2. 登录成功进入主界面
  3. 主界面包含:
    • 学生表格(展示所有学生)
    • ID、姓名、年龄输入框
    • 添加、删除、修改、刷新按钮
  4. 数据依然存在 MySQL(保留 V4.0 所有数据库功能)
  5. 学到的新知识:
    • Swing 窗体、组件
    • 事件监听(按钮点击)
    • 表格 DefaultTableModel
    • 界面与数据分离

新建类:LoginFrame.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;

public class LoginFrame extends JFrame {
    private JTextField tfUser;
    private JPasswordField tfPwd;

    public LoginFrame() {
        setTitle("管理员登录");
        setSize(300, 200);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null); // 居中

        // 面板
        JPanel panel = new JPanel(new GridLayout(3, 2, 10, 10));
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        // 组件
        panel.add(new JLabel("用户名:"));
        tfUser = new JTextField();
        panel.add(tfUser);

        panel.add(new JLabel("密码:"));
        tfPwd = new JPasswordField();
        panel.add(tfPwd);

        // 按钮
        JButton btnLogin = new JButton("登录");
        btnLogin.addActionListener(this::doLogin);
        panel.add(btnLogin);

        add(panel);
    }

    // 登录逻辑
    private void doLogin(ActionEvent e) {
        String user = tfUser.getText();
        String pwd = new String(tfPwd.getPassword());

        if ("admin".equals(user) && "123456".equals(pwd)) {
            JOptionPane.showMessageDialog(this, "登录成功");
            this.dispose();
            new MainFrame().setVisible(true); // 打开主界面
        } else {
            JOptionPane.showMessageDialog(this, "账号或密码错误");
        }
    }

    public static void main(String[] args) {
        new LoginFrame().setVisible(true);
    }
}

新建类:MainFrame.java

package com.baosight;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.sql.*;
import java.util.Vector;

public class MainFrame extends JFrame {
    private JTable table;
    private DefaultTableModel model;
    private JTextField tfId, tfName, tfAge;

    public MainFrame() {
    setTitle("Student System V5.0");
    setSize(600, 400);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);

    //table
    model = new DefaultTableModel();
    model.setColumnIdentifiers(new String[]{"ID", "Name", "Age"});
    table = new JTable(model);
    JScrollPane sp = new JScrollPane(table);
    //panel
    JPanel panelInput = new JPanel(new FlowLayout());
    panelInput.add(new JLabel("ID:"));
    tfId = new JTextField(5);
    panelInput.add(tfId);

    panelInput.add(new JLabel("Name:"));
    tfName = new JTextField(5);
    panelInput.add(tfName);

    panelInput.add(new JLabel("Age:"));
    tfAge = new JTextField(3);
    panelInput.add(tfAge);
    // button
    JButton btnAdd = new JButton("Add");
    JButton btnUpdate = new JButton("Update");
    JButton btnDelete = new JButton("Delete");
    JButton btnRefresh = new JButton("Refresh");

    JPanel panelBtn = new JPanel();
    panelBtn.add(btnAdd);
    panelBtn.add(btnUpdate);
    panelBtn.add(btnDelete);
    panelBtn.add(btnRefresh);

    // layout
    setLayout(new BorderLayout());
    add(panelInput, BorderLayout.NORTH);
    add(sp, BorderLayout.CENTER);
    add(panelBtn, BorderLayout.SOUTH);

    btnRefresh.addActionListener(this::refresh);
    btnAdd.addActionListener(this::add);
    btnDelete.addActionListener(this::delete);
    btnUpdate.addActionListener(this::update);

    refresh(null);
    }

    //refresh table
    private void refresh(ActionEvent e) {
        model.setRowCount(0);
        try (Connection conn = DBUtil.getConnection();
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("select id, name, age from student")) {
            while (rs.next()) {
                Vector<Object> row = new Vector<>();
                row.add(rs.getString("id"));
                row.add(rs.getString("name"));
                row.add(rs.getInt("age"));
                model.addRow(row);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    private void add(ActionEvent e) {
        String id = tfId.getText();
        String name = tfName.getText();
        String age = tfAge.getText();
        String sql = "insert into student values(?,?,?)";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, id);
            pstmt.setString(2, name);
            pstmt.setString(3, age);
            int count = pstmt.executeUpdate();
            JOptionPane.showMessageDialog(this, "Add successful!");
            refresh(null);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    private void delete(ActionEvent e) {
    int row = table.getSelectedRow();
    if (row == -1) {
        JOptionPane.showMessageDialog(this, "Please select a row to delete.");
        return;
    }
    String id = model.getValueAt(row, 0).toString();
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement("DELETE FROM student WHERE id=?")) {
            pstmt.setString(1, id);
            pstmt.executeUpdate();
            JOptionPane.showMessageDialog(this, "delete successful!");
            refresh(null);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    private void update(ActionEvent e) {
        int row = table.getSelectedRow();
        if (row == -1) {
            JOptionPane.showMessageDialog(this, "Please select a row to update.");
            return;
        }
        String id = tfId.getText();
        String name = tfName.getText();
        String age = tfAge.getText();

        String sql = "update student set name=?, age=? where id=?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, name);
            pstmt.setString(2, age);
            pstmt.setString(3, id);
            pstmt.executeUpdate();
            JOptionPane.showMessageDialog(this, "update successful!");
            refresh(null);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

这段代码,是一个 **「MVC 思想的简化版」**,分成三层:

  1. Swing 视图层:窗口、表格、输入框、按钮(你看到的界面)
  2. 事件控制层:按钮点击、表格选中、输入框交互(响应用户操作)
  3. JDBC 数据层:连接 MySQL、执行 SQL、更新表格数据(和数据库打交道)

它的工作流程是:用户点按钮 → 触发事件方法 → 调用 JDBC 执行SQL → 刷新表格 → 界面更新

我们来仔细讲一个方法实现比如说这个delete

private void delete(ActionEvent e) {
    int row = table.getSelectedRow();
    if (row == -1) {
        JOptionPane.showMessageDialog(this, "Please select a row to delete.");
        return;
    }
    String id = model.getValueAt(row, 0).toString();
    try (Connection conn = DBUtil.getConnection();
         PreparedStatement pstmt = conn.prepareStatement("DELETE FROM student WHERE id=?")) {
        pstmt.setString(1, id);
        pstmt.executeUpdate();
        JOptionPane.showMessageDialog(this, "delete successful!");
        refresh(null);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

  • table.getSelectedRow():获取用户在表格里选中的行号
  • if (row == -1):判断用户有没有选中行,没选就弹提示
  • model.getValueAt(row, 0):从表格模型里,获取选中行第 0 列(ID 列)的值
  • 执行 DELETE SQL,删除数据库里的对应数据
  • 调用 refresh 刷新表格,删除的行就会消失

我们再来看看现在的项目结构

类名 核心作用 程序里的角色
DBUtil 数据库连接工具 「数据层」:提供 JDBC 连接,和 MySQL 打交道
LoginFrame 登录窗口 「入口视图层」:程序启动时的第一个界面,负责账号验证
MainFrame 主界面窗口 「主视图 + 控制层」:增删改查按钮、表格、输入框、业务逻辑都在这里

这个项目已经有MVC的简化版了

MainFrame 里,Controller 和 View 是写在一起的(都在 MainFrame 这一个类里),所以是简化版 MVC。)

MVC 是一种软件设计思想,它把程序分成 3 个部分:

  • M = Model(模型)
  • V = View(视图)
  • C = Controller(控制器)

它的核心目的:把界面、业务逻辑、数据分开,谁也不混在一起,代码好维护、好扩展。

我们对应一下

MVC 部分 项目里对应的是什么 作用
V 视图 View LoginFrameMainFrame 用户看到的界面:窗口、按钮、表格、输入框,只负责显示和接收用户操作
C 控制器 Controller MainFrame 里的按钮事件方法(add/delete/update/refresh) 响应用户操作,调用数据层方法,更新界面
M 模型 Model DBUtil(数据模型)、Student(实体模型) 数据相关的逻辑:连接数据库、执行 SQL、存储学生数据

1. V = View 视图层

  • 代表:LoginFrameMainFrame
  • 只做两件事:
    1. 把界面画出来(按钮、表格、输入框)
    2. 接收用户操作(点按钮、输文字)
  • 它不处理业务逻辑,也不直接操作数据库,只负责 “显示” 和 “传话”
// 这是 View 的事:显示界面、接收输入
tfId = new JTextField(5);
tfName = new JTextField(5);
tfAge = new JTextField(3);

2. C = Controller 控制层

  • 代表:MainFrame 里的 adddeleteupdaterefresh 方法
  • 它是中间的 “指挥者”:
    1. 接收 View 传来的用户操作(比如 “点了添加按钮”)
    2. 调用 Model 里的方法(比如 “执行添加 SQL”)
    3. 操作完成后,通知 View 更新界面(比如 “刷新表格”)
private void add(ActionEvent e) {
    // 1. 从 View 拿用户输入
    String id = tfId.getText();
    String name = tfName.getText();
    String age = tfAge.getText();

    // 2. 调用 Model 层的 JDBC 操作
    try (Connection conn = DBUtil.getConnection();
         PreparedStatement pstmt = conn.prepareStatement(sql)) {
        pstmt.setString(1, id);
        pstmt.setString(2, name);
        pstmt.setString(3, age);
        pstmt.executeUpdate();

        // 3. 通知 View 更新界面
        JOptionPane.showMessageDialog(this, "Add successful!");
        refresh(null);
    }
}

3. M = Model 模型层

  • 代表:DBUtilStudent
  • 它只做两件事:
    1. 数据存储 / 操作DBUtil 连接数据库、执行 SQL
    2. 数据封装Student 类把学生的 id/name/age 打包成对象
  • 它完全不关心界面,只负责 “处理数据”
// DBUtil:Model 层的数据库工具
public static Connection getConnection() {
    // 只做连接数据库这件事
}

// Student:Model 层的实体类
public class Student {
    private String id;
    private String name;
    private int age;
    // 只封装学生数据
}

MVC的优点在于

  • 改界面不用动数据逻辑:以后想把 Swing 换成网页界面,只改 View 层就行,Model 层的 SQL 代码不用动
  • 改数据逻辑不用动界面:以后想换数据库(比如从 MySQL 换成 Oracle),只改 DBUtil 就行,界面不用动
  • 代码清晰,好维护:每个类只做一件事,出问题一眼就能找到在哪
  • 方便团队协作:有人专门写界面,有人专门写数据逻辑,互不干扰
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐