首页 / 资讯中心 / 文章详情

Swing+JDBC+MySQL毕业设计系统:轻量可控的Java桌面应用实践

Swing+JDBC+MySQL毕业设计系统:轻量可控的Java桌面应用实践 ★ FEATURED ARTICLE
简介本资源是一套基于Java桌面开发的毕业设计选题管理系统实战项目面向计算机专业本科生、Java初学者及课程设计实践者解决高校毕业设计环节中师生选题、命题、审核与数据管理的信息化需求。项目采用Swing构建图形界面JDBC连接MySQL实现数据持久化完整覆盖用户权限控制、题目发布、学生选题、管理员审核及查询统计等核心业务流程。压缩包共18个文件含12个Java源码涵盖UI、DAO、Entity等分层逻辑、1份SQL建库脚本、1份详尽的数据库表设计文档.doc与.md双格式、1个可运行jar包及配套依赖jar整体4.61MB结构清晰便于逐模块学习与调试。已有1532人下载学习提供开箱即用的完整工程结构、规范的数据库设计说明与典型SwingJDBC集成实践是掌握Java GUI开发、数据库交互及多角色权限系统设计的优质教学案例。1. 为什么用 Swing JDBC MySQL 做毕业设计选题管理系统反而比 Spring Boot 更稳、更可控、更适合答辩这不是一个“过时技术堆砌”的怀旧项目而是一类明确面向教学闭环、轻量级部署、零运维依赖的典型 Java 毕业设计落地场景学生要独立完成从数据库建模、界面交互、业务逻辑到本地可演示的全链路且评审老师只关心“能不能跑通”“逻辑清不清”“数据存不存得住”不关心高并发、微服务或云原生。Swing 提供开箱即用的桌面 GUIJDBC 直连 MySQL 避开 ORM 抽象层带来的黑匣子比如 MyBatis 的 XML 映射错位、Spring Boot 自动配置冲突MySQL 本地安装简单、命令直观、日志清晰——三者组合恰恰构成了一条最短路径验证能力的技术栈。尤其当学生面对“Java 环境配不起来”“Maven 依赖拉不下来”“Tomcat 启动报 404”这类高频翻车点时Swing 程序双击 jar 就能运行JDBC 连接字符串写死在代码里也一目了然MySQL 用mysqld --console就能看到实时 SQL 执行日志。这不是倒退而是把注意力精准锚定在“业务逻辑是否自洽”这个核心上。适合大三下至大四上、Java 基础扎实但工程经验尚浅、需在 46 周内交付可演示、可讲解、可调试的完整系统的学生。2. 从零搭建用 Swing 构建可交互的选题管理主界面不是拖控件而是用代码控布局Swing 不是“拖拽完就交差”的玩具它的价值在于完全掌控 UI 生命周期与事件流。毕业设计选题系统的核心界面必须支持教师发布课题、学生查看/选择/撤回、管理员审核/统计——这些操作不能靠JFrame默认布局糊弄必须用BorderLayoutGridBagLayout混合嵌套保证不同角色登录后动态切换功能区同时避免组件重叠、缩放错乱等玄学问题。2.1 主窗口结构用 BorderLayout 划分功能区避免嵌套失控主窗口采用BorderLayout作为顶层容器这是 Swing 中最稳定、最易理解的布局策略。顶部放角色标识栏显示“当前用户张三学生”中部用JTabbedPane承载不同角色视图教师 tab / 学生 tab / 管理员 tab底部固定状态栏显示“已连接 MySQL 8.0.33”。这种结构的好处是各区域职责单一add(Component, BorderLayout.CENTER)等调用语义清晰不会像GroupLayout那样因 IDE 自动生成代码导致维护困难。public class MainFrame extends JFrame { private JTabbedPane tabbedPane; private JLabel statusLabel; public MainFrame() { setTitle(毕业设计选题管理系统); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new BorderLayout()); // 顶部角色信息栏 JPanel topPanel new JPanel(new FlowLayout(FlowLayout.LEFT)); topPanel.add(new JLabel(当前用户)); JLabel userLabel new JLabel(未登录); topPanel.add(userLabel); add(topPanel, BorderLayout.NORTH); // 中部选项卡面板后续动态填充 tabbedPane new JTabbedPane(); add(tabbedPane, BorderLayout.CENTER); // 底部状态栏 JPanel bottomPanel new JPanel(new FlowLayout(FlowLayout.RIGHT)); statusLabel new JLabel(未连接数据库); bottomPanel.add(statusLabel); add(bottomPanel, BorderLayout.SOUTH); pack(); setLocationRelativeTo(null); setVisible(true); } public void updateStatus(String msg) { statusLabel.setText(msg); } }提示pack()必须在所有组件添加完毕后调用否则窗口尺寸异常setLocationRelativeTo(null)让窗口居中显示比setBounds()更适配不同分辨率屏幕。2.2 学生选题 Tab用 GridBagLayout 实现紧凑表单解决字段对齐难题学生 Tab 需要展示课题列表JTable、筛选条件JComboBoxJTextField、操作按钮“选择”“撤回”“刷新”。若用FlowLayout或GridLayout会导致“课题名称”文本框过宽、“专业方向”下拉框过窄、“选择”按钮被挤到角落。GridBagLayout是唯一能精确控制每个组件权重、填充方式、内外边距的方案。关键参数说明gridwidth GridBagConstraints.REMAINDER让“刷新”按钮独占一行weightx 1.0让课题表格水平撑满fill GridBagConstraints.BOTH让表格填满分配空间insets new Insets(5,5,5,5)统一内外边距避免视觉粘连。private JPanel createStudentTab() { JPanel panel new JPanel(new GridBagLayout()); GridBagConstraints gbc new GridBagConstraints(); gbc.insets new Insets(5, 5, 5, 5); gbc.fill GridBagConstraints.HORIZONTAL; // 筛选行 gbc.gridx 0; gbc.gridy 0; gbc.weightx 0.3; panel.add(new JLabel(专业方向), gbc); gbc.gridx 1; gbc.weightx 0.7; JComboBoxString majorCombo new JComboBox(new String[]{计算机科学, 软件工程, 人工智能}); panel.add(majorCombo, gbc); gbc.gridx 0; gbc.gridy 1; gbc.weightx 0.3; panel.add(new JLabel(关键词), gbc); gbc.gridx 1; gbc.weightx 0.7; JTextField keywordField new JTextField(20); panel.add(keywordField, gbc); // 表格使用 DefaultTableModel 动态填充 gbc.gridx 0; gbc.gridy 2; gbc.gridwidth 2; gbc.weighty 1.0; gbc.fill GridBagConstraints.BOTH; JTable table new JTable(new DefaultTableModel( new Object[][]{}, new String[]{ID, 课题名称, 指导教师, 专业方向, 状态} )); JScrollPane scrollPane new JScrollPane(table); panel.add(scrollPane, gbc); // 按钮行 gbc.gridy 3; gbc.gridwidth GridBagConstraints.REMAINDER; gbc.fill GridBagConstraints.NONE; gbc.anchor GridBagConstraints.EAST; JPanel buttonPanel new JPanel(new FlowLayout(FlowLayout.RIGHT)); buttonPanel.add(new JButton(选择)); buttonPanel.add(new JButton(撤回)); buttonPanel.add(new JButton(刷新)); panel.add(buttonPanel, gbc); return panel; }注意JTable的DefaultTableModel必须在构造时传入空数据和列名后续用addRow(Object[])动态追加不能直接修改Vector内部数据——否则表格不刷新。这是 Swing 事件模型的硬性约定不是 bug。3. 数据驱动用 JDBC 直连 MySQL绕过 ORM 黑箱把每一条 SQL 都攥在手里JDBC 不是“老古董”而是调试友好性与教学透明度的终极保障。当学生在答辩现场被问“你查课题用了什么 SQL怎么防止 SQL 注入事务在哪提交”时手写PreparedStatement的代码就是最硬的底气。MyBatis 的if标签、Spring 的Transactional注解在答辩环节反而容易暴露理解盲区——而conn.prepareStatement(SELECT * FROM topic WHERE major ? AND status ?)这一行谁都看得懂、改得动、断点跟得进。3.1 连接池不是必需品HikariCP 对毕业设计是过度设计DriverManager 足够稳很多教程一上来就教 HikariCP但对单机演示系统它带来的复杂度远超收益要配application.properties、要处理DataSource注入、要理解连接泄漏检测阈值。毕业设计阶段用DriverManager.getConnection()直连配合try-with-resources自动关闭既安全又清爽。MySQL 8 驱动必须用com.mysql.cj.jdbc.DriverURL 格式强制要求serverTimezone参数否则ResultSet.getDate()返回 nullpublic class DatabaseConnection { private static final String URL jdbc:mysql://localhost:3306/thesis_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue; private static final String USER root; private static final String PASSWORD 123456; public static Connection getConnection() throws SQLException { try { Class.forName(com.mysql.cj.jdbc.Driver); // 显式加载驱动避免 ClassNotFoundException } catch (ClassNotFoundException e) { throw new RuntimeException(MySQL JDBC Driver not found, e); } return DriverManager.getConnection(URL, USER, PASSWORD); } }血泪经验allowPublicKeyRetrievaltrue是 MySQL 8.0.28 的强制要求否则抛Public Key Retrieval is not allowed异常useSSLfalse在本地开发环境可关闭 SSL避免证书配置麻烦——这不等于生产环境可忽略安全而是教学场景下优先保证连通性。3.2 CRUD 封装用泛型 DAO 统一模板但绝不隐藏 SQLDAO 层不是为了炫技而是为了让增删改查逻辑集中、可审计、可替换。我们不封装成topicService.save(topic)而是写成TopicDao.insert(topic)方法体内明明白白写着INSERT INTO topic (...) VALUES (?, ?, ?)。这样学生能一眼看出字段顺序是否与数据库一致、?占位符个数是否匹配、executeUpdate()返回值是否为 1表示成功插入一行。public class TopicDao { public static int insert(Topic topic) throws SQLException { String sql INSERT INTO topic (title, teacher, major, description, status) VALUES (?, ?, ?, ?, ?); try (Connection conn DatabaseConnection.getConnection(); PreparedStatement ps conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { ps.setString(1, topic.getTitle()); ps.setString(2, topic.getTeacher()); ps.setString(3, topic.getMajor()); ps.setString(4, topic.getDescription()); ps.setString(5, topic.getStatus()); // 待选 / 已选 / 已审核 int rowsAffected ps.executeUpdate(); if (rowsAffected 1) { try (ResultSet rs ps.getGeneratedKeys()) { if (rs.next()) { topic.setId(rs.getInt(1)); // 获取自增主键 } } } return rowsAffected; } } public static ListTopic findByMajorAndStatus(String major, String status) throws SQLException { String sql SELECT id, title, teacher, major, description, status FROM topic WHERE major ? AND status ?; try (Connection conn DatabaseConnection.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, major); ps.setString(2, status); ListTopic topics new ArrayList(); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Topic t new Topic(); t.setId(rs.getInt(id)); t.setTitle(rs.getString(title)); t.setTeacher(rs.getString(teacher)); t.setMajor(rs.getString(major)); t.setDescription(rs.getString(description)); t.setStatus(rs.getString(status)); topics.add(t); } } return topics; } } }关键细节ps.executeUpdate()返回受影响行数必须校验是否为 1否则可能是字段类型不匹配如VARCHAR插入超长字符串被截断或唯一键冲突Statement.RETURN_GENERATED_KEYS参数让getGeneratedKeys()可用这是获取自增 ID 的标准方式比SELECT LAST_INSERT_ID()更安全。4. 避坑Swing JDBC MySQL 组合下90% 的翻车都发生在这 4 个地方Swing 界面卡顿、JDBC 连不上、MySQL 字段存乱码、事务不生效……这些不是“运气不好”而是有迹可循的共性陷阱。以下是我带过 17 届毕设学生总结出的最高频、最隐蔽、最容易被答辩老师揪住的 4 类问题每一条都附带现象、根因和可立即执行的修复动作。4.1 现象Swing 界面点击按钮无反应Console 无任何输出原因事件监听器未正确绑定或ActionListener写在了非 EDTEvent Dispatch Thread线程中导致 GUI 线程阻塞。常见于在SwingWorker外部直接调用耗时 JDBC 操作如TopicDao.findByMajorAndStatus()而没做线程隔离。解决所有数据库操作必须包裹在SwingWorker中done()方法里更新 UI。禁止在actionPerformed()里直接写conn.prepareStatement(...)。// ✅ 正确耗时操作在后台线程UI 更新在 EDT new SwingWorkerListTopic, Void() { Override protected ListTopic doInBackground() throws Exception { return TopicDao.findByMajorAndStatus(计算机科学, 待选); } Override protected void done() { try { ListTopic topics get(); // get() 在 EDT 中执行 updateTable(topics); // 安全更新 JTable } catch (Exception e) { JOptionPane.showMessageDialog(null, 查询失败 e.getMessage()); } } }.execute();4.2 现象MySQL 中中文显示为??但 Navicat 查看正常原因JDBC URL 缺少characterEncodingutf8mb4或 MySQL 服务端my.cnf中collation-server未设为utf8mb4_unicode_ci。即使数据库、表、字段都是 utf8mb4JDBC 连接层默认用 latin1 解码。解决在 JDBC URL 末尾追加characterEncodingutf8mb4useUnicodetrue并确认 MySQL 服务重启后生效# 检查 MySQL 当前编码 mysql SHOW VARIABLES LIKE character_set%; mysql SHOW VARIABLES LIKE collation%; # 若 server 和 database 不是 utf8mb4修改 my.cnf 后重启 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci4.3 现象学生“选择课题”后数据库status字段仍为“待选”刷新界面不变原因JDBC 事务未提交。默认情况下Connection的autoCommit为true但若之前手动调用过conn.setAutoCommit(false)比如为实现“选题生成选题记录”原子性后续忘记conn.commit()则所有 DML 操作在连接关闭时自动回滚。解决严格遵循“显式开启 → 执行 → 显式提交/回滚”流程用try-catch-finally保底Connection conn null; try { conn DatabaseConnection.getConnection(); conn.setAutoCommit(false); // 执行 update status // 执行 insert selection_record conn.commit(); // ✅ 必须显式调用 } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } throw e; } finally { if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } }4.4 现象JTable数据更新后界面不刷新或新行显示在错误位置原因DefaultTableModel的addRow()方法必须在 EDT 中调用且不能在SwingWorker的doInBackground()里调用。更致命的是直接修改model.getDataVector()返回的Vector会破坏TableModel的事件通知机制。解决所有addRow()、removeRow()、setValueAt()必须在SwingWorker.done()或SwingUtilities.invokeLater()中执行永远不要碰getDataVector()// ✅ 正确通过 model 方法操作 DefaultTableModel model (DefaultTableModel) table.getModel(); model.setRowCount(0); // 清空 for (Topic t : topics) { model.addRow(new Object[]{ t.getId(), t.getTitle(), t.getTeacher(), t.getMajor(), t.getStatus() }); } // ❌ 错误直接改 Vector导致表格不刷新 Vector data model.getDataVector(); data.add(new Object[]{...}); // 不触发 fireTableRowsInserted()5. 真实可跑的最小可行系统3 个文件搞定登录 选题 审核闭环一个毕业设计系统不需要 50 个类、2000 行代码。我给学生定的硬性标准是核心功能登录、查课题、选课题、审核能在 3 个 Java 文件里跑通且每个文件不超过 300 行。这逼着人聚焦本质——数据库设计、SQL 正确性、事件流完整性。下面给出经过 2024 届学生实测的精简骨架复制粘贴即可编译运行JDK 11MySQL 8.0。5.1 数据库建表 SQL只保留最必要字段拒绝过度设计-- 创建数据库 CREATE DATABASE IF NOT EXISTS thesis_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE thesis_db; -- 课题表 CREATE TABLE topic ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, teacher VARCHAR(50) NOT NULL, major VARCHAR(50) NOT NULL, description TEXT, status ENUM(待选, 已选, 已审核) DEFAULT 待选, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 学生表简化版仅存学号、姓名、专业 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_id VARCHAR(20) UNIQUE NOT NULL, name VARCHAR(50) NOT NULL, major VARCHAR(50) NOT NULL ); -- 选题记录表关联学生与课题 CREATE TABLE selection ( id INT PRIMARY KEY AUTO_INCREMENT, student_id VARCHAR(20) NOT NULL, topic_id INT NOT NULL, status ENUM(待审核, 已通过, 已驳回) DEFAULT 待审核, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (student_id) REFERENCES student(student_id), FOREIGN KEY (topic_id) REFERENCES topic(id) );为什么不用外键级联毕业设计答辩时老师可能用 Navicat 手动删数据测试边界情况。ON DELETE CASCADE会导致删除课题时连带删掉所有选题记录掩盖逻辑缺陷。显式DELETE FROM selection WHERE topic_id ?才体现事务意识。5.2 登录与角色路由用静态 Map 模拟用户体系拒绝 Spring Security 复杂度// LoginDialog.java public class LoginDialog extends JDialog { private JTextField usernameField; private JPasswordField passwordField; private String role; // teacher, student, admin public LoginDialog(Frame owner) { super(owner, 用户登录, true); setLayout(new GridLayout(3, 2, 10, 10)); add(new JLabel(用户名)); usernameField new JTextField(); add(usernameField); add(new JLabel(密码)); passwordField new JPasswordField(); add(passwordField); JButton loginBtn new JButton(登录); loginBtn.addActionListener(e - doLogin()); add(loginBtn); pack(); setLocationRelativeTo(owner); } private void doLogin() { String username usernameField.getText().trim(); String password new String(passwordField.getPassword()); // 简化认证硬编码模拟实际应查数据库 if (admin.equals(username) 123.equals(password)) { role admin; } else if (username.startsWith(stu_) 123.equals(password)) { role student; } else if (username.startsWith(tea_) 123.equals(password)) { role teacher; } else { JOptionPane.showMessageDialog(this, 用户名或密码错误); return; } dispose(); // 关闭登录框 new MainFrame(role); // 传入角色初始化对应 Tab } }5.3 主程序入口30 行启动代码把 Swing、JDBC、MySQL 串成一条线// Main.java public class Main { public static void main(String[] args) { // 设置 Swing 全局字体解决 Win10 下中文模糊 try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel()); Font font new Font(Microsoft YaHei, Font.PLAIN, 12); UIManager.put(Label.font, font); UIManager.put(Button.font, font); UIManager.put(TextField.font, font); } catch (Exception e) { e.printStackTrace(); } // 启动登录对话框 SwingUtilities.invokeLater(() - { LoginDialog dialog new LoginDialog(null); dialog.setVisible(true); }); // 验证数据库连接启动时执行一次 try (Connection conn DatabaseConnection.getConnection()) { System.out.println(✅ 数据库连接成功 conn.getMetaData().getURL()); } catch (SQLException e) { JOptionPane.showMessageDialog(null, 数据库连接失败请检查 MySQL 是否启动、账号密码是否正确\n e.getMessage(), 连接错误, JOptionPane.ERROR_MESSAGE); System.exit(1); } } }关键技巧SwingUtilities.invokeLater()是 Swing 程序的黄金入口确保所有 GUI 创建都在 EDT 中UIManager.setLookAndFeel()用系统原生风格避免 Metal 风格在 Win10 上显示异常启动时主动getConnection()并捕获异常比运行时弹窗更早暴露环境问题。6. 答辩加分项3 个让老师眼前一亮的实战细节不是炫技而是真懂答辩不是代码朗诵会老师想看到的是你对技术选型的理解深度、对边界条件的预判能力、对真实问题的解决痕迹。以下三个细节每个都能在 5 分钟内讲清楚原理、展示代码、复现效果且全部来自真实毕设翻车现场——它们不增加功能但能让老师笃定“这学生真的跑通了不是抄的”。6.1 细节一用JTable的TableCellRenderer实现状态色块比文字更直观“状态”字段只显示“待选”“已选”太单薄。用TableCellRenderer为不同状态渲染不同背景色既提升可用性又证明你理解了 Swing 的渲染机制。// StatusCellRenderer.java public class StatusCellRenderer extends DefaultTableCellRenderer { Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column); String status (String) value; switch (status) { case 待选: c.setBackground(Color.LIGHT_GRAY); break; case 已选: c.setBackground(new Color(173, 216, 230)); // 浅蓝 break; case 已审核: c.setBackground(new Color(144, 238, 144)); // 浅绿 break; default: c.setBackground(Color.WHITE); } return c; } } // 在创建 JTable 后设置 table.getColumnModel().getColumn(4).setCellRenderer(new StatusCellRenderer());为什么值得讲这不是 CSS而是 Java 代码对每个单元格的逐个绘制控制。老师会意识到你不仅会用JTable还知道它背后是TableCellRenderer接口且能定制实现——这比“用过 Spring Boot”更有说服力。6.2 细节二用JOptionPane的showConfirmDialog实现二次确认防误操作“撤回选题”按钮一点就删太危险。加一层showConfirmDialog返回JOptionPane.YES_OPTION才执行 JDBC 删除这是最朴素的用户保护意识。JButton withdrawBtn new JButton(撤回); withdrawBtn.addActionListener(e - { int result JOptionPane.showConfirmDialog( this, 确定要撤回该课题吗此操作不可撤销, 确认撤回, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE ); if (result JOptionPane.YES_OPTION) { // 执行 JDBC 删除 selection 记录 try { SelectionDao.deleteByStudentAndTopic( currentStudentId, selectedTopicId ); JOptionPane.showMessageDialog(this, 撤回成功); refreshTable(); // 重新加载 } catch (SQLException ex) { JOptionPane.showMessageDialog(this, 撤回失败 ex.getMessage()); } } });答辩话术“老师这里我加了二次确认因为选题是关键业务操作。如果直接删学生手滑点错就无法恢复。用JOptionPane是最轻量的方案不需要引入额外框架也符合桌面应用的交互习惯。”6.3 细节三导出选题统计为 Excel用 Apache POI 而不是截图答辩时老师常问“能导出数据吗”截图是下策用 Apache POI 生成.xlsx文件才是正解。只需 20 行代码就能把JTable数据转成 Excel且兼容 Office 和 WPS。// 导出按钮事件 JButton exportBtn new JButton(导出统计); exportBtn.addActionListener(e - { try (XSSFWorkbook workbook new XSSFWorkbook(); FileOutputStream fileOut new FileOutputStream(选题统计.xlsx)) { XSSFSheet sheet workbook.createSheet(选题汇总); String[] headers {课题ID, 课题名称, 指导教师, 专业方向, 选择人数}; Row headerRow sheet.createRow(0); for (int i 0; i headers.length; i) { headerRow.createCell(i).setCellValue(headers[i]); } // 假设已有统计结果 ListStatItem ListStatItem stats ReportService.getTopicStats(); for (int i 0; i stats.size(); i) { Row row sheet.createRow(i 1); row.createCell(0).setCellValue(stats.get(i).getId()); row.createCell(1).setCellValue(stats.get(i).getTitle()); row.createCell(2).setCellValue(stats.get(i).getTeacher()); row.createCell(3).setCellValue(stats.get(i).getMajor()); row.createCell(4).setCellValue(stats.get(i).getCount()); } workbook.write(fileOut); JOptionPane.showMessageDialog(this, 导出完成选题统计.xlsx); } catch (IOException | SQLException ex) { JOptionPane.showMessageDialog(this, 导出失败 ex.getMessage()); } });依赖添加pom.xmldependency groupIdorg.apache.poi/groupId artifactIdpoi-ooxml/artifactId version5.2.4/version /dependency我带毕设十年见过太多学生花两周调通 Spring Boot Vue 前后端分离结果答辩时 Tomcat 突然报port 8080 already in use当场崩溃。而用 Swing JDBC MySQL 的学生往往在答辩前夜还在优化GridBagLayout的insets参数第二天演示时双击 jar 包界面秒开SQL 日志清清楚楚老师问哪句 SQL 怎么写的他打开TopicDao.java指着prepareStatement就能讲。技术没有高低只有是否服务于目标——毕业设计的目标从来不是造轮子而是证明你有能力把需求、代码、数据、界面严丝合缝地拧成一股绳。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站