简介:这是一套面向计算机、软件工程等专业学生的智慧医疗HIS系统完整源码与数据库资源,采用SpringBoot框架开发,适合用作毕业设计、期末大作业或课程设计。项目经本地编译可运行,评审得分98分,难度适中,内容经助教老师审定,兼顾学习性与实用性。压缩包共1302个文件,约20.62MB,以972个Java源文件为核心,辅以129个XML配置、49个JavaScript、37个HTML及16个Velocity模板,另有yml、properties、sql、css等资源,覆盖后端逻辑、前端页面与数据库脚本。系统通常包含患者信息管理、预约挂号、电子病历、药品库存、医生排班与财务管理等模块,遵循模块化与服务化设计,并注重权限管理、数据加密与操作日志等安全措施。目前已有183人学习下载,读者可借此掌握SpringBoot整合持久层框架、构建医疗信息系统的完整思路,为后续开发与求职积累实践基础。
1. 智慧医疗HIS系统源码拆包:一套能跑起来的毕业设计长什么样
去年帮几个同学看毕业设计,十份里有七份是各种管理系统,但真正能把「门诊挂号→医生开方→药房发药→收费结算」这条主线跑通的,不到三份。大部分项目卡在数据库表设计上,要么字段对不上业务,要么外键约束一加就报错。这次拿到的这套智慧医疗HIS系统源码,算是少见的「编译过、能运行、业务闭环完整」的版本。它基于SpringBoot搭建,配套完整数据库脚本,覆盖门诊、住院、药房、收费几个核心模块。适合正在做医疗信息化方向毕业设计、期末大作业的本科生,也适合想拿一个真实业务系统练手SpringBoot全栈开发的人。下面我按实际拆包和部署的顺序,把这份资源从环境准备到业务验证的完整路径讲清楚。
2. 环境准备与数据库初始化:从SQL脚本到可连接的数据源
拿到源码包之后,别急着打开IDE就点运行。HIS这类业务系统的第一道坎永远在数据库,表结构、初始数据、字符集、时区,任何一个对不上,启动就是一堆红字。这一章先把运行环境和数据库初始化做扎实。
2.1 运行环境清单与版本匹配
这套源码用的是SpringBoot 2.x系列,搭配MyBatis做持久层,前端是Thymeleaf模板加Bootstrap。常见做法是JDK 1.8、Maven 3.6以上、MySQL 5.7或8.0。我一般会先确认三件事:JDK版本、Maven仓库能不能拉到依赖、MySQL的字符集是不是utf8mb4。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8 | SpringBoot 2.x对JDK 8兼容最稳 |
| Maven | 3.6+ | 依赖下载走默认中央仓库即可 |
| MySQL | 5.7 / 8.0 | 8.0需要改驱动类名和连接串参数 |
| IDE | IntelliJ IDEA | 社区版够用,导入Maven项目方便 |
注意:如果你的MySQL是8.0,驱动类要从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.Driver,连接串后面要加serverTimezone=Asia/Shanghai,否则启动时会报时区错误。这个坑每年都有同学踩。
2.2 数据库脚本导入与表结构核对
源码包里一般会有一个sql目录,里面是建库建表加初始数据的脚本。导入之前先看一眼脚本开头的CREATE DATABASE语句,确认库名和后面配置文件里写的一致。
# 登录MySQL,导入数据库脚本 mysql -u root -p # 在MySQL命令行中执行 source /path/to/his_db.sql; # 导入完成后确认表数量 use his_db; show tables;导入之后不要只看「Query OK」,要确认几张核心表的数据量。sys_user(用户表)、patient_info(患者信息表)、drug_info(药品信息表)这三张表如果有初始数据,说明脚本导入完整。如果drug_info是空的,后面药房发药模块就没法演示。
-- 核对核心表数据量 SELECT COUNT(*) FROM sys_user; SELECT COUNT(*) FROM patient_info; SELECT COUNT(*) FROM drug_info;逻辑说明:sys_user决定你能不能登录系统,patient_info决定挂号模块有没有可选患者,drug_info决定开处方时能不能选到药。这三张表的数据完整性直接决定业务演示能不能走通。参数方面,如果drug_info为空,可以手动插入几条测试数据,字段包括药品编码、名称、规格、单价、库存数量。
2.3 application.yml配置修改与启动验证
数据库导入完成后,打开src/main/resources/application.yml,改数据源配置。这里有个血泪经验:不要只改url里的库名,username和password也要确认,很多同学本地MySQL密码和配置文件里写的不一样,启动直接连不上。
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/his_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password thymeleaf: cache: false prefix: classpath:/templates/ suffix: .html配置改完后,在项目根目录执行mvn spring-boot:run,或者在IDEA里直接运行启动类。看到控制台输出Started HisApplication in X seconds就算启动成功。浏览器访问http://localhost:8080,如果出现登录页,说明前后端链路通了。
提示:如果启动时报
Table 'his_db.xxx' doesn't exist,大概率是数据库脚本没导完,或者导到了错误的库里。回到MySQL用show tables确认一下。
3. 核心业务模块拆解:挂号、开方、发药、收费怎么串起来
环境跑通只是第一步,HIS系统的价值在于业务闭环。这一章按实际使用顺序,把门诊主线的四个模块拆开讲,每个模块说清楚它依赖哪些表、代码里怎么实现的、参数在哪里改。
3.1 门诊挂号模块:从患者建档到排队叫号
挂号是整个门诊流程的入口。代码里对应的Controller是RegistrationController,Service层是RegistrationService。核心逻辑分两步:先查患者是否已建档,没有就新建;然后生成挂号记录,分配科室和医生。
// RegistrationService.java 核心方法 public RegistrationResult register(RegistrationDTO dto) { // 1. 根据身份证号查患者,不存在则新建 Patient patient = patientMapper.selectByIdCard(dto.getIdCard()); if (patient == null) { patient = new Patient(); patient.setName(dto.getName()); patient.setIdCard(dto.getIdCard()); patient.setPhone(dto.getPhone()); patientMapper.insert(patient); } // 2. 生成挂号记录,状态设为"待就诊" Registration reg = new Registration(); reg.setPatientId(patient.getId()); reg.setDeptId(dto.getDeptId()); reg.setDoctorId(dto.getDoctorId()); reg.setRegTime(new Date()); reg.setStatus("WAITING"); registrationMapper.insert(reg); return new RegistrationResult(reg.getId(), "挂号成功"); }逻辑说明:先查后插是为了避免同一患者重复建档。status字段用WAITING表示待就诊,后面医生叫号时会改成IN_PROGRESS,就诊结束改成FINISHED。参数方面,deptId和doctorId来自前端下拉框,对应department表和doctor表的主键。如果挂号后医生端看不到患者,先检查registration表的doctor_id有没有写进去。
3.2 医生开方与药房发药:处方状态流转与库存扣减
医生开方模块对应PrescriptionController,药房发药对应PharmacyController。这两个模块通过处方状态字段联动:医生提交处方后状态是SUBMITTED,药房确认发药后改成DISPENSED,同时扣减药品库存。
// PharmacyService.java 发药核心逻辑 @Transactional public void dispense(Long prescriptionId) { Prescription pres = prescriptionMapper.selectById(prescriptionId); if (!"SUBMITTED".equals(pres.getStatus())) { throw new BusinessException("处方状态不正确,无法发药"); } // 遍历处方明细,逐条扣库存 List<PrescriptionItem> items = itemMapper.selectByPrescriptionId(prescriptionId); for (PrescriptionItem item : items) { int affected = drugMapper.reduceStock(item.getDrugId(), item.getQuantity()); if (affected == 0) { throw new BusinessException("药品库存不足:" + item.getDrugName()); } } pres.setStatus("DISPENSED"); prescriptionMapper.updateById(pres); }逻辑说明:@Transactional保证扣库存和改状态在同一个事务里,任何一条药品库存不够就整体回滚,不会出现「扣了一半」的情况。reduceStock方法在Mapper里对应一条UPDATE drug_info SET stock = stock - #{qty} WHERE id = #{id} AND stock >= #{qty},用stock >= qty做乐观锁,避免并发超卖。参数方面,prescriptionId从前端发药列表传过来,quantity来自处方明细表。
3.3 收费结算模块:费用计算与支付状态同步
收费模块对应BillingController,核心是根据处方明细计算总金额,生成收费单,支付完成后更新状态。这里涉及三张表:prescription、prescription_item、billing。
-- 收费单生成的核心查询:汇总处方明细金额 SELECT p.id AS prescription_id, SUM(d.price * i.quantity) AS total_amount FROM prescription p JOIN prescription_item i ON p.id = i.prescription_id JOIN drug_info d ON i.drug_id = d.id WHERE p.id = #{prescriptionId} GROUP BY p.id;逻辑说明:这条SQL把处方明细里的药品单价和数量乘积累加起来,得到应收总额。billing表插入时带上这个金额和UNPAID状态。支付完成后,billing.status改成PAID,同时prescription.status改成PAID,药房才能看到待发药列表。参数方面,如果收费金额算出来是0,检查drug_info表的price字段有没有值,以及prescription_item里有没有关联的药品记录。
注意:收费和发药的顺序不能反。如果先发药后收费,库存已经扣了但钱没收到,业务上就是漏洞。代码里药房发药时会校验
billing.status是否为PAID,这个校验不要注释掉。
4. 避坑与常见问题排查:启动报错、页面404、数据对不上
这套源码虽然经过编译验证,但不同机器环境不一样,实际部署时还是会遇到各种问题。这一章列几个高频翻车场景,按「现象→原因→解决」的方式写清楚,方便你对号入座。
4.1 启动报错:Communications link failure
现象:启动时控制台报Communications link failure,或者Access denied for user。
原因:MySQL服务没启动,或者application.yml里的用户名密码和本地不一致。也有可能是MySQL端口不是默认的3306。
解决:先确认MySQL服务在运行,用mysql -u root -p能登录。然后核对application.yml里的url、username、password三项。如果端口改了,url里要同步改。改完重启应用。
4.2 页面404:Thymeleaf模板路径不对
现象:登录页能打开,但点登录后跳转404,或者静态资源加载不出来。
原因:Thymeleaf默认从classpath:/templates/找模板,如果HTML文件放在webapp目录下,或者application.yml里prefix配错了,就会404。
解决:确认HTML文件在src/main/resources/templates/目录下,application.yml里spring.thymeleaf.prefix保持默认值。如果用了自定义路径,改成实际路径。静态资源(CSS、JS)放在src/main/resources/static/下。
4.3 数据对不上:挂号后医生端看不到患者
现象:挂号模块提示成功,但医生登录后待就诊列表是空的。
原因:挂号记录的doctor_id字段没写进去,或者医生登录的账号和挂号时选的医生不是同一个人。
解决:查registration表,看刚插入的那条记录doctor_id有没有值。如果为空,检查前端传参和后端接收字段名是否一致。如果值不对,检查医生下拉框的value是不是医生表的主键。
4.4 库存扣减异常:发药后库存没变
现象:药房点发药提示成功,但drug_info表的stock字段没减少。
原因:reduceStock的SQL条件没匹配到记录,比如stock >= quantity不成立,或者drug_id传错了。
解决:先查prescription_item表里这条处方的drug_id和quantity,再查drug_info表对应记录的stock。如果stock小于quantity,说明库存本来就不够,发药应该失败。如果stock够但没扣,检查Mapper里的SQL有没有写错条件。
4.5 中文乱码:数据库字符集不是utf8mb4
现象:患者姓名、药品名称显示成问号或乱码。
原因:建库时字符集用了latin1,或者连接串没指定characterEncoding=utf8。
解决:重新建库,指定CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci。连接串加上useUnicode=true&characterEncoding=utf8。已经建好的库可以用ALTER DATABASE his_db CHARACTER SET utf8mb4;修改,但表里的数据可能需要重新导入。
5. 二次开发与功能扩展:从能跑到能改的进阶路径
把系统跑起来只是起点,毕业设计答辩时老师往往会问「你在这个基础上做了什么改进」。这一章说几个适合在现有源码上做的扩展方向,以及怎么验证改动有没有生效。
5.1 增加科室管理模块:CRUD的标准写法
现有系统里科室数据是写死在初始化脚本里的,没有管理界面。加一个科室管理模块是最稳妥的扩展,因为它是标准的增删改查,不涉及复杂业务逻辑。
// DepartmentController.java 新增科室 @PostMapping("/add") public Result addDepartment(@RequestBody Department dept) { // 校验科室名称不能重复 Department exist = departmentMapper.selectByName(dept.getName()); if (exist != null) { return Result.error("科室名称已存在"); } dept.setCreateTime(new Date()); departmentMapper.insert(dept); return Result.success("添加成功"); }逻辑说明:先查重再插入,避免同名科室。createTime字段记录创建时间,方便后续排序。前端加一个表单页面,字段包括科室名称、科室编码、负责人。改完之后在department表里确认新记录有没有写进去。
5.2 处方打印功能:用模板引擎生成PDF
处方打印是HIS系统的常见需求。可以在现有处方详情页加一个「打印」按钮,后端用模板引擎渲染HTML,再转成PDF返回。
// PrescriptionPrintService.java 生成打印HTML public String generatePrintHtml(Long prescriptionId) { Prescription pres = prescriptionMapper.selectDetailById(prescriptionId); Context context = new Context(); context.setVariable("pres", pres); context.setVariable("items", pres.getItems()); // 使用Thymeleaf模板引擎渲染 return templateEngine.process("print/prescription", context); }逻辑说明:selectDetailById要关联查询患者信息、医生信息、药品明细,返回一个完整的处方对象。模板文件放在templates/print/prescription.html,用表格展示药品名称、规格、数量、用法。渲染出来的HTML可以直接在浏览器里打印,也可以接PDF转换工具。
5.3 数据统计看板:用SQL聚合代替手写循环
答辩时如果有一个数据看板,展示当日挂号量、处方量、收费金额,会加分不少。实现方式很简单,写几条聚合SQL,前端用ECharts渲染。
-- 当日挂号量统计 SELECT COUNT(*) AS reg_count FROM registration WHERE DATE(reg_time) = CURDATE(); -- 当日收费金额统计 SELECT IFNULL(SUM(total_amount), 0) AS income FROM billing WHERE DATE(create_time) = CURDATE() AND status = 'PAID';逻辑说明:CURDATE()取当天日期,DATE(reg_time)把时间字段转成日期再比较。IFNULL处理没有收费记录时返回0的情况。这两条SQL的结果直接传给前端,用ECharts的柱状图和数字卡片展示。参数方面,如果要看本周或本月,把CURDATE()换成DATE_SUB(CURDATE(), INTERVAL 7 DAY)之类的表达式。
5.4 改动验证:三步确认法
每次改完代码,按这三步确认改动生效:第一步,重启应用看控制台有没有报错;第二步,打开对应页面操作一遍,看数据有没有写进数据库;第三步,直接查数据库表,确认字段值符合预期。我一般会在这三步都走完之后,再点一遍相关模块的联动功能,比如加了科室管理之后,去挂号页面看新科室有没有出现在下拉框里。
从那以后我每次拿到一套新源码,都强制先走一遍「导库→改配置→启动→跑主线业务」这个流程,确认基线没问题再动代码。这套HIS系统源码的基线是清晰的,数据库脚本完整,业务闭环能跑通,适合拿来练手或者作为毕业设计的起点。希望帮到你。
本文还有配套的精品资源,点击获取