☰
医院管理系统课程设计:Spring Boot+MyBatis数据库与核心模块实战
2026/9/26 6:19:56 网站建设 项目流程

简介:这是一份以纯C语言实现医院管理系统的完整课程设计资源,覆盖患者信息管理、预约挂号、诊疗记录等核心业务模块。资源以C语言数据结构与逻辑设计为基础,结合API接口与SQL数据库操作,完成关系表结构定义、增删改查及事务处理,并包含命令行或图形界面的交互设计。配套总结报告涵盖项目背景、需求分析、系统设计、实现过程、测试结果与经验总结,适合高校计算机专业学生、课程设计开发者以及想练习C语言与数据库综合应用的初学者参考。压缩包共16个文件,以cpp源文件、h头文件、o目标文件、exe可执行程序、rc资源文件和docx总结报告为主,类型覆盖源码、界面资源、编译产物和文档说明,整体大小约566KB。已有1096人学习下载。通过这份资源,读者可以快速了解完整项目的目录组织方式、核心代码结构与报告撰写框架,也能参考其API调用与SQL交互写法,为同类管理系统的开发或课设答辩准备提供有力支撑。

1. 整体设计思路:别一上来就写代码,先把“需求边界”框死

医院管理系统,是课程设计里生命力最顽强的一个题。每年都有学生选它,但每年也都有不少人做到一半就卡死。为什么?因为这个题的“真实度”太高了,真按三甲医院的 HIS 系统来做,模块能列三四十个,数据表能设计上百张,一个课程设计做完,人也就废了。

所以接这个题的第一步,不是急着找框架、建工程,而是先明确自己的“边界”:你是在做一个用于教学演示的课程设计,不是在做商用产品。

我当时拿到这个题之后,先花了一晚上把需求砍成了四个核心闭环:

患者管理闭环:建档 → 挂号 → 就诊 → 开处方 → 收费取药。医生工作闭环:登录 → 查看待诊患者 → 填写诊断和处方。药品管理闭环:药品增删改查 → 库存扣减 → 补库存。系统管理闭环:用户/角色管理 → 账号分配 → 基础数据维护(科室、医生排班)。

砍完之后,范围一下子清晰多了。这个边界很重要:它既能完整展示一个医院管理系统的主干业务流,答辩的时候老师问“你这系统覆盖了哪些环节”,你能说清楚;又不会因为摊子铺得太大导致代码烂尾。

技术选型上,我见过有人用 Python Flask、有人用 ASP.NET,有人干脆用 GUI 程序。但最稳妥、资料最多、答辩最好讲的组合还是 Java 系那一套:Spring Boot + MyBatis + MySQL + Thymeleaf。有条件、前端功底好的可以上 Vue 做前后端分离,课程设计其实没必要。Thymeleaf 服务端渲染对“数据回显”“权限拦截”这种场景演示效果非常直观,而且代码量少,出 bug 的概率低。如果你只学过 JSP/Servlet,也可以,就是把 Spring Boot 换成原生 Servlet 那套,原理一样,只是开发效率低一点。我给你的建议是:别在课程设计里学新框架,用你最有把握的那套。

2. 数据库设计:这 9 张表,够你撑起整个系统了

表结构设计是医院管理系统课程设计里最见功夫的部分。很多人的表就是“对着需求字段乱建”,结果业务一跑起来,数据根本对不上。正确的做法是从业务流程反推表结构:先画一遍患者从进医院到离开要经过哪些环节,每个环节需要记哪些数据,然后再把环节之间的关系抽象出来。

我最终定下的核心表,一共 9 张,完全能支撑前面的业务闭环,同时也能在报告里画出像样的 ER 图:

表名用途核心关键字段外键关系
sys_user系统用户(登录账号)username, password, role关联 doctor/patient 可空
base_dept科室表dept_name, location, leader无
base_doctor医生表doctor_name, title, dept_iddept_id 关联科室
base_patient患者表patient_name, gender, age, id_card, phone无
reg_registration挂号表patient_id, doctor_id, dept_id, reg_date, status三张外键都在
med_drug药品表drug_name, spec, price, stock无
doc_prescription处方表reg_id, doctor_id, diagnosis关联挂号与医生
doc_prescription_item处方明细表prescription_id, drug_id, quantity, amount双外键
fin_payment收费记录表reg_id, total_amount, pay_time, pay_method关联挂号

这里面最值得展开讲的是挂号表和处方明细表的设计。

挂号表的表名我用了reg_前缀而不是outpatient,是图省事?不是。命名前缀统一用模块缩写,代码里一眼就能看出表属于哪个业务域,排查问题的时候非常省时间,课程设计报告里也能写上“模块化命名规范”这种加分句。

处方主表和处方明细表,为什么要拆成两张?这就好比超市小票:主表记录“这一单是哪个医生开的、诊断是什么”,明细表记录“这单里到底买了哪几样药、每样几盒、多少钱”。如果不拆,一个人开了三盒阿莫西林就得存三行重复的挂号信息和诊断信息,数据冗余大,改起来也麻烦。拆成主从表,一个prescription_id就能把整单的明细全部查出来,这也是业务系统里非常标准的建模手法。

再看金额字段。药品表里price用DECIMAL(10,2),一分钱都不能差,用 FLOAT 会出精度丢失的问题,这点课程设计报告里一定要写进去,属于体现思考深度的细节。quantity用 INT,处方明细里算amount时用 Java 端计算后再入库,尽量别用数据库函数做运算,这样逻辑都在应用中,排查方便。

建表这块还有一个教训是:先建基础表,再建业务表。科室、医生、药品这类“数据字典”,是挂号表、处方表的外键来源。我一上来先建了挂号表,结果 MyBatis 初始化时外键关联报错,回头重新理顺序。你建表直接按sys_user → base_dept → base_doctor → base_patient → med_drug → reg_registration → doc_prescription → doc_prescription_item → fin_payment这个顺序来,一次过。

这里再给一段 MySQL 建表脚本里最容易出错的“外键 + 索引”写法,完整脚本太长,挑一个最有代表性的reg_registration:

CREATE TABLE reg_registration ( reg_id INT PRIMARY KEY AUTO_INCREMENT, patient_id INT NOT NULL, doctor_id INT NOT NULL, dept_id INT NOT NULL, reg_date DATETIME DEFAULT CURRENT_TIMESTAMP, status TINYINT DEFAULT 0 COMMENT '0-待就诊 1-已就诊 2-已取消', reg_no VARCHAR(32) UNIQUE COMMENT '挂号流水号', CONSTRAINT fk_reg_patient FOREIGN KEY (patient_id) REFERENCES base_patient(patient_id), CONSTRAINT fk_reg_doctor FOREIGN KEY (doctor_id) REFERENCES base_doctor(doctor_id), CONSTRAINT fk_reg_dept FOREIGN KEY (dept_id) REFERENCES base_dept(dept_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

注意到reg_no那个唯一索引没有?挂号流水号是业务的“门面”,比如202505201030001这种,直接关系到一个患者的寻医轨迹。我在代码里用时间戳加随机数生成,避免并发下重复。这个细节答辩的时候老师问“并发挂号怎么处理”,你就能答上来了。这是加分项。

3. 核心模块实现:抓住这三个功能,就抓住了系统骨架

3.1 登录与权限拦截:用拦截器保证医生只能干医生的事

登录模块不难,难的是“登录之后的权限控制”。一个医生登录进来,不能看到患者管理菜单,更不应该能随手把系统用户给删了。这就意味着后端每个接口都要做角色校验,不能只在前端把菜单隐藏了就完事。

Spring Boot 里最简洁的做法是写一个HandlerInterceptor拦截器,在请求进入 Controller 之前做两件事:第一,检查 Session 里有没有登录用户;第二,检查请求的接口前缀是否匹配当前用户角色。

public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("loginUser"); if (user == null) { response.sendRedirect("/login"); return false; } // 按模块前缀做角色校验 String uri = request.getRequestURI(); SysUser loginUser = (SysUser) user; if (uri.startsWith("/admin/") && !"ADMIN".equals(loginUser.getRole())) { response.sendError(403); return false; } if (uri.startsWith("/doctor/") && !"DOCTOR".equals(loginUser.getRole())) { response.sendError(403); return false; } return true; } }

注意uri.startsWith("/admin/")这种粗粒度控制只适合课程设计。真实的系统会有更复杂的菜单权限、按钮权限和数据权限。但课程设计里能拿出“拦截器统一校验”这个方案,说明你理解“认证和授权是两回事”,这已经超过一半的人了。密码存储记得用 MD5 加盐或者 BCrypt,别明文存数据库。老师要是一时兴起打开数据库看到明文密码,印象分会掉一大截。

3.2 挂号流程:事务让“减号源、增挂号、扣库存”不打架

挂号的背后的业务流程是:选科室 → 选医生 → 选号源 → 生成一条挂号记录 → 医生排班表中的号源数量减一。这三个操作必须绑在一起,任何一个失败,前面两个都要回滚。

我用一个挂号 Service 方法来演示“事务操作”的写法,这是面试和答辩都被问烂了的“核心题”:

@Service public class RegistrationService { @Autowired private RegistrationMapper regMapper; @Autowired private DoctorScheduleMapper scheduleMapper; @Transactional(rollbackFor = Exception.class) public void register(Registration reg) { // 1. 校验号源是否充足 DoctorSchedule schedule = scheduleMapper.selectById(reg.getScheduleId()); if (schedule.getRemainCount() <= 0) { throw new BusinessException("该医生号源已满"); } // 2. 保存挂号信息 regMapper.insert(reg); // 3. 号源扣减 scheduleMapper.decreaseRemainCount(schedule.getId()); } }

@Transactional注解是 Spring 声明式事务的开关,rollbackFor = Exception.class表示任何异常都回滚。课程设计里业务大多数是单表单操作,很难体现事务的作用,挂号恰好是少有的能讲清楚为什么要用事务的场景。我之前看到有同学在那个方法里忘了加事务,结果测试的时候故意让第三步报错,挂号记录还是写进库了,演示当场翻车。加了事务之后,数据就永远是完整的了。

这个小节我建议你在报告里放一张“时序图”,把患者、前端、Controller、Service、数据库之间的调用关系画清楚。不用工具画,用 draw.io 就能画,放在核心功能设计那一节,非常撑场面。切忌用 mermaid 画,答辩 PPT 一般都不支持渲染。

3.3 查询与统计:MyBatis 动态 SQL,一张表救人

管理系统逃不掉各种条件查询:按患者姓名查、按科室查、按日期范围查、按状态查。每个查询条件的组合都不一样,用 Java 拼 SQL 是灾难,用 MyBatis 动态标签就好办多了。

以“挂号记录分页查询”为例,条件可能有无:患者名的模糊、科室 ID、状态、日期范围。动态 SQL 的where标签会自动去掉多余的 AND,很好用:

<select id="selectRegList" resultType="com.example.entity.RegistrationVO"> SELECT r.*, p.patient_name, d.doctor_name, dept.dept_name FROM reg_registration r LEFT JOIN base_patient p ON r.patient_id = p.patient_id LEFT JOIN base_doctor d ON r.doctor_id = d.doctor_id LEFT JOIN base_dept dept ON r.dept_id = dept.dept_id <where> <if test="patientName != null and patientName != ''"> AND p.patient_name LIKE CONCAT('%', #{patientName}, '%') </if> <if test="deptId != null"> AND r.dept_id = #{deptId} </if> <if test="status != null"> AND r.status = #{status} </if> <if test="startDate != null"> AND r.reg_date &gt;= #{startDate} </if> <if test="endDate != null"> AND r.reg_date &lt;= #{endDate} </if> </where> ORDER BY r.reg_date DESC </select>

这里有几个注意点:

  • LEFT JOIN而不是INNER JOIN:比如一个医生可能还没有任何挂号记录,用 INNER JOIN 查出来就少了医生信息;LEFT JOIN 保住了主表的完整性。
  • <if>里的status != null:注意status如果是 Integer 类型,要判断!= null,同时如果业务里状态有0这种值,判断里不能写!= '',否则0会被当成空字符串过滤掉。
  • &gt;=和&lt;=是 XML 转义:在 MyBatis XML 里写不了>和<,要用转义字符,不然 XML 解析直接报错。

统计报表也是课程设计里容易出彩的地方。比如“每天挂号量趋势图”的 SQL,其实就几行 GROUP BY:

SELECT DATE(reg_date) AS regDay, COUNT(*) AS cnt FROM reg_registration GROUP BY DATE(reg_date) ORDER BY regDay;

后端接个 ECharts 就能画折线图,效果非常直观。有些同学到了数据可视化就慌,实际上 ECharts 官方文档的例子直接拷贝改数据就能用,完全不用从零学。我建议你把“挂号统计图表”做成一个亮点功能,因为课程设计答辩的时候,“你这是不是只是简单的增删改查”是最常被质问的问题,你亮出一张图表来,说服力马上不一样。

4. 前端页面:别在 “美化” 上浪费太多时间,但这 3 件事必须做到

前端是课程设计里最容易走极端的地方。

一种极端是把所有精力花在调 CSS 上,搞一堆动画效果,结果后端逻辑一塌糊涂;另一种极端是完全不做样式,白底黑字的表格往那一放,老师一眼就觉得是“应付”。我的建议是:样式做到“干净、规范、逻辑清晰”就够了,不需要惊艳。实际开发里前端框架都封装好了,你学会用 Bootstrap 或 Layui 的现成组件就够。

具体到页面,有这么几个关键点需要注意:

登录取色,别做纯白背景,用一个带医疗感的淡蓝色调(#e8f4fd这种)做侧边栏的底色,能马上把“课程设计感”降下来。页面布局统一:左侧菜单栏,右侧内容区。左侧菜单按角色动态渲染,管理员看到的是“系统管理”菜单,医生看到的是“我的患者”“开处方”菜单。用 Thymeleaf 的sec:authorize或者前端判断用户角色都行。

表单校验不能只靠前端。比如添加药品时库存不能为负数,前端 JS 校验做了,后端 Service 也要再校验一次。我在帮同学调 bug 时就发现,他前端 input 加了type="number"以为万事大吉,结果用接口工具直接调后端接口传了个负数进去,库存变成了 -5。所以前后端各校验一遍,这就是软件开发里常说的“永远不要信任客户端输入”,报告中可以单独写一条。

Tab 管理和提示信息要做足:增删改查操作之后给用户一个明确的反馈,比如“添加成功”“删除失败:该科室下存在医生”,而不是啥提示都没有直接把数据刷没了。用 Thymeleaf 可以在页面加一个全局的消息组件,存到 Model 里model.addAttribute("msg", "操作成功"),然后模板里判断msg非空就渲染一个 alert 提示条。这个细节能让系统看起来“像个正式的项目”。

前端还有个很多人踩的坑:静态资源路径。Spring Boot 默认把src/main/resources/static下的文件映射为根路径资源,但如果你配置了spring.mvc.static-path-pattern=/static/**,页面里的 CSS/JS 引用路径就得同步调整。不然就会出现“HTML 能打开,但没有任何样式和图”的诡异情况,排查一下午发现只是路径写错。

5. 总结报告的写法:把“做了什么”升级为“为什么这么做”

课程设计有两份交付物,一个能跑的系统,一份报告。我见过系统做得一般但报告写得漂亮,最后拿高分的人;也见过系统完成度很高但报告上全是无意义的流水账最后被压分的人。实话实说,报告是老师快速判断你水平的最重要依据,值得花时间认真写。

一份好的课程设计报告,结构可以这样组织:

第一章 绪论:写清楚项目背景——为什么要做一个医院管理系统,现有医院信息化有哪些痛点(排队久、药房库存不透明、人工统计效率低等),本课题要达到的目标。注意不要大段复制网上的“医院信息化意义”的套话,用一两段语言概括清楚即可。

第二章 需求分析:这是报告的灵魂。要画用例图(角色与功能的关系图),列功能需求清单(模块划分、每个模块的核心功能),写清楚非功能需求(系统响应时间、并发量、安全性要求)。用例图画好,能体现出你对“用户视角”的理解。

第三章 系统设计:包含总体架构图、技术选型与理由、功能模块设计图、数据库 E-R 图、核心表结构说明。这块是给老师展示“设计能力”的地方,别只放代码截图,要放图、放表、放设计思路。

第四章 系统实现:分模块贴核心代码并逐段解释。注意不要大段大段贴代码然后什么都不说,那样既浪费字数又显得没有理解。我写的时候每段代码配合一个“设计说明”,比如“这段用拦截器实现了权限控制,避免未登录用户访问内部页面”,再加一个“核心逻辑”说明。

第五章 系统测试:表格化的测试用例记录,包括测试编号、测试项、操作步骤、预期结果、实际结果、是否通过。这里不要求你用完整的测试框架写自动化测试,但手工用例至少写 8~10 个,覆盖登录失败、挂号成功后号源减少、删除有外键关联的数据被拦截、非法访问直接跳登录页等场景。

第六章 总结与展望:写“本系统实现了什么”“遇到的最大挑战是什么、怎么解决的”“还有哪些不足、未来怎样改进”。最后一段千万别写“由于时间紧、水平有限,系统还存在很多不足之处,敬请老师批评指正”这种模板,老师看了几百遍,起不到好效果。换成具体的不足,比如“目前挂号模块不支持退号退费,后续可以通过新增退费状态和退费金额字段来实现”,你会显得是真的认真思考过问题。

6. 常见问题与排查技巧:这五个坑,我基本都踩过

问题一:数据库连接时报Public Key Retrieval is not allowed。这是 MySQL 8.0 之后的新坑,连接数据库的 URL 里要加一个参数allowPublicKeyRetrieval=true&useSSL=false。完整的 JDBC 串长这样:

jdbc:mysql://localhost:3306/hospital_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

课程设计环境里 MySQL 8.x 是大趋势,这个参数问题几乎是必踩的,提前把 URL 写好就能省一晚上排查时间。

问题二:Tomcat 端口被占用。启动 Spring Boot 报Port 8080 was already in use,要么改端口:server.port=8081,要么把占用进程找出来杀掉。Windows 可以用netstat -ano | findstr 8080,拿到 PID 之后taskkill /F /PID 端口号,MacOS/Linux 用lsof -i:8080和kill -9 PID。这个属于环境问题,不是代码问题,心态上别慌。

问题三:乱码。这是老生常谈。控制台乱码多半是编码不一致,IDE 设置 UTF-8,数据库连接 URL 也设置 UTF-8,数据库表创建时DEFAULT CHARSET=utf8mb4,三处都对齐才不容易出乱码。页面乱码还要检查 Spring Boot 里配置的字符过滤器,在application.yml中加server.servlet.encoding.force=true。注意 MySQL 统一 utf8mb4 才是正确的,单纯 utf8 存 emoji 表情会报错,写进数据库设计心得也是一条加分项。

问题四:删除数据时报外键约束错误。比如你要删除一个科室,但这个科室下面还有医生,就会报外键约束异常。两种处理方式:一种是用逻辑删除(加一个deleted字段,查数据的时候带上WHERE deleted=0),不用物理删除,这也是很多商用系统的做法;另一种是在删除之前先校验子表是否存在关联数据,存在就提示“请先清空该科室下的医生”。课程设计阶段推荐用第二种,代码直观,也好讲清楚。

问题五:MyBatis 里出现Invalid bound statement (not found)。这个基本是 Mapper XML 文件的 namespace 和接口没对上,或者 XML 文件没有被 Maven 编译到 target 目录。很多人忘了在pom.xml里配置resources标签包含mapper目录,导致 XML 不打进包。排查方法很简单:你去 target 目录里看有没有 XML 文件,没有就是没编译进去,在 pom.xml 里加配置,别去改一堆没用的地方。

7. 最后再聊几句实在话

我做完这个医院管理系统的课程设计之后,最大的体会是:课程设计的价值不在于系统有多完善,而是给你一个机会把平时零散学的东西串成一条线。数据库课上讲的外键、事务、范式,Java 课上讲的面向对象、集合框架,软件工程课上讲的需求分析、用例图,在一门课设里全部汇到一起变成能跑的东西,这个“串起来”的过程,才是我认为做课设最大的收获。

说回这个项目,它虽然是一个“老掉牙”的题目,但仔细想一想,无论是用户角色、业务流转,还是权限管理、数据统计,每一个点都紧密对应着实际项目中反复出现的需求。你把这一套搞透了,后面做任何管理系统,求职类、图书类、宿舍管理类,都是同一套方法论换皮而已,核心骨架完全是一模一样的。

如果时间充裕,我建议在这个基础上试着加一个“住院管理”模块,把床位分配、住院费用明细、出院结算做出来。这个模块会让你的项目从“门诊流程”升级成“完整的院内业务闭环”,答辩时明显更有底气。就算来不及做完,把报告里的“展望”写得足够具体可信,老师也看得出来你对这个系统有自己的理解。

做课设有时候就是拼谁更细心、谁更愿意多往前走一步。你愿意把这个二十年前的老题目做到什么程度,它最后也就会回馈给你什么样的成绩。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询