ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于 Java Swing + MySQL 的学生健康档案管理系统解析

基于 Java Swing + MySQL 的学生健康档案管理系统解析 简介基于MySQL与Java Swing实现的学生健康档案管理系统面向高校计算机相关专业学生、教师及企业开发者适用于课程设计、毕业设计或Java GUI与数据库开发的入门进阶。系统覆盖学生信息管理、体检信息管理、病历信息管理三大模块支持体检/病历数据的增删改查、多条件高级查询、导入导出Excel及动态折线图数据分析并附带E-R图与数据库表结构说明。压缩包共98个文件其中包含30个Java源文件、38个class编译文件、7个XML配置、7张PNG和6张JPG效果图另有SQL建表脚本、properties配置文件、xls测试数据及.rp原型设计文档整体大小1.27MB。资源还包含项目运行所需的pom.xml和可直接导入的数据库脚本目录结构清晰便于对照学习。已有76人学习下载代码经测试运行成功适合拿来练手或在此基础上二次开发。1. 学生健康档案系统一个 Java Swing MySQL 的完整课设样本如果你正处在课程设计或者毕设初期的“选题焦虑”里大概率刷到过这类名字长到一口气念不完的项目基于 MySQL Java Swing 实现的学生健康档案管理系统。我第一次拆这个源码包的时候说实话没抱太高期望以为又是那种把数据库课设换个皮就拿出来重复上传的流水线作品。但看完HealthArchivesManagementSystem的代码结构和那几张功能截图之后我得承认它比我预想的要完整不少——不是只有 CRUD 摆在那里而是把登录注册、病历管理、体检管理、多条件查询、批量操作、Excel 导入导出全部串在了一起而且数据库脚本dbstuhealth.sql是直接能跑的。这个项目适合三类人第一类是计算机相关专业软件工程、物联网、电子信息这类需要交课程设计或者毕设初稿的学生拿它当骨架能省掉大量造轮子的时间第二类是刚学完 Java SE、想看看 Swing 实际项目长什么样的小白第三类是自己有管理系统开发需求、想参考模块划分和数据表设计的人。接下来我会把这套系统的表结构、界面实现、关键代码逻辑和最容易翻车的几个点全部拆开讲你照着能复现踩过的坑我也会直接标出来。2. 先立住数据层学生、病历、体检三张核心表怎么设计2.1 E-R 图背后的实体关系拿到这个项目的源码包时第一眼值得看的不是src下的 Java 类而是根目录那张E-Rͼ.jpg。这张图把整个系统分成了三条业务线学生信息管理、体检信息管理、病历信息管理。健康档案说白了就是把病历和体检两类数据挂到学生这个主实体下面形成一对多的关系——一个学生可以有多条病历记录也可以有多条不同日期的体检记录。这种设计其实是医疗信息管理系统里最常见的做法学生是主数据体检记录和病历记录是流水数据两者通过学号这个外键关联。学号在这里不仅是主键还承担了业务标识的角色这一点和很多只拿自增 id 当主键的课设项目不一样实际开发里也更符合校方查询的习惯——不管是导 Excel 还是按学号检索都比拿 id 去对要直观得多。病历数据的字段是学号、姓名、性别、系别、诊断、日期体检数据多了年龄、身高、体重、胸围这几项。注意体检表里没有独立的诊断字段因为体检本身只是体征记录不产生诊断结论这也是为什么系统要把病历和体检拆成两张表而不是合成一张大宽表——两类数据的更新频率和关注维度不一样合在一起反而会让查询逻辑变乱。2.2 从建表 SQL 看字段类型选择数据库脚本文件是dbstuhealth.sql导入之后你会看到一共三张表学生表是主表另外两张是明细表。建表语句的风格非常“课设标准”字段名直接见名知意类型选择保守没有玩什么花活。这种风格如果你是第一次做数据库设计直接照抄都不会出大问题。核心建议导入dbstuhealth.sql之前先把 MySQL 的字符集确认好。这个项目里面有中文数据包括初始化的学生姓名、系别所以建库语句里如果没显式指定utf8mb4Windows 下默认的latin1会让你后面查出来的中文全是问号。常见做法是先执行一条建库语句再导数据CREATE DATABASE IF NOT EXISTS dbstuhealth DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE dbstuhealth; SOURCE /your/path/dbstuhealth.sql;utf8mb4比老版utf8多覆盖了生僻字和 Emoji虽然学生档案里大概率不会出现这些字符但统一用utf8mb4可以避免以后插入特殊字符时直接报错。主键字段我没看到用AUTO_INCREMENT的强制约束学号是字符串类型这也是合理的——如果学号前面有零开头的前缀比如2025001用整数类型会自动丢零用VARCHAR虽然占空间稍多但在这个数据量级别完全无所谓。2.3 三张表之间的 JOIN 查询怎么写最顺项目里数据看板和高级查询这两个功能涉及的 SQL 不是简单的单表查询。比如统计某个系别的平均身高体重你得先 JOIN 学生表和体检表再按系别分组。我在源码里看到的查询逻辑基本是这种模式SELECT s.s_no, s.s_name, s.s_dept, h.h_height, h.h_weight, h.h_date FROM student s LEFT JOIN health h ON s.s_no h.s_no WHERE s.s_dept 计算机系 AND h.h_date BETWEEN 2024-09-01 AND 2025-01-15 ORDER BY h.h_date DESC;逻辑说明LEFT JOIN保证了即使某个学生没有体检记录他的基本信息也会出现在结果集里只是在身高体重列显示为 NULL。如果换成INNER JOIN那么没有体检记录的学生会直接被过滤掉这在学生管理场景下不是你想要的结果——你想看到的是完整名单而不是只有体检过的名单。参数说明BETWEEN ... AND ...用来圈定日期范围是体检周期查询最常用的写法。这里的日期字段类型建议用DATE而不是VARCHAR项目建表时如果写成了VARCHAR也能跑但你在做日期范围统计的时候就要用字符串比较一旦格式不统一极容易翻车。我拆这个包的时候注意到它的日期的规范程度还算可以但你拿到手最好先确认一下日期列存的到底是纯YYYY-MM-DD还是带时间戳的格式。3. 代码骨架拆解登录认证、DAO 层和 Swing 界面的联动逻辑3.1 登录模块不是装饰它是整个系统的入口守卫登录注册.jpg那张截图看着朴素但它的代码逻辑值得抄一下。登录校验的流程是用户在JTextField输入账号密码点击登录按钮后触发ActionListener从文本框取值发给UserDao的login()方法方法内部通过PreparedStatement防注入地执行SELECT COUNT(*) FROM user WHERE username ? AND password ?返回布尔值决定是否跳转到主界面。常见做法是密码存 MD5 摘要而不是明文这个项目里我看到了注册功能所以注册的时候至少应该对密码做一次不可逆处理。Java 自带的MessageDigest就能实现 MD5不需要引第三方 jarpublic static String md5(String input) { try { MessageDigest md MessageDigest.getInstance(MD5); byte[] digest md.digest(input.getBytes(UTF-8)); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); } catch (Exception e) { e.printStackTrace(); return null; } }逻辑说明MessageDigest.getInstance(MD5)拿到的是 JDK 内置的加密器对字符串转成的字节数组求摘要后%02x是把每个字节格式化成两位十六进制的小写字符串。这样即使数据库被别人拖走明文密码也不会直接暴露。参数说明String.format(%02x, b)里02表示至少占两位x是十六进制。Java 的byte是有符号的转十六进制时如果不做位运算会出现ffffff80这种怪结果稳妥写法是b 0xFF之后再格式化。你在这个项目里看到我这段代码其实是我把它后端注册逻辑里漏掉的部分补出来的——源码里虽然没有现成的 MD5 工具类但注册功能已经有了后续你自己叠加上去很顺。3.2 DAO 模式加 JTable 数据模型是 Swing 项目最值得抄的部分Swing 写业务界面有个痛点JTable默认的数据模型是DefaultTableModel但这个模型对数据库查询结果并不友好——你要手动把ResultSet一条条转成Object[]塞进Vector或者二维数组里。项目里各个管理界面的写法几乎统一DAO 层负责查库返回List实体界面层再把这个 List 转化成表格能用的二维数据。我看它导出的 Excel 那张截图时注意到的第一件事是表头跟数据库字段名完全对不上。这是对的数据库字段s_no不能直接拿去做 Excel 的列名你要在代码里映射成“学号”。这个思路其实暗合了后面第四点我会提到的“多层数据映射”原理——界面上显示的是业务名代码里处理的是实体属性数据库里存的是表的列名。举个例子体检模块查出来的是这样一组字段映射数据库字段Java 实体属性JTable 列名h_nohealthNo体检编号s_nostudentNo学号h_heightheight身高/cmh_weightweight体重/kgh_chestchest胸围/cmh_datehealthDate体检日期逻辑说明这三层命名有一个看起很“绕”但实际特别重要的设计意图——不管哪一层改名其他两层不会全部跟着乱数据访问层对界面层是屏蔽的。如果你以后接 ORM 框架MyBatis 或 JPA这种分层会让你迁移时省非常多事。3.3 多选项高级查询和批量删除背后的 SQL 拼接技巧多选项高级查询.png和多选删除.png这两个功能在课设答辩时非常加分因为它们是“教科书外的真实需求”。多选项查询的难点在于用户可能只选了系别没选性别可能只填了身高范围没填日期你的 SQL 条件个数是动态的。项目里用的是字符串拼接加 flag 判断的做法第一步先拼固定前缀WHERE 11后面每个条件用AND接上StringBuilder sql new StringBuilder(SELECT * FROM health WHERE 11 ); if (!dept.equals(全部)) { sql.append(AND s_dept ? ); } if (minHeight 0) { sql.append(AND h_height ? ); } if (maxHeight 0) { sql.append(AND h_height ? ); }逻辑说明WHERE 11不是废话它是动态条件拼接的锚点。这样不管后面有没有条件追加SQL 语法都不会因为多出一个裸AND而报错。这种写法在老工程师眼里可能不优雅但对课设体量的系统来说是最稳的。参数说明minHeight和maxHeight用 0 作为“未填写”的哨兵值是因为身高不可能为 0这样就能用 0来判断用户是否真的输入了数值。如果你用空字符串做哨兵还得处理字符串转 int 的异常代码会多一截 try-catch。批量删除的 SQL 要稍微小心一点。常见的做法是拼IN子句但如果你直接字符串拼接学号可能会有 SQL 注入风险。稳妥做法是先把学号列表验证一遍只允许数字和有限符号再拼接进 SQLDELETE FROM health WHERE s_no IN (2025001, 2025002, 2025003)这个功能在多选删除.png里的交互逻辑是用户在 JTable 里勾选多行程序收集所有选中行的学号生成上面的 SQL 一次执行。不要写循环逐条 DELETE那样不仅慢而且遇到外键约束中断时会出现删一半的脏状态。4. 避坑手册从 MySQL 连接到 Excel 导入的五个常见翻车点4.1 MySQL 连接失败驱动版本和时区设置各占一半原因现象程序一启动登录界面点按钮就报Communications link failure或者The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。原因这个项目默认连的是 MySQL 5.x但如果你本机装的是 MySQL 8.x驱动 jar 不匹配加上连接串里没配serverTimezone。解决换 mysql-connector-java 8.x 的驱动连接串显式加?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8三个参数一个都不能少。4.2 中文乱码问题全在连接串和数据导入两个环节现象界面上显示的中文全部变成???或者菱形问号。原因数据库表是utf8但连接串没指定characterEncodingutf8或者dbstuhealth.sql导入时 MySQL 客户端默认用了latin1。解决先在 MySQL 命令行执行SET NAMES utf8mb4;再SOURCE dbstuhealth.sql;同时把 JDBC 连接串里的编码参数加上。这个坑我每次配课设项目都会遇到不是代码问题是环境问题。4.3 Excel 导入格式校验空行是最大元凶现象导入体检数据 Excel 时明明文件内容没问题程序却报数据越界。原因Excel 表格末尾往往存在“肉眼看不见”的空行POI 按行号读取时拿到的 Row 对象不为 null但里面的 Cell 全是 null代码没判空就直接调getStringCellValue()。解决遍历行时先用row null判行、再用cell null判单元格连续空行超过 3 行就 break。项目里导入Excel.png对应的代码逻辑如果有这层判断就不会炸没有的话你拿到手第一件事就是加上。4.4 多选删除时外键约束报错现象删除一个学生时提示Cannot delete or update a parent row: a foreign key constraint fails。原因学生表是主表体检表通过学号外键关联了它直接删学生主表记录会被数据库拒绝。解决要么先删从表记录再删主表要么建表时在FOREIGN KEY上声明ON DELETE CASCADE。项目初始的 SQL 如果没配级联删除这就是你大数据量操作时最可能遇到的第一个外键报错。4.5 Swing 界面卡死查询别放在事件线程里现象点击查询按钮后整个窗口“假死”标题栏显示未响应。原因耗时操作查库组装 TableModel放在了 Swing 事件分发线程里界面渲染被阻塞。解决用SwingWorker或者把查询丢进new Thread(() - {...}).start()查询完通过SwingUtilities.invokeLater()回到事件线程更新表格。课设答辩时如果评委现场狂点按钮没反应这基本就是扣分点。项目代码里这部分做得比较粗你要交高分版本的话这步必须改。5. 从档案管理到数据分析把系统升级成“能算数”的体检工具5.1 用分组查询替代肉眼统计体检数据才真正有价值系统虽然能录入和展示体检数据但我拿到手后发现它缺了一个关键的落点统计报表。一个学生身高 175cm、体重 70kg单看没有意义但如果按系别分组算出平均身高、平均体重数据就开始说话了。你可以在现有 DAO 层之上加一个统计方法用 GROUP BY 实现SELECT s_dept, COUNT(*) AS student_count, ROUND(AVG(h_height), 2) AS avg_height, ROUND(AVG(h_weight), 2) AS avg_weight, MAX(h_date) AS latest_date FROM health GROUP BY s_dept;逻辑说明GROUP BY s_dept把同系别的学生聚成一组AVG和ROUND组合可以输出保留两位小数的均值。这个统计结果可以作为“数据概览”面板的核心数据源比单纯展示明细列表要有说服力得多。参数说明ROUND(x, 2)是 MySQL 的保留小数位函数不要用 Java 端去四舍五入——数据库这边算好再取代码更干净。MAX(h_date)在这里表示每个系别最近一次体检日期方便判断数据新鲜度。5.2 给 Swing 界面插一个动态折线图面板源码包里那张动态折线图数据分析.png是我觉得整个项目最有亮点的部分。它展示的不是静态图片而是基于历史体检数据画出来的趋势折线图。实现路径不复杂先查询某个学生或者某个系别在过去 N 次体检中的平均体重得到一组(日期, 数值)序列然后用 Java 2D 绘图把点画在JPanel上连线形成折线图。这里不需要引入 JFreeChart 这种大而全的第三方库Swing 自带的Graphics2D就够用Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 (Graphics2D) g; int baseY getHeight() - 40; // 底部基线 int leftX 60; // 左侧留白 int stepX (getWidth() - leftX - 30) / (points.size() - 1); for (int i 0; i points.size() - 1; i) { int x1 leftX i * stepX; int y1 baseY - (int) (points.get(i).value * scale); int x2 leftX (i 1) * stepX; int y2 baseY - (int) (points.get(i 1).value * scale); g2.drawLine(x1, y1, x2, y2); } }逻辑说明paintComponent里先算出绘图区域的基线和左侧边距然后按数据点数均匀分布 X 坐标Y 坐标用(实际值 × 缩放系数)映射到面板像素空间。核心思路就是把“数值区间”映射成“像素区间”搞懂这个比例关系折线图就能正常显示。参数说明scale的取值很关键——如果写死为 1身高 180 会直接画到面板外面去。我一般会动态计算double maxVal points.stream().mapToDouble(p - p.value).max().orElse(1); double scale (getHeight() - 80) / maxVal;这样不管数据范围怎么变图形都会自适应地填满面板高度。这一步改完你就拥有了一张“读数据库实时刷新”的图表答辩时评委问起来你可以直接演示修改一条体检记录后折线跟着变。5.3 导出体检报表日期和表头是两处关键细节导出 Excel 功能项目本身已经实现了但如果你要把它变成答辩的加分项一个值得改造的点是导出文件名动态拼接日期。我看源码里导出文件名如果是写死的就会有个小问题连续导两次会把前一份覆盖掉。String fileName 体检报表_ new SimpleDateFormat(yyyyMMdd_HHmmss).format(new Date()) .xls;逻辑说明SimpleDateFormat把系统当前时间格式化成20250701_143000这种不带特殊字符的字符串拼到文件名后面保证每次导出都是新文件。这里的HHmmss是 24 小时制时分秒yyyyMMdd是年月日连在一起就是一份带时间戳的报表名。参数说明如果导出格式是.xls建议用 HSSFWorkbook如果是.xlsx用 XSSFWorkbook。两者不兼容用错了扩展名 Excel 打开文件会提示损坏。项目里导出Excel.png用的是老版.xls格式别自己画蛇添足改成.xlsx但又没换 Workbook 类型。5.4 这些坑我不会再踩第二次我带学生做课设这几年把同样的代码在不同机器上跑过很多遍踩得最多的是数据表和代码字段对不上。这个项目的data.xls里面有几列看起来是给导入功能测试用的样例数据但它的列顺序和 Java 代码里ImportExcelUtil读取的列索引必须完全一致——差一列身高和体重就会互换位置整个体检数据全错。从那以后我每次打开别人的课设项目第一件事永远是核对三样东西数据库建表脚本的列顺序、DAO 层实体类的字段定义、Excel 导入模板的表头顺序三个对齐了才动代码。这个习惯帮我省下了大量“明明代码没问题但结果不对”的排障时间。这份资源本身质量在课设里算中上但同样的坑它也有你拿到手先做这一步对齐后面能少流很多汗。希望帮到你。本文还有配套的精品资源点击获取
返回列表