资讯详情

Spring Boot医院管理系统源码实战:HIS部署与二次开发详解

📅 2026/10/7 3:27:29 | 华诺云谱 👁 阅读
Spring Boot医院管理系统源码实战:HIS部署与二次开发详解
简介这是一份面向Java开发者和医院信息化初学者的Spring Boot医院管理系统(HIS)源码基于springbootshirolayuijquerythymeleaf构建内置shiro安全框架与layui前端界面覆盖门诊、住院、系统、统计、数据中心、排班、仓库、药房等核心业务模块重点实现患者挂号信息校验、医生排班与住院流程管理。系统在门诊环节支持录入患者姓名、年龄、手机号、性别、身份证号等详细信息选择科室、挂号类型和医生后自动计算挂号费并会校验手机号或身份证号是否正在就诊避免重复挂号住院管理则跟踪患者入院、用药、护理等环节适合学习企业级项目的权限控制、模块化开发与数据库设计。压缩包为117MB的7z文件内含约2000个文件主要包括JavaScript、TypeScript、Java源码、JSON配置、Markdown文档、XML描述及SQL脚本附带安装视频和说明文档可辅助在JDK8、MySQL、IDEA、Maven环境下完成部署运行。目前已有7487人学习下载对毕业设计、项目实训或HIS二次开发都有直接参考价值。1. Spring Boot 医院管理系统源码能直接跑的 HIS 长什么样医院信息系统在圈里一直有点“黑匣子”的意思——你在网上搜“Java 医院系统源码”能翻到一堆写着 HIS 的项目但多数是半成品要么缺模块要么数据库脚本根本导不进去。这套 Spring Boot HIS 源码属于那种“能直接当毕业设计、也能当二次开发底子”的类型它把挂号、门诊、收费、药房、住院这几个核心环节串成了一条完整链路用 Spring Boot 2.x MyBatis-Plus MySQL 搭起来的标准分层结构。对正在做 Java 项目、想找完整业务闭环源码的人来说这东西不是玩具它里面那张几十张表的库结构比网上那些学生管理系统有价值得多。更重要的是它带安装视频从 JDK、MySQL 到 IDEA 启动一步一步录好的省掉了最让人上火的起步阶段。这篇笔记我就按“模块拆解 → 本地部署 → 踩坑记录 → 二次开发”的顺序把这份源码里你能复用的东西全给你捋一遍。2. 先看懂 HIS 的业务骨架挂号、收费、药房、住院的数据怎么流转2.1 模块边界从门诊到住院的完整闭环你在拆这套源码之前得先有个心理预期HIS 不是由一个“超级大模块”构成的它更像一组互相调用的子服务拼起来。这套源码虽然没拆成微服务但在业务代码上是分了层的这一点非常关键。它核心包含这几个模块门诊挂号、门诊收费、药房管理发药退药、住院登记、医生工作站写病历、开医嘱、基础数据维护科室、药品、医生排班。说白了一个患者从进医院大门到办完住院整套流程在这套系统里是能走通的——挂个号医生接诊开单去收费处交钱药房看到收费记录发药住院的话再走一套登记流程。数据模型上患者信息、挂号记录、收费单、处方明细、药品库存、医嘱记录这些表之间有明确的外键关联不是东一张表西一张表拼出来的。这也是我判断一套 HIS 能不能用的第一标准业务闭环能不能走通而不只是界面好不好看。拆源码的时候我建议你先在 navicat 里把表结构过一遍重点关注patient_info患者主档、register_info挂号表、prescription_item处方明细、settlement_info结算单这四张表。你看明白了它们之间的 join 关系也就看明白了整个系统的钱和药是怎么动的。2.2 核心表结构拆解患者、挂号、收费、药房之间的关联关系拿到数据库脚本后别急着跑起来先把表关系理清楚。下边这句 SQL 是我在拆这套源码时最常用的探查方式你可以直接放到 Navicat 里看这个系统的骨架SELECT TABLE_NAME AS 表名, TABLE_COMMENT AS 注释, COLUMN_NAME AS 字段, COLUMN_TYPE AS 类型, IS_NULLABLE AS 是否为空 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA his_db -- 你的数据库名 ORDER BY TABLE_NAME, ORDINAL_POSITION;这套脚本能一次性把系统里所有表和字段的注释导出来。从字段命名习惯上你能很快判断出这个系统是 MyBatis-Plus 风格create_time、update_time、逻辑删除del_flag还是纯 MyBatis 风格。这套源码用的是前者这也就意味着单表 CRUD 几乎不用写 XMLBaseMapper直接搞定你只需要把精力放在多表关联和业务状态的流转上。核心表之间的关系大致是这样的表名作用关键外键/字段patient_info患者主档patient_no, name, id_cardregister_info挂号记录patient_id, doctor_id, dept_id, visit_timeprescription_header处方单头register_id, total_amount, statusprescription_item处方明细prescription_id, drug_id, quantitydrug_info药品字典drug_code, stock, retail_pricesettlement_info收费结算register_id, pay_type, amount这套设计的核心其实就一句话挂号单是主线收费单是凭证处方明细是药房发药的依据。只要这三张表的状态对得上整个系统的资金流和药品流就是干净的。我见过不少烂源码处方明细里药品 ID 和药品字典对不上导出的报表全是负数库存基本都是表关系设计时就没想清楚。这套源码在这一点上做得很规矩省了你不少清洗数据的功夫。2.3 登录权限和角色隔离为什么分诊台看不到收费菜单HIS 系统里最容易被忽略但实际很重要的部分是权限模型。每个科室的人进去看到的界面应该完全不一样——分诊台的护士不该看到收费报表药房的人不该看到患者病历。这套源码用的是 Shiro 或者 Spring Security 做的菜单权限隔离你在sys_menu、sys_role、sys_user_role这三张表里能直接配出角色-菜单-用户的三角关系。生产环境里我一般建议你保持这种基于角色的访问控制模型不动不要去改成在控制器里写死if (user.getRoleId() 1)这种方式因为访问权限逻辑一旦硬编码进业务代码里后期给新员工配权限就成了地狱。在配置权限时注意一下登录用户的加密方式看是 MD5 还是 BCrypt。如果是 MD5 且没加盐建议你接手后直接改成加盐加密——这是一套系统安身立命的基础不值得偷懒。3. 把系统跑起来JDK、MySQL、IDEA 全流程实操3.1 环境准备与版本选择不是越新越好这套源码的坑不在功能而在环境。Spring Boot 项目一旦版本不匹配启动直接报一堆诡异的错。我的建议是严格按照源码里pom.xml写的版本来不要想当然地去用最新的 JDK 和 MySQL。先把环境版本讲清楚。JDK 1.8 是这套系统的基准虽然你本机可能装了 JDK 17但我建议你还是用 JDK 8 去跑它。为什么因为 Spring Boot 2.x 在 JDK 8 和 JDK 17 下的类加载行为不一样特别是反射相关的操作在旧版本框架配新 JDK 时经常会坑你一下。MySQL 用 5.7 或 8.0 都行但要注意驱动版本——如果源码里配的是com.mysql.jdbc.Driver那你 MySQL 8.0 就必须改成com.mysql.cj.jdbc.Driver这是最常见的翻车点之一。提示检查你本机 Java 版本用命令java -version确保命令行里能正常返回 1.8 的版本号。不够 1.8 就装一个这个项目的编译选项是照着 JDK 8 写的高版本编译大概率会出source/target报错。3.2 数据库初始化脚本执行顺序决定成败数据库导入这一步最有玄学感。很多人失败不是因为 SQL 有问题而是执行顺序错了。连锁表的外键还没建立就导入子表数据会直接报错。我拿到的这套源码里SQL 文件一般都分几种his_db.sql全量脚本、his_data.sql初始化数据和his_upgrade.sql增量脚本。正确的执行顺序是先库后表再数据全量再增量。在 Navicat 里操作时你按这个顺序走就行# 第一步创建数据库建议字符集 utf8mb4排序规则 utf8mb4_general_ci CREATE DATABASE his_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 第二步执行全量结构脚本 source D:/his/his_db.sql; # 第三步执行初始化数据脚本 source D:/his/his_data.sql; # 第四步确认管理员账号在 sys_user 表里存在 SELECT id, username, password, salt FROM sys_user WHERE username admin;这里的逻辑说明utf8mb4是为了兼容病人的特殊字符和 emoji 记录你不想看到把患者名字里的特殊字存成问号就一定要用这个字符集。执行完查询后重点看password字段如果是一长串密文说明加密逻辑对了如果明文那你登录时大概率会失败需要走一遍源码里的加密方法重新生成。参数说明数据库端口默认 3306如果你本机跑过其他服务占用这个端口就在连接串里显式指向新端口。字符集这一项在连接串里也要写清楚我在 JDBC 连接里通常这样配spring.datasource.urljdbc:mysql://localhost:3306/his_db?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLfalseserverTimezoneAsia/Shanghai3.3 启动 IDEA 项目用 package 命令验证编译是否通过导入 IDEA 的步骤我就不细讲了基本就是File - Open - 选择 pom.xml走 Maven 导入。这里我更想说的是在你点绿色三角形之前先在 IDEA 的 Terminal 里跑一遍 Maven 打包提前把编译救出来mvn clean package -DskipTests跑这条命令有三个价值第一它能让你在启动前发现所有编译错误——我之前接手过一套 HIS导入后代码里各种红色波浪线就是有人改了 JDK 版本导致 Lombok 不生效直接卡在编译这一层第二它能验证 Maven 仓库里的依赖是否齐整某些环境第一次构建要下很久的包提前等它就是提前排雷第三target/目录下会生成一个可执行 jar你可以直接java -jar验证脱离 IDEA 之后能不能跑起来这对后面部署到服务器很有帮助。如果你发现打包失败先看具体报什么错。最常见的几个一是 Lombok 版本与 JDK 不匹配解决方法是把 Lombok 升级到 1.18.20 以上二是Spring Boot Maven Plugin标红这个直接看它的下载日志十有八九是网络问题导致依赖没拉全。3.4 修改配置文件数据库账号密码和端口边界源码里的application.yml是这套系统能不能连上你本地数据库的关键。默认配置通常写着root/123456你直接用不行得改成你本机的真实账号。我看不少人在这里栽跟头——他们在代码里放了个云数据库连接串结果启动一直报 connect time out 也不去改配置。修改配置时你需要关注这几个参数server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/his_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: yourpassword # 打印 SQL开发时强烈建议开启 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl参数说明server.port默认 8080但如果你本机开了 Nginx 或者别的东西占了 8080启动会直接报端口占用错误改个8081就好但要记得改完后登录地址也要带端口号。serverTimezoneAsia/Shanghai这个是时间字段和 MySQL 的时区转换不写或写错你会看到所有create_time都比实际时间差 8 个小时。这里的log-impl是 MyBatis-Plus 的 SQL 输出开关。开发阶段建议打开能直接在控制台看到每一次数据库查询的完整 SQL 和参数排查业务问题的效率高很多。但上生产环境时记得关掉否则每个请求的 SQL 都会打到日志文件里量大了磁盘很快会满。提示如果你是在 Windows 上用 Navicat 能连上数据库但 Spring Boot 启动报Access denied for user八成是账号密码不对。去 MySQL 里跑一句ALTER USER rootlocalhost IDENTIFIED BY 新密码;刷新权限就行。4. 避坑手册HIS 源码部署最常见的五个坑4.1 登录页面能开但登录失败密码加密盐值不匹配现象Tomcat 起来了登录页也出来了但无论输什么账号密码后端都返回 500 或者提示用户名密码错误。原因这套源码的密码不是明文比对登录逻辑是先查用户再用用户表里的salt字段做哈希校验。如果你在数据库里直接改了sys_user.password字段比如把密文改成明文 123456那校验自然永远失败。解决不要手动改数据库密码。用源码里自带的工具类一般在utils包里比如MD5Util或EncryptUtil生成加密后的密码再更新。命令大概是# 在测试类里调用加密工具生成新密码 java -cp his-util.jar com.his.util.MD5Util.generate(123456)然后去数据库执行UPDATE sys_user SET password 生成的密文 WHERE username admin。从那之后我接手任何一套带 salt 逻辑的系统第一件事就是找到加密工具类而不是在数据库里手动改密码。4.2 启动时表不存在数据库名字对不上现象项目启动成功但一访问菜单就报Table his.his_user doesnt exist。原因数据库脚本导入到了一个名字不同的库导致application.yml里配置的库名和实际库名不一致或者脚本里面CREATE TABLE时根本没带库名前缀。解决先确认application.yml里 datasource url 的数据库名是his_db再去 MySQL 里执行SHOW DATABASES;看实际存在的库。如果你导错到his直接USE his_db;去验证表是否都在。这种情况最稳妥的做法是把库删了重导一遍脚本严格按照第 3 章的导入顺序。不要试图手动把表挪库外键关系会搞乱。4.3 端口被占用莫名其妙的 8080 冲突现象启动日志最后一行是APPLICATION FAILED TO START往下翻能看到Port 8080 was already in use。原因本机有别的进程占用 8080比如之前跑过前后端分离项目里的 Nginx或者上一次启动没退出的 jar 进程。解决在命令行执行netstat -ano | findstr 8080找到占用端口的 PID然后去任务管理器结束进程。如果你还要并行跑别的项目就在application.yml里改端口server.port: 8081。我的习惯是一台开发机上统一规划端口段位比如系统管理类项目固定 8080-8085业务接口类固定 8200-8250这样不会自相残杀。4.4 中文乱码页面全是问号或者方框现象前端页面上中文显示成????或方框数据库里存的患者姓名也乱。原因数据库表的字符集不是 utf8mb4而是默认的 latin1。这通常是执行 SQL 脚本时终端编码没控制住或者是脚本自动创建的库继承了 MySQL 全局变量里落后的字符集设置。解决按第 3 章的方法重新建库限定字符集DEFAULT CHARACTER SET utf8mb4。连接串里也强制带上characterEncodingutf8。执行脚本前把 Navicat 的连接字符集改为utf8mb4再重新导入一次。如果你已经在跑的系统里有了脏数据那就先把源头的字符集改对脏数据看情况手动清理不建议直接 UPDATE 全表容易产生新的混乱。4.5 数据查得出来但列表空白MyBatis 驼峰映射问题现象Navicat 里明明有患者数据但页面表格是空的控制台报错Invalid bound statement (not found)或字段映射不上。原因数据库字段是下划线风格patient_name实体类是驼峰风格patientName但 MyBatis 配置里没开启下划线到驼峰的自动转换。解决在application.yml里确认加了map-underscore-to-camel-case: true。如果你用的是纯 XML 方式就在 resultMap 里明确写columnpatient_name propertypatientName。这套源码既然用了 MyBatis-Plus一般这个配置是默认开启的但如果你拿到的版本不走默认配置还是要手动补上。排查逻辑是从数据库表字段到实体类成员一个一个对一个字绝大多数空列表都是这一层映射断了。5. 二次开发的第一刀给医生工作站加一个常用诊断词库一套系统能跑起来只是开始真正有用的时刻是你改它的第一刀。这一章我给你一个完整的开发案例给医生工作站的诊断录入框加上联想词库功能。这是一个典型的 HIS 定制需求做起来也不难但能让你把整个 Spring Boot 链路重新走一遍——从数据库建表到后端接口到前端触发形成一个最小的闭环。先建表。在数据库里加一张常用诊断词表用来存放诊断描述和对应的科室编码CREATE TABLE common_diagnosis ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, dept_code VARCHAR(20) NOT NULL COMMENT 科室编码, diagnosis_keyword VARCHAR(255) NOT NULL COMMENT 诊断关键词, diagnosis_text VARCHAR(500) NOT NULL COMMENT 诊断标准描述, sort_order INT DEFAULT 0 COMMENT 排序权重, del_flag TINYINT DEFAULT 0 COMMENT 逻辑删除 0正常 1删除, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT常用诊断词库;这张表的设计逻辑dept_code用来做科室隔离——内科医生输入“咳嗽”联想的应该是呼吸系统诊断词骨科医生不该看到这些。diagnosis_keyword负责匹配用户输入的前缀diagnosis_text是最终要插入到病历里的标准描述。del_flag是 MyBatis-Plus 的逻辑删除位不直接 DELETE 数据。然后写后端查询接口。在 Controller 里加一个方法用 MyBatis-Plus 的 LambdaQueryWrapper 做模糊匹配RestController RequestMapping(/api/diagnosis) public class DiagnosisController { Autowired private CommonDiagnosisMapper commonDiagnosisMapper; GetMapping(/suggest) public ResultListCommonDiagnosis suggest( RequestParam String deptCode, RequestParam String keyword) { LambdaQueryWrapperCommonDiagnosis wrapper new LambdaQueryWrapper(); wrapper.eq(CommonDiagnosis::getDeptCode, deptCode) .like(CommonDiagnosis::getDiagnosisKeyword, keyword) .eq(CommonDiagnosis::getDelFlag, 0) .orderByAsc(CommonDiagnosis::getSortOrder) .last(LIMIT 10); ListCommonDiagnosis list commonDiagnosisMapper.selectList(wrapper); return Result.success(list); } }逻辑说明这里用了 MyBatis-Plus 的 LambdaQueryWrapper避免手写字符串列名。eq精确匹配科室like模糊匹配关键词last(LIMIT 10)限制单次返回数量避免响应体过大。如果用户输入为空字符串like会返回该科室下全部常用词正好当作医生打开录入框时的默认推荐。最后在前端调用。这套源码的前端是 Thymeleaf 模板加常规 JS你找到医生工作站的诊断录入输入框给它绑一个 input 事件$(#diagnosisInput).on(input, function () { var keyword $(this).val().trim(); if (keyword.length 0) { $(#suggestList).empty(); return; } $.get(/api/diagnosis/suggest, { deptCode: currentDeptCode, // 当前登录医生所属科室 keyword: keyword }, function (res) { if (res.code 200) { var list res.data; var html ; list.forEach(function (item) { html li style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑