尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Java课程设计:用Swing+JDBC实现小型档案管理系统
简介一份基于Java实现的小型档案管理系统实验设计资源采用C/S架构覆盖用户登录、角色权限、档案上传下载、条件查询与个人信息维护等完整流程。系统将用户分为系统管理人员、档案录入人员、档案浏览人员三类客户端与服务器端通过Socket通信服务器端多线程可同时响应多个请求适合作为高校Java课程设计、多线程与Socket编程实验的参考范例。资源包含完整Eclipse工程源码与编译后的class文件client/server双端目录清晰另有SQL建表脚本、MySQL驱动JAR包、使用说明文档及实验指导书docx文档便于按步骤部署运行。压缩包共47个文件以java源码、class字节码、txt文档为主整体仅1.37MB轻量易取目前已有873人学习下载。读者可获得可运行的C/S通信示例、多线程并发处理思路、三种角色权限管理的数据库设计以及文件上传下载与元数据分离存储的实践方案并能对照工程结构快速完成实验环境搭建与功能扩展。1. 拿到“Java实验设计-实现一个小型档案管理系统”这个题目先别慌它难在哪又能带来什么拿到“Java实验设计-实现一个小型档案管理系统”这个题目时多数人的第一反应是“又要连数据库又要画界面我从哪头开始”。这个选题看起来小实则把Java基础、面向对象编程Java、JDBC和Swing事件驱动串成了一条完整的练习链正好可以作为Java学习路线里的第一个有业务闭环的练手项目。它适合课程设计、期末实验也适合准备Java基础面试题前做一个能讲出设计亮点的作品。我会采用一套最保守也最可控的技术方案Java SE Swing JDBC MySQL。不引入Spring不写前端页面单人一周内可以从建库跑到答辩演示。整个方案把“档案管理”收敛为登录、档案增删改查、借阅登记、数据导出几个模块既满足实验评分也不至于让项目失去边界。本文按“需求拆解 → 技术选型 → 分层实现 → 界面落地 → 避坑排查 → 答辩进阶”的顺序展开。目标很明确你不仅能跑通这个项目还能在被老师问到“为什么这样设计”“并发时怎么办”时给出有底气的回答。2. 小型档案管理系统的需求拆解与技术选型先画好边界再写代码很多课程设计翻车不是代码写错而是需求没锁住。档案管理系统听上去很大但“小型”两个字就是给你划好了边界不需要流程审批、不需要多级权限、不需要微服务。你只需要做成一个能让一个管理员完成日常纸质档案电子化、查询和借阅登记的单机桌面程序。在动笔前我会先把功能清单列在纸上并对照课程设计评分表逐项打勾。这样写代码时不会东一榔头西一棒子答辩时也能说清“每一个功能对应的验收标准是什么”。2.1 从课程设计评分表反推功能清单大多数Java课程设计的评分维度是功能完整度、界面可用性、数据库设计、代码规范性、演示流畅度。围绕这五点一个能站稳脚跟的档案管理系统至少要包含用户登录区分管理员和普通用户密码不能明文硬编码在业务代码里档案台账以表格形式展示所有档案支持编号、标题、分类检索新增档案录入编号、标题、内容摘要、分类、录入人编辑与删除修改档案信息删除前必须二次确认借阅登记记录借出人和借出时间归还时更新归还时间日志或审计线索哪怕只是记录“谁在什么时候操作了哪条档案”也是加分项。我一般会做成一个三行三列的功能矩阵模块 / 最低验收点 / 加分项。例如登录模块最低验收点是“错误密码进不去”加分项是“输错三次锁定30秒”查询模块最低验收点是“按标题模糊查询”加分项是“组合条件查询”。把这个矩阵写在设计说明里答辩老师一眼就能看出你做过需求分析。很多同学一上来就做复杂的权限模型结果界面堆了七八个窗口最后只演示了登录和跳出。要记住实验设计的目的是验证你知道怎么组织一个完整的小系统而不是模拟Oracle ERP。功能范围控制在“一个人一周能完成”的状态留出时间打磨异常处理和答辩话术性价比最高。2.2 技术选型为什么是Swing JDBC而不是Spring全家桶先回答一个高频问题现在企业都写Spring Boot Vue为什么课程设计还要用Swing和JDBC因为实验课的时间、运行环境和评分标准都不支持你去搭一套前后端分离工程。Swing是JDK自带的GUI框架打包成jar后双击即可运行不需要安装TomcatJDBC是Java访问关系型数据库的原始接口它能让你看清SQL的执行过程而不是被MyBatis的映射文件包住。从Java学习路线的角度看先掌握Swing JDBC再去看Spring的JdbcTemplate和事务管理理解成本会低很多。Java基础面试题里常问的PreparedStatement防SQL注入、try-with-resources自动关闭、线程与事务在这个项目中都能亲手验证一次。如果你直接跳到Spring Boot这些底层细节反而不容易讲清楚。数据库我选MySQL 8.x驱动是mysql-connector-java 8.x。连接URL里必须带serverTimezoneAsia/Shanghai否则新版驱动会报时区错误。开发环境需要先配置好JAVA_HOME和PATH这个步骤属于Java环境变量配置有人会在IDE里能运行但命令行java -version报错最后在连接数据库时卡住。所以第一件事是确认命令行能敲出java -version和javac -version再继续往下走。另外一个需要理性看待的选型是JavaFX。Swing虽然老但在课程设计中更常见遇到问题容易搜到资料JavaFX的布局更现代但新电脑上可能要额外配置OpenJFX模块。如果你只有五天时间选Swing的试错成本最低。界面丑可以通过布局和配色补救“跑不起来”才是真翻车。2.3 数据库表设计三张表把档案业务说清楚档案管理系统的核心数据可以抽象成三个概念操作者、档案本身、借阅记录。档案分类不需要单独建表用varchar字段存“人事档案/行政档案/技术档案”即可这是小型系统里很常见的简化做法。下面是我推荐的建表语句直接用MySQL 8执行即可。CREATE DATABASE IF NOT EXISTS archives DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE archives; CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(32) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT 密码实验阶段存原文生产环境必须加密, role VARCHAR(16) NOT NULL DEFAULT USER COMMENT ADMIN/USER ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_archive ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 档案ID, archive_no VARCHAR(32) NOT NULL UNIQUE COMMENT 档案编号业务唯一键, title VARCHAR(128) NOT NULL COMMENT 标题, content TEXT COMMENT 内容摘要, category VARCHAR(32) DEFAULT 未分类 COMMENT 档案分类, user_id INT COMMENT 录入人ID, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE t_borrow ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 借阅ID, archive_id INT NOT NULL COMMENT 档案ID, borrower VARCHAR(32) NOT NULL COMMENT 借用人, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 借出时间, return_time DATETIME DEFAULT NULL COMMENT 归还时间为空表示未归还 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;执行完这段SQL后可以顺手插入一条管理员数据和两条样例档案方便后面调试界面INSERT INTO t_user(username, password, role) VALUES(admin, 123456, ADMIN); INSERT INTO t_archive(archive_no, title, content, category, user_id) VALUES(DA-2024-0001, 员工入职登记表, 张三2024年3月入职, 人事档案, 1);这段DDL的关键点有三个。第一t_archive的archive_no字段用了UNIQUE约束对应业务规则“档案编号不允许重复”这比在Java代码里先查询再判断要可靠得多。第二t_borrow不建物理外键只保留逻辑外键archive_id因为实验演示时删除档案会被外键约束拦住老师会觉得你的系统“删不掉数据”。第三create_time用DATETIME DEFAULT CURRENT_TIMESTAMP避免在Java层手动拼时间少一个出错点。关于密码字段实验阶段用原文可以但你要能主动说出“正式系统应该用BCrypt或SHA-256加盐”这句话在答辩时是明显的加分项。数据一致性方面后续在Service层用事务保证借阅登记的原子性这里先不展开。三张表的粒度正好对应三个业务模块认证、档案台账、借阅。如果以后项目要扩展成Web版直接把这套模型平移到Spring Boot JPA几乎不需要改表结构。3. 用面向对象分层把核心业务写扎实实体类、DAO与Service的落地技术选型确定后最容易犯的错是把所有JDBC代码都塞进Swing事件监听器里。一个登录按钮里既写SQL又写ResultSet解析短期能跑后期改需求时只能重构。这里我会采用教科书式的分层界面层只调用ServiceService只调用DAO接口DAO实现细节完全被隔离。这也是面向对象编程Java里“面向接口编程”的直观演练。包结构建议这样建com.archives ├── entity // Archive、User、BorrowRecord实体 ├── dao // ArchiveDao接口 ├── dao.impl // ArchiveDaoImpl ├── service // ArchiveService ├── ui // LoginFrame、MainFrame └── util // DBUtil3.1 实体类与连接工具把面向对象编程Java的封装落到实处实体类对应数据库表是Java基础里“类与对象”最直接的体现。以档案实体为例所有属性私有对外只暴露getter/setter这就是封装。不写公共字段更不允许直接操作数据库列名。下面的Archive实体保留核心字段ID用Integer而不是int是为了方便判断“尚未保存”的空值状态。public class Archive { private Integer id; private String archiveNo; private String title; private String content; private String category; private Integer userId; private String createTime; // getter/setter省略建议手写而非依赖IDE生成 // 便于在setter中添加空值校验 public void setTitle(String title) { if (title null || title.trim().isEmpty()) { throw new IllegalArgumentException(标题不能为空); } this.title title; } }实体类里可以做轻量校验比如setTitle抛IllegalArgumentException把数据合法性检查从界面层前置到模型层。这种做法会让你在答辩时被问到“谁负责校验”时回答“实体层做基础校验Service层做业务校验UI层只负责展示提示”这就是清晰的分层职责。连接工具类我一般写成这样读取classpath根目录下的db.properties避免把数据库账号密码写死在Java代码里。public class DBUtil { private static String url; private static String user; private static String password; static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)) { Properties props new Properties(); props.load(in); Class.forName(com.mysql.cj.jdbc.Driver); url props.getProperty(url); user props.getProperty(user); password props.getProperty(password); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } }db.properties放在src目录下内容为urljdbc:mysql://localhost:3306/archives?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai userroot password你的密码这段代码有一个细节容易被新手忽略Class.forName注册驱动只执行一次放在static块里最合适。getConnection每次都创建新连接是实验项目的正常做法但如果后续要撑高并发就要换成连接池我在最后一张会提替代方案。3.2 DAO接口与JDBC实现用PreparedStatement把SQL注入挡在门外DAO层的第一个决策是定义一个接口而不是直接写实现类。接口定义了“这个模块对外承诺提供哪些能力”实现类可以被替换这就是面向对象编程Java里的“多态”在架构层面的体现。下面是ArchiveDao接口public interface ArchiveDao { ListArchive findAll() throws SQLException; Archive findById(int id) throws SQLException; int insert(Archive archive) throws SQLException; int update(Archive archive) throws SQLException; int deleteById(int id) throws SQLException; ListArchive search(String keyword) throws SQLException; }为什么方法要声明throws SQLException因为把异常抛给Service层统一处理比在DAO里打印吃掉更利于事务回滚。这是Java基础面试题里常问的“受检异常vs运行时异常”的实际应用。实现类ArchiveDaoImpl里我重点演示insert方法其余方法同构。public class ArchiveDaoImpl implements ArchiveDao { Override public int insert(Archive archive) throws SQLException { String sql INSERT INTO t_archive(archive_no, title, content, category, user_id) VALUES (?, ?, ?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, archive.getArchiveNo()); ps.setString(2, archive.getTitle()); ps.setString(3, archive.getContent()); ps.setString(4, archive.getCategory()); ps.setInt(5, archive.getUserId()); return ps.executeUpdate(); } } }参数说明PreparedStatement的setString/setInt从1开始编号顺序和SQL里的问号一一对应。try-with-resources会在方法结束时自动调用close即使执行中抛异常也不会连接泄漏。这里不要用Statement拼接字符串因为形如“1 or 11”的输入可以直接改写SQL语义。把参数用问号占位符传给数据库等于把“数据”和“SQL结构”彻底分开这是Java基础里一个必须拿得出手的安全实践。findAll的常见写法是循环遍历ResultSet把每一行映射成一个Archive对象再放入List。这里有一个性能细节ResultSet的默认游标只能向前如果你在遍历时执行了另一个查询连接可能被占用。所以要在同一个try块内完成查询和对象映射尽早释放Statement。我见过有人把ResultSet直接存进List关闭连接后再取数据结果报“Closed Statement”错误这是很典型的踩坑点。3.3 Service层的更新边界对象深度拷贝与事务的初步使用DAO只负责“一条SQL跑完”但业务上经常需要“多条SQL一起成功”。例如借阅登记时要先在t_borrow里插入一条记录再在内存里维护“该档案已借出”的状态。如果第二条SQL失败第一条已经提交账就会对不上。Java面试题里常出现的“怎么保证数据一致性”答案就是事务。日常项目里我通常不会把JDBC事务代码直接写在DAO里而是放在Service层统一控制。借阅登记的简化代码如下public void borrowArchive(int archiveId, String borrower) throws SQLException { String insertBorrow INSERT INTO t_borrow(archive_id, borrower) VALUES (?, ?); String updateArchive UPDATE t_archive SET status 1 WHERE id ?; boolean success false; try (Connection conn DBUtil.getConnection()) { conn.setAutoCommit(false); try (PreparedStatement ps1 conn.prepareStatement(insertBorrow); PreparedStatement ps2 conn.prepareStatement(updateArchive)) { ps1.setInt(1, archiveId); ps1.setString(2, borrower); ps1.executeUpdate(); ps2.setInt(1, archiveId); ps2.executeUpdate(); conn.commit(); success true; } catch (SQLException e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); } } finally { // 可以在这里打日志记录 borrowArchive 成功/失败 } }参数说明setAutoCommit(false)关闭自动提交所有SQL在同一个数据库事务内执行commmit或rollback后要恢复自动提交否则连接归还到池子时会带着错误状态。这段代码在答辩时是回答“数据一致性”问题的最佳素材。老师再追问“两条SQL执行过程中有人同时查询怎么办”你可以进一步说需要配合锁或隔离级别但实验课能讲到事务这层已经很扎实。Service层还牵扯到一个Java对象图常识对象深度拷贝。比如从数据库查出一条Archive界面打开了编辑框用户点了“取消”如果编辑框里的对象就是原对象的引用那么原对象已经被污染了。常见做法是在Service层提供copyForEdit方法new一个Archive再逐个字段赋值。这里别用Object.clone()因为默认是浅拷贝如果实体里持有List或自定义对象浅拷贝会出现两个对象共享同一个子对象的副作用。课程设计里用构造器或手动拷贝方法最直观也能讲清楚。4. 用Swing把增删改查变成可演示的界面从登录到档案台账分层代码写完之后Swing界面就变成了“表现层”。很多同学喜欢先把界面画得天花乱坠再补业务逻辑结果发现按钮事件里塞了500行JDBC代码。正确顺序是先有Service的方法再设计窗口调用它们。下面我会给出一个能复制的登录框架和JTable数据刷新模板。4.1 用SwingUtilities.invokeLater启动程序登录窗口的完整写法Swing不是线程安全的界面必须在事件分发线程EDT上创建。如果直接在main里写new LoginFrame()在部分操作系统上会出现随机闪烁或控件失效。安全写法是public class App { public static void main(String[] args) { SwingUtilities.invokeLater(() - { LoginFrame frame new LoginFrame(); frame.setVisible(true); }); } }invokeLater让界面的创建任务排队到EDT执行这是Java事件机制的基础。你可以在构造LoginFrame时加载用户列表或者初始化主题耗时操作要放到后台线程。登录按钮的监听器是Swing事件编程最典型的例子loginBtn.addActionListener(e - { String username usernameField.getText().trim(); String password new String(passwordField.getPassword()); if (username.isEmpty() || password.isEmpty()) { JOptionPane.showMessageDialog(LoginFrame.this, 用户名和密码不能为空); return; } boolean ok userService.checkLogin(username, password); if (ok) { new MainFrame(username).setVisible(true); dispose(); // 关闭登录窗口 } else { JOptionPane.showMessageDialog(LoginFrame.this, 用户名或密码错误); } });这里有两个细节JPasswordField的getPassword返回char数组而不是String这是为避免密码字符串滞留在堆内存中校验放在Service层界面只负责触发和展示结果。错误提示不要用System.out.println打印到控制台因为演示时没人看后台要用JOptionPane弹窗。4.2 JTable与DefaultTableModel把档案列表变成可刷新界面档案台账是系统的门面我通常用JTable DefaultTableModel实现。JTable本身不存数据数据模型才是数据源这也是MVC模式的最小实践。DefaultTableModel model new DefaultTableModel( new String[]{ID, 档案编号, 标题, 分类, 录入人ID, 创建时间}, 0); JTable table new JTable(model); public void loadData() { model.setRowCount(0); ListArchive list archiveService.listAll(); for (Archive a : list) { model.addRow(new Object[]{ a.getId(), a.getArchiveNo(), a.getTitle(), a.getCategory(), a.getUserId(), a.getCreateTime() }); } }每次刷新前先model.setRowCount(0)清空旧数据再addRow重新填充。这个模式虽然性能不高但课程设计的数据量通常只有几十条完全够用。如果你固定JTable的列数可以在setAutoResizeMode(JTable.AUTO_RESIZE_OFF)时手动设置列宽避免最后一列被压缩。JTable选中行后通过table.getSelectedRow()可以拿到视图行号。这里有一个常见坑如果对表格做排序或过滤selectedRow是视图索引不能直接用它去访问原始List需要table.convertRowIndexToModel()转换。我建议课程设计的演示不要开启排序减少一个变量。4.3 事件监听里的三个细节保存、清空与错误提示新增档案是JDialog里的一组JTextField点“保存”后需要触发Service。下面是保存事件的模板saveBtn.addActionListener(e - { String no noField.getText().trim(); String title titleField.getText().trim(); if (no.isEmpty() || title.isEmpty()) { JOptionPane.showMessageDialog(this, 编号和标题为必填项, 校验, JOptionPane.WARNING_MESSAGE); return; } Archive archive new Archive(); archive.setArchiveNo(no); archive.setTitle(title); archive.setContent(contentArea.getText()); archive.setCategory(categoryBox.getSelectedItem().toString()); archive.setUserId(currentUserId); try { archiveService.insert(archive); loadData(); clearFields(); JOptionPane.showMessageDialog(this, 保存成功); } catch (SQLException ex) { JOptionPane.showMessageDialog(this, 保存失败 ex.getMessage(), 错误, JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); } });这里组合使用了StringBuilder拼日志吗其实不需要。如果异常信息很长用StringBuilder组装JOptionPane的text最合适例如StringBuilder msg new StringBuilder(保存失败); msg.append(ex.getMessage()); msg.append(\n请检查档案编号是否重复);这个点在面试里会被延伸“字符串拼接用还是StringBuilder”在循环内拼接必须用StringBuilder这里只有一个append用也可读。关键是你能说明自己的选择依据。清空按钮直接对每个JTextField调用setText()刷新表格时不要重新new DefaultTableModel赋给JTable否则会丢失表头样式。错误提示统一用Error级别图标区别于“请输入内容”的Warning图标用户一看图标就知道是什么性质的提示。Swing的老规矩是不要在监听器里写耗时超过几百毫秒的操作。如果借阅登记要实时校验外部系统应该放到SwingWorker的doInBackground中。课程设计中不一定用得到但你要能说“我知道事件线程不能阻塞”这句话足够让老师对你刮目相看。5. 档案管理系统实现中的避坑记录4个常见的翻车现场与排查思路这一节我把做同类项目时踩过的坑整理成清单每条都按“现象→原因→解决”来写。只要你能按顺序排查这个项目基本不会在演示当天当机。5.1 报错ClassNotFoundException: com.mysql.cj.jdbc.Driver现象在IDEA里运行正常直接双击jar包或打包后运行提示找不到MySQL驱动类。有些同学在代码里写Class.forName(com.mysql.jdbc.Driver)也报一样的错。原因把mysql-connector-java的jar包导入了IDE的Library但打包时没有把它带进classpath。或者驱动类名用错MySQL 8.x驱动类是com.mysql.cj.jdbc.Driver旧驱动名在新版里已经被移除。解决项目结构里把驱动jar放在一个lib目录并在IDEA的Project Structure Modules Dependencies中设为“Compile”。如果打包成可执行fat jar用Ant或Maven的shade插件把驱动类并入jar。临时启动时命令行用java -cp lib/*;classes com.archives.App确保通配符能覆盖lib下的所有jar。这里也提醒一点配置驱动之前先用命令行验证java和javac存在如果只有java但没有javac说明只装了JRE没装JDK需要回看Java环境变量配置。这是很多人忽略的前置条件。5.2 中文写入数据库变成问号Swing界面显示也是乱码现象控制台打印中文正常但插入MySQL后变成??或者在Swing里刚输入的中文马上就变成乱码。原因数据库连接URL没有指定characterEncodingutf8并且建表时用了默认的latin1字符集。MySQL服务器、连接层、Java内存三者字符集不一致数据就在转换中丢失了。解决建库建表统一使用utf8mb4连接URL改成jdbc:mysql://localhost:3306/archives?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai。如果已经建错表用ALTER TABLE t_archive CONVERT TO CHARACTER SET utf8mb4修复。Swing自身的乱码通常是JVM默认编码问题在启动参数里加-Dfile.encodingUTF-8即可。判断问题出在哪一步按顺序查先在Navicat手工插入中文看数据库本身支不支持再在Java代码里直接打印SQL看传给PreparedStatement的中文是否正确最后看ResultSet读回来的中文是否正常。这三分支能快速定位责任层避免一上来就改数据库。5.3 点击“登录”后整个窗口卡死数据库一慢就假死现象登录按钮按下后窗口鼠标变成忙状态拖动不了过一会才恢复。如果数据库连接超时窗口可能卡到必须强制关闭。原因监听器里直接执行了JDBC查询而JDBC的获取连接和SQL执行是阻塞式IO。EDT线程被阻塞后无法处理重绘和鼠标事件所以整个窗口看起来死掉了。解决最轻量的做法是new Thread(() - { boolean ok userService.checkLogin(...); SwingUtilities.invokeLater(() - { ... }); }).start()。更规范的是使用SwingWorkerSwingWorkerBoolean, Void worker new SwingWorker() { Override protected Boolean doInBackground() { return userService.checkLogin(username, password); } Override protected void done() { boolean ok false; try { ok get(); } catch (Exception ex) { ex.printStackTrace(); } if (ok) { ... } } }; worker.execute();这里注意在doInBackground里不能直接触碰JButton或JLabel需要把结果带回EDT的done方法里再更新界面。我当年就犯过这个错新线程里调用model.addRow结果表格刷新时灵时不灵。SwingWorker的好处是回调都落在EDT不需要你手动invokeLater。5.4 借阅登记执行到一半失败第一条SQL却生效了现象borrowArchive方法里先insert借阅记录再update档案状态第二条SQL因字段长度超限失败但第一条已经提交结果查到了借阅记录档案状态却没变。原因JDBC默认自动提交每条SQL多条SQL之间没有事务边界。这不是“并发导致”而是最基本的原子性问题。解决使用第3.3节的事务写法在同一个Connection上setAutoCommit(false)两条SQL都成功后再commit失败则rollback。要让这段代码真正可靠必须把两个PreparedStatement拿到同一个try块里不能各取一个连接。如果直接用DAO里的两个方法各开各的连接事务根本不成立。一个有经验的工程师会把这段逻辑收进Service层并用一个Boolean返回“是否借出成功”给界面。遇到重复借阅同一档案的场景还需要在SQL层面加条件UPDATE t_archive SET status1 WHERE id? AND status0返回值0表示档案已被借出。这比在Java里先查一下再更新更可靠因为“查”和“更新”之间仍然有竞态窗口。6. 让项目从“能跑”到“能答辩”POI导出、连接池与验证清单课程设计展示只跑通功能是及格分要拿高分你得在“项目能跑”之外再提供一两个亮点。最稳妥的加分项是用Apache POI把档案台账导出成Word或Excel以及用一个清晰的自测清单证明你考虑过边界情况。6.1 用Apache POI生成Word档案台账以及图表那个提问怎么答POI不是JDK自带的需要在Maven里引入poi-ooxml依赖。这里不贴完整代码给出能生成Word表格的最小例子XWPFDocument doc new XWPFDocument(); XWPFTable table doc.createTable(2, 4); table.getRow(0).getCell(0).setText(档案编号); table.getRow(0).getCell(1).setText(标题); table.getRow(0).getCell(2).setText(分类); table.getRow(0).getCell(3).setText(创建时间); // 第二行填充真实数据 FileOutputStream out new FileOutputStream(档案台账.docx); doc.write(out); out.close(); doc.close();这个例子中createTable的行数需要预先确定如果后面要动态追加行用table.createRow()更灵活。POI对Word里生成图表支持很弱原生API没有直接生成chart的方法网上问“java poi word能生成图表吗”的答案通常是“要手动拼DrawingML XML”。所以在答辩时如果老师问图表更好的回复是“我选择在Excel中生成图表或者先用Java绘图生成图片再插入Word”而不是硬啃XML规范。用POI导出Excel并插入Chart也是可行的但课程设计时间紧张做一个Word表格台账足够体现你的工程扩展能力。6.2 一份答辩前的半小时自测清单我会在项目交付前按这份清单过一遍登录错误密码时能否弹窗且不退出程序档案编号重复时数据库报的Duplicate Entry错误有没有被转成可读提示空数据时档案列表是否显示“暂无数据”而不是白屏删除档案是否有二次确认多选批量删除是否只删选中的行借阅登记后能不能在档案列表或借阅记录里看到状态变化快速点击“保存”按钮会不会产生重复提交导出Word文件后用WPS打开是否出现编码错乱把所有jar打成可执行包换一台没有JDBC环境的电脑能否运行这些点每项都可能成为老师追问“你考虑过XXX吗”的引子。我现在做这类项目习惯先把异常路径的录屏准备好再演示正常流程因为答辩的本质是证明你对失败情况的预判能力。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Win11 Edge无法卸载?四步解除默认绑定与后台驻留

Win11 Edge无法卸载?四步解除默认绑定与后台驻留

1. 为什么Win11 Edge“卸载”是个伪命题?先搞清系统级绑定的本质Win11 Edge浏览器根本不是传统意义上能“一键卸载”的独立软件,它和Windows 11操作系统是深度耦合的系统组件——就像你不能把汽车的刹车油管从发动机舱里整个拔出来还指望车能正常开一样。…

📅 2026/9/30 5:36:46
Jev类型安全AI封装:密钥申请、SDK接入与API避坑指南

Jev类型安全AI封装:密钥申请、SDK接入与API避坑指南

最近后台和评论区被同一个词刷屏了——Jev。有人问它是不是又一个套壳的AI工具,有人拿着"jev密钥"到处找申请入口,还有人把它和TypeSafe AI、System One Model这些概念混在一起聊。我花了两周时间把Jev相关的资料、SDK接入流程、API调用链路完…

📅 2026/9/30 5:36:46
AI+CAD工程化落地:从Demo到真实项目的踩坑与实操指南

AI+CAD工程化落地:从Demo到真实项目的踩坑与实操指南

1. 从Demo到工程:AICAD落地的真实鸿沟过去两年,我参与过三个AI辅助CAD的项目,从图纸识别到参数化生成都摸过一遍。每次立项时团队都信心满满,Demo演示时效果惊艳,但一到真实工程环境就各种翻车。这个现象太普遍了&…

📅 2026/9/30 5:31:46
MORE NEWS

更多资讯

📰

YOLOv13改进策略【卷积层篇】| CVPR2024 UniRepLKNet Block,大核感受野的可重参数化卷积

本文基于 YOLOv13 官方仓库(iMoonLab/yolov13,ultralytics 8.3.63 fork) 实测整理,Windows/CPU 全程可跑。UniRepLKNet(Ding et al., CVPR 2024《UniRepLKNet: A Universal Perception Large-Kernel ConvNet》,官方源码 github.com/AILab-CVC/UniRepLKNet)给"大核卷…

📰

YOLOv13改进策略【卷积层篇】| CVPR2023 DCNv3 可变形卷积,采样点第三次进化

本文基于 YOLOv13 官方仓库(iMoonLab/yolov13,ultralytics 8.3.63 fork) 实测整理,Windows/CPU 全程可跑。DCNv3(Wang et al., CVPR 2023《InternImage: Exploring Large-Scale Vision Foundation Models with Deformable Convolutions》,官方源码 github.com/OpenGVLab/…

📰

YOLOv13改进策略【卷积层篇】| 2024 MobileNetV4 UIB 万能倒残差,一块卷积通吃轻量微结构

本文基于 YOLOv13 官方仓库(iMoonLab/yolov13,ultralytics 8.3.63 fork) 实测整理,Windows/CPU 全程可跑。MobileNetV4(Qin et al., CVPR 2024 Workshop,《MobileNetV4: Universal Models for the Mobile Ecosystem》,arXiv 2404.10518;官方实现为 TensorFlow,无官方 …

📰

使用 Rube MCP 自动化 Aero Workflow:awesome-claude-skills 中 aero-workflow-automation Skill 实战指南

AI 技能AI 插件人工智能工作流自动化 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-claude-skills 点击…

📰

DGCharts(Charts 5.x)iOS/tvOS/macOS 图表库完全指南:从安装集成到八大图表实战

数据可视化图表库移动开发 【免费下载链接】Charts Beautiful charts for iOS/tvOS/OSX! The Apple side of the crossplatform MPAndroidChart. 项目地址: https://gitcode.com/gh_mirrors/cha/Charts 点击查看 免费下载 DGCharts 是著名 Android 图表库 MPAndroi…

📰

security-audit-skill HTTP 协议与身份认证安全审计指南:从请求分帧到 mTLS 的系统化狩猎方法

AI 技能应用安全 【免费下载链接】security-audit-skill A coding-agent skill for multi-phase security audits with independently verified, machine-readable findings 项目地址: https://gitcode.com/GitHub_Trending/se/security-audit-skill 点击查看 免费下…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬