资讯动态

Spring Boot电子病历系统毕设:数据库建模与权限控制实战解析

发布时间:2026/10/20 16:18:43 来源:尧图企业网站定制
每次有同学拿医院信息系统的选题来找我我先问一句你是把它当一个“管理后台”做还是当一个“医疗业务系统”做这个回答基本决定了作品最后能拿多少分。Spring Boot 电子病历管理系统毕业设计源码编号23540这类题目常年热门表面看就是一套增删改查实际上却暗含数据库建模、状态流转、权限控制、事务一致性这些硬功夫。这篇文章我把平时带项目积累的经验揉进去拆一拆这套系统怎么做才像样也把从技术选型到答辩展示的整条思路梳理给准备用它做毕业设计的同学参考。1. 先搞清楚电子病历到底管理的是什么这题就不能只写增删改查很多同学拿到题目第一反应是“患者表、医生表、病历表加几个页面”。这么想不算错但做完基本也就是个演示级作品。电子病历系统的业务核心不是“存病历”而是“记录一次医疗行为发生的完整过程”。你写的每一张表、每一个状态本质上都在回答一个问题这个病人在什么时间、被谁、按什么流程、做了哪些诊疗操作。1.1 一次就诊背后的数据闭环我把这套系统要覆盖的业务链拉直了看大概是这样的患者建档是入口紧接着是挂号或分诊然后医生接诊。接诊之后产生核心诊疗数据主诉、现病史、既往史、体格检查、初步诊断。诊断之后是处理意见可能是开药可能开检查单、检验单也可能直接建议住院。再往后药房执行发药护士录入体征、执行医嘱费用模块记录每一笔收费。最后是复诊、病程记录、出院归档。这一串流程里病历不是孤立的一张大表而是围绕“一次就诊记录”展开的一组数据。患者可能会来很多次所以患者和就诊是父子关系一次就诊可能产生多份病历文书所以就诊和病历又是一对多。医嘱挂在就诊下面检查、检验报告也挂在就诊下面费用又和医嘱关联。这个关系理顺了数据库设计才不会变成所有表都去关联患者表的大平铺。1.2 从角色反推功能四类人眼里是完全不同的四个系统做系统之前先列角色这是老生常谈但医疗系统的角色差异比大多数管理系统都大。我至少会划分出四类角色管理员只管用户、角色、菜单、数据字典、系统参数基本不参与诊疗流程。医生核心使用者需要患者列表、接诊工作台、病历编辑器、诊断录入、医嘱开立、检查检验单申请。护士需要体征记录、医嘱执行、护理记录、输液/注射执行单关注的是“该做什么、做没做”。药房需要待审核处方、发药退药、药品库存预警、有效期管理。同一个系统四类角色打开首页后看到的菜单完全不同这叫功能级权限同一个患者列表医生只能看自己接诊过的患者这叫数据级权限。很多毕设只做了前者没做后者。而“医生只能看自己负责科室的数据”恰恰是医疗系统里最现实、也最容易被评委追问的点。1.3 状态流转比几十个接口更能体现设计能力一个用心做的电子病历系统肯定有明确的状态机。就诊状态要经历待接诊、接诊中、检查中、治疗中、待出院、已出院、已归档。病历状态要经历草稿、待提交、已提交、已审核、已归档。医嘱状态要经历已开立、已审核、已执行、已停止。这些状态不是想改就改的得有流向约束。比如草稿才能编辑已归档的不能再动已发药的医嘱不能直接把库存加回来。实现上我建议用一个统一的业务状态流转方法集中处理每一个合法迁移而不是在十几个接口里各写各的 if else。状态迁好了后面统计每个阶段耗时、查流程卡在哪都是顺手的事。这一章看明白了你就会发现这套系统不只是“电子病历”它是“诊疗流程的数字化影子”。带着这个认知去做表格设计和接口设计项目的高度完全不一样。2. 技术选型Spring Boot 生态里最稳妥的毕设组合技术选型的核心逻辑是在有限时间内最大化体现个人能力同时保证项目能稳定跑起来、答辩能讲清楚。我见过太多同学在选型上追求“新”最后被框架本身的问题拖死。下面这套组合我实测过很多次是性价比最高的方案。2.1 后端版本与持久层框架为什么我总推 2.7.x MyBatis-PlusSpring Boot 版本建议选 2.7.x比如 2.7.18而不是 3.x。原因很现实3.x 强制 JDK17且部分老依赖不兼容有的同学本机还是 JDK8 或者学校机房环境较老光是环境就够折腾两天。2.7.x 配 JDK8 或 JDK11 都非常稳网上可参考的资料最多遇到问题一搜就有答案。持久层我推荐 MyBatis-Plus 3.5.x理由有三条单表 CRUD 几乎不用写 SQL节省大量时间分页插件 PageHelper 一条语句就能分页写列表页效率极高内置代码生成器可以从表结构直接生成实体、Mapper、Service、Controller 四层代码。但这不代表你可以不懂 SQL。答辩时评委很喜欢问“你这条分页怎么实现的”“连表查询写在哪”你至少能解释 MyBatis-Plus 的分页底层是拦截器改写 SQL 生成 LIMIT关联查询还是要手写 XML 里的 ResultMap。为什么不用原生 MyBatis不是不能用而是纯手写 CRUD 太耗时毕设时间宝贵把时间花在业务设计上更值。为什么不用 JPA/HibernateHibernate 自动建表、自动管理状态确实省事但对字段和 SQL 的掌控感弱一旦出现“为什么多查了一条”“为什么更新了整行”这类问题新手很难排查。MyBatis-Plus 是半自动SQL 和映射尽在掌握更适合讲解。2.2 认证与权限Sa-Token 还是 Spring Security我站前者说到登录和权限很多人下意识想到 Spring Security。它确实是行业标准但学习曲线放在那里Security 的过滤器链和认证流程对于新手来说过于抽象。而 Sa-Token 最直观的优势就是 API 简单登录后一句StpUtil.login(userId)校验登录一句StpUtil.checkLogin()做角色校验一句SaCheckRole(doctor)。底层帮你封装好了 Token 的生成、存储、过期和拦截业务代码里几乎不需要关心过滤器链。我给的组合是Sa-Token 负责认证授权 自定义注解和数据权限校验实现 RBAC 模型。如果你非要用 Spring Security也不是不行但请留出至少一周的时间熟悉它而且答辩准备时间要加倍。相比之下把精力花在业务功能上收益明显更高。2.3 前端呈现方式Vue3 前后端分离还是 Thymeleaf 服务端渲染这是另一个关键决策。如果时间充裕两个月以上我强烈推荐 Vue3 Vite Element Plus Axios 做前后端分离。理由是页面组件化以后写病历编辑、医嘱选择这类复杂交互方便得多接口调用和 JSON 数据结构也能体现现代开发模式答辩展示时前端项目和后端项目各跑一个进程观感上更专业。如果时间真的紧或者你 JS 基础比较弱那 Thymeleaf Bootstrap 服务端渲染也可以。Thymeleaf 的一个明显好处是数据直接在后端 Model 里不需要处理跨域、Token 缓存等前端联动问题一个 Spring Boot 工程跑起来就完事。它的问题是复杂交互写起来痛苦但毕设的功能复杂度和真实产品比有限用模板渲染完全能应付。我的建议是除非你对自己写前端很有信心否则第一版先用 Thymeleaf 把业务跑通剩下的时间再考虑要不要迁移到 Vue 重构首页。不要上来就 Vue一大把时间砸在环境、构建、路由上回头业务没做透那才是真正的翻车。2.4 中间件加还是不加要看你能不能讲清楚不少同学一看别人项目用了 Redis、用了 RabbitMQ自己也想加。我的态度是加了中间件你就要为它负责。答辩时评委的一句“为什么这段逻辑要引入 Redis”就够你解释半天。这套系统里Redis 可以用在三个非常合理的场景存储登录 Token 的会话状态Sa-Token 本身就支持 Redis 集成、缓存数据字典和科室列表等低频变动数据、存图形验证码。这三个场景既真实又容易讲清楚能明显提升响应速度。至于 RabbitMQ建议先不加。电子病历系统在单体毕业设计阶段没有跨系统异步通信的刚需硬上消息队列只会暴露你对分布式架构理解的薄弱。MinIO 或其他对象存储可以看情况如果要做病历附件上传用它比把文件塞进数据库强得多。3. 数据库设计医疗表结构里的关键约束与常见坑数据库设计是这类系统真正的分水岭。逻辑建得好后端代码写起来行云流水建得乱后面每个接口都在为表结构补洞。我直接把核心表结构和容易踩的坑摊开讲。3.1 核心表结构与数据关系从 ER 图到物理表先画大关系用户表和角色菜单表负责权限患者表独立存在身份证号做唯一约束就诊表是业务中转站几乎一切都围着它转病历表挂就诊医嘱表挂就诊药品表、检查表、检验表作为基础资料收费表关联医嘱或检查单操作日志表记录每一个关键动作。就诊表是这个系统的“总线”。它至少要有这些字段患者ID、接诊医生ID、科室ID、就诊类型门诊/急诊/住院、就诊状态、主诉、初步诊断、收费状态、创建时间。这样一张表建好后面统计科室接诊量、医生工作量、患者就诊次数都直接从它出发。再看病历表它不能简单叫“medical_record”然后一个 content 字段打完收工。我建议表结构至少包含就诊ID、病历类型初诊/复诊/病程记录/出院小结、标题、病历正文富文本、诊断结果JSON、状态、创建人、创建时间、提交时间、审核人、审核时间。其中“病历类型”特别重要同一份就诊下可能有“首诊记录”和“病程记录”两种文书用 type 字段区分比拆成两张表灵活得多。这里的唯一索引可以这样设计同一个就诊下相同类型的病历如果已经到了归档状态就不允许再新建一份草稿防止医生重复录入。当然不同类型的病历可以并存。3.2 病历正文富文本与结构化数据并存病历正文是这个系统最核心的内容载体。很多同学的方案是存一个 HTML 富文本字符串其实可以但不够。纯 HTML 能解决“像病历”的问题却解决不了“按诊断类型统计”“按症状筛选”这些结构化查询需求。我给你一个折中方案主表里用 LONGTEXT 存富文本正文保证展示效果和打印效果另设一个结构化子表或 JSON 字段存主诉、现病史、既往史、体格检查、诊断ICD码这类键值对。这样展示和统计两边都占住。如果不想建子表MySQL 5.7 以上支持 JSON 字段诊断信息直接塞JSON列也够用。这里我记得一个细节JSON 字段虽然查询时可以用 JSON_EXTRACT 取值但写 SQL 会复杂一点不建议在 JSON 上建索引做核心查询。你还是拿它做低频统计和校验展示高频查询放独立列里。还有一个小坑富文本编辑器很容易引入不安全的 HTML比如script。如果这个病历内容会被别的浏览器打开XSS 漏洞就来了。做法是后端接收富文本后做白名单过滤只保留 p、br、strong、em、span 这类常用标签Strip 掉 script、iframe、link 等危险节点。前端不能完全信任一定要在后端再过滤一遍。有些做毕设的同学不知道这个答辩时被问到安全问题容易卡壳提前注意很加分。3.3 时间字段、状态字段和逻辑删除防御性设计三件套医疗系统对时间极其敏感。谁来建的就诊记录、什么时候提交的病历、什么时候审核的全部要能追溯。MyBatis-Plus 的MetaObjectHandler可以统一处理createTime和updateTime的自动填充避免每个 Service 里手动 set既省事又不会漏。状态字段我强烈建议用tinyint加代码里的枚举类不要直接存字符串。字符串“已提交”“审核中”看着直观但一旦有人填了“已提价”数据就废了。用数字枚举通过注释和枚举类明确含义既节省空间又方便做状态流转控制。PostgreSQL 同学可能喜欢用VARCHAR CHECK约束MySQL 里用 tinyint 就够了。逻辑删除是医疗数据的硬性要求因为真实业务里病历是不能物理删除的只能作废并留痕。MyBatis-Plus 提供了TableLogic注解删除时自动转 UPDATE查询时自动加 WHERE deleted0。这个特性一定要用答辩时可以说这是为了满足医疗数据留痕要求。注意逻辑删除字段别加到唯一索引里去不然逻辑删除后无法重建同身份证号的患者——这个问题我见过不止一次。3.4 医嘱、药品和收费的挂接中间表别建薄了医嘱表和药品之间是多对多关系。一张医嘱可能开了三种药一种药也可能在多次医嘱里出现所以要建doctor_order_item中间表。这个表要承载的不仅仅是“哪个药品挂在哪个医嘱下”还包括单次剂量、频次、数量、给药途径、用法说明、状态、已发药数量。很多同学把中间表建成了只有“医嘱ID药品ID”完全无法支撑发药、退药、费用统计。这个细节直接决定了药房模块能不能做出来。收费表建议挂接到医嘱明细而不是只挂到医嘱头。因为费用往往按药品项计算一次订单费用等于所有明细费用之和。这样退一盒药时费用只调整那一项。否则只记总费用退药就永远算不清楚账。建模阶段多想一步后面写退药接口能省两小时。4. 核心功能实现我从 0 到 1 绕过的几个坎技术选型和表结构定好系统骨架就成型了。真正把系统填起来的时候有几个功能点容易写崩我逐个讲一下我的实现方案和踩坑记录。4.1 病历模板与动态表单别再为每个科室硬编码一个页面电子病历最烦人的地方在于内科病历和外科病历的字段不一样门诊病历和住院病程记录也不一样。如果每张表单都写一个 Vue 组件或 Thymeleaf 模板去匹配工作量巨大而且后续加模板就得改代码极难维护。我用的是 JSON 模板思路类似动态表单设计。在数据库里建一张record_template表一个模板是一段 JSON 配置。比如{ title: 门诊初诊病历, sections: [ { key: chiefComplaint, label: 主诉, type: textarea, required: true, maxLength: 500 }, { key: presentIllness, label: 现病史, type: textarea, required: true, maxLength: 2000 }, { key: physicalExam, label: 体格检查, type: textarea, required: false, maxLength: 1000 }, { key: diagnosis, label: 初步诊断, type: select, required: true, optionsSource: icdDict } ] }前端拿到这个 JSON 后动态渲染表单用户填完提交的也是 JSON。后端用统一的校验器根据 required 和 maxLength 规则完成参数校验然后把数据同时写入结构化字段和富文本正文。以后要增加“出院小结模板”只需要在后台配置新 JSON不用动代码。这个设计在答辩时非常抢眼因为它体现了抽象能力属于典型的“低成本高表现”功能。4.2 医嘱开立与药品库存扣减事务边界和并发扣减怎么处理开医嘱不是简单地往 order_item 里 insert 一行还要同步扣减药品表里的库存。这两个动作必须在一个事务里要么都成功要么都失败。Spring 的Transactional可以包住这个方法但要记住事务只对RuntimeException回滚自定义业务异常最好继承RuntimeException或者显式配置rollbackFor。光有事务还不行并发扣减是经典考点。我用的是乐观锁写法不搞悲观锁避免锁表拖慢正常业务。扣减 SQL 类似这样UPDATE drug_stock SET stock stock - #{quantity}, version version 1 WHERE drug_id #{drugId} AND stock #{quantity}这条 SQL 的含义是库存足够才更新库存行数影响为 0 说明当前并发条件下数量不足抛出异常让事务回滚前端提示“库存不足”。它不需要显式SELECT ... FOR UPDATE性能更好代码也短。答辩时你可以说这模仿了秒杀系统的库存防超卖方案虽然医疗场景并发量没那么大但这个防御性设计很专业。还有一个很容易漏掉的退药逻辑。病人没来取药或者医生停医嘱时要把库存还回去。还多少要注意区分“已开立未发药”“已发药未执行”“已执行”几种状态。我建议order_item里维护prescribedQuantity开立数量和dispensedQuantity已发药数量。退药时只能退dispensedQuantity剩余部分且要同步更新费用表和库存表。这些都是真实业务里的细节做进去之后系统一下就有了“产品感”。4.3 会话、鉴权与操作审计医疗系统的底线逻辑登录会话方案我用 Sa-Token 后拦截器配置非常简单。后端写一个配置类注册 SaInterceptor对/api/**路径开启鉴权再按方法注解控制角色。比如医生接口上加SaCheckRole(doctor)管理员接口上加SaCheckRole(admin)未登录的请求在拦截器层面直接被挡掉。操作审计是医疗系统绕不开的。我用 AOP 做了一个OperationLog注解标在关键 Service 方法上通过环绕通知把操作人、操作时间、操作类型、方法耗时、操作结果统一写入日志表。比如“医生提交病历”“药房发药”“管理员重置密码”这几个操作全部埋点。实现很轻量但效果很重——答辩时评委若问“这套系统的安全性体现在哪里”你可以直接展示这张审计表再强调业务规范要求可追溯安全性的回答就落地了。数据脱敏也得做。患者手机号、身份证号、住址属于敏感信息列表接口不应该返回明文。我习惯在 VO 层统一处理手机号保留前3后4中间四位置星身份证号保留前1后1地址精确到小区或楼栋级别就停。不要等到前端再遮后端口径统一才是真正安全的。4.4 文件上传与附件管理格式、路径、下载三个细节病历系统通常还要支持上传检验报告图片、检查影像文件、出院小结 PDF。Spring Boot 里实现很简单但有三处必须处理好第一文件类型白名单。不要用前端传的扩展名校验别人改一下上传请求就能绕过。后端应该读取文件的 MIME Type 或判断文件头魔数只允许 JPG、PNG、PDF 这几个常见类型大小限制建议单文件 10MB 以内。第二磁盘路径不可预测。保存文件时不要拼用户输入统一用 UUID 重命名后放到按日期分层的目录里比如/data/upload/2025/06/01/uuid.pdf。文件名存数据库时也存这个相对路径绝对地址每次请求按配置拼接。千万别把上传文件名当作实际存储名更不要直接拿文件名做下载路径否则路径穿越漏洞很容易爆。第三下载接口要做鉴权。不要直接走静态资源映射暴露整个上传目录而是要写一个 Controller 接口先校验登录状态和权限再从数据库取出文件相对路径用ResourceHttpMessageConverter把文件流返回给前端。这样所有文件访问都在权限保护之下。5. 从“能运行”到“能答辩”演示路径与高频追问应对方案很多同学系统做完了到答辩现场不知道先点哪个按钮。为了演示效果更好我建议设计一条3分钟的业务闭环链路按这条线走完评委基本就能理解系统的全貌和亮点。5.1 一条 3 分钟的最佳演示链路我的推荐顺序是先用管理员账号登录系统演示图形验证码和登录成功后的菜单变化顺带展示首页统计卡片切到医生账号打开“我的患者”新建一位患者完成建档给这位患者新建一次就诊选择门诊类型在接诊工作台里选择“门诊初诊病历”模板演示模板自动带入表单的过程填写主诉和初步诊断提交病历然后开一组医嘱选择两种药品提交后观察药品库存同步扣减切到药房账号看到待审核处方执行发药再切回医生视角确认医嘱状态变为已发药最后切到管理员后台查看操作审计日志里刚才那几步的操作记录。这条链路的妙处在于它把四类角色、两大模块病历医嘱、一条事务、一个安全机制全部串进了一次演示。不用刻意讲功能列表业务自然就讲完了。5.2 评委最爱问的问题及回答思路答辩里常见问题其实相当一致我梳理了一份高频问题清单问题建议回答思路为什么用乐观锁而不是悲观锁避免长事务锁表库存充足场景下乐观锁失败概率低遇到失败就回滚重试符合医疗场景并发量不高的实际病历正文怎么防止 HTML 注入后端白名单过滤危险标签只保留安全富文本标签在存储和展示两侧都做清洗如果两个医生同时编辑同一份病历怎么办方案一是乐观锁版本号更新时校验 version冲突提示重新加载方案二是操作前锁定病历编辑期间其他人只读不可写数据库里的病历能不能删除医疗数据必须留痕物理删除一律禁止逻辑删除必须由管理员操作并记录审计日志数据权限怎么控制的医生查询患者列表时SQL 自动追加“接诊医生当前用户”或“科室当前用户科室”的条件通过 MyBatis 拦截器统一注入避免在业务代码里重复写为什么用 Sa-Token 而不是 Shiro四年前 Shiro 用得比较多但 Sa-Token 对 Token 无状态鉴权、会话管理、踢人下线的集成更简洁毕设场景下更直观易懂建议把每个问题都准备一个1分钟左右的答案讲清“背景-方案-效果”就行不要绕。5.3 答辩加分项工程化细节比功能多更值钱几个很便宜的加分项强烈建议做进去统一返回格式。所有接口返回{ code, message, data }结构失败返回错误码。这个改动本身不大但在答辩时展示接口文档层次感立刻不一样。全局异常处理器捕获业务异常和系统异常统一转成标准返回体页面不会弹裸的500错误。用 Knife4j 生成在线 API 文档启动后打开/doc.html就能看到每个接口的说明和参数这是最直观的工程化证据。多环境配置文件拆成 dev 和 prod 两套演示时用 dev说明你懂环境隔离。项目启动初始化脚本里创建好管理员账号和基础数据让评委自己点两下就能上手观感会好很多。6. 源码 23540 的 2.0 方向这套系统还能往哪里长毕设做完不代表这套系统的生命力就结束了。如果时间有富余或者后续想把它写成更完整的作品下面几个方向是最自然的延伸路径。6.1 向医疗标准靠拢结构化文档与归档导出目前病历内容虽然是 JSON 存储但严格来说还不算标准化。进阶方向是引入临床文档架构CDA的简化版定义。简单理解就是把病历的文档头、文档体、章节、条目拆成标准结构让不同系统之间能够交换病历数据。实现不复杂写一个导出服务把数据库里的病历 JSON 渲染成标准 XML 或 PDF 文件文件名按“患者ID-就诊日期-病历类型”规则生成落在归档目录。这样打印、病案室归档、第三方调阅都有据可查。虽然毕业设计不一定需要走到这一步但答辩时展示“病历数据可以按规范归档导出”明显更有临床场景的味道。6.2 患者端延伸院外报告查询与消息通知给系统增加一个患者端的简化版门户比如 H5 页面或小程序提供的功能不需要多登录、查看自己的就诊记录、查看检查报告 PDF、在线预约复诊。接口层已有完整的鉴权和数据模型扩展患者端几乎是顺理成章主要新增一套查询接口和页面。加上一条简单的消息通知机制——比如检查报告出结果后给患者推送一条待查看提醒就能让系统从“医生端的工具”变成一个“闭合的服务链路”。这里要提醒一句患者端和医生端的数据权限要重新过一遍确保患者只能查自己名下的数据防越权测试那种安全意识对医疗场景尤其重要。6.3 给正在肝毕设的同学三条能省两周时间的实操习惯最后分享几条开发节奏上的经验。第一拿到这套源码后绝对不能直接拿去交差。我的建议是把核心模块重写一遍数据库表自己建登录权限自己配病历模块自己写。重写不仅让你熟悉每一行代码更重要的是答辩时心里有底。直接背别人的项目评委随便追问一个关联查询就会措手不及。第二每天推进后立即提交 Git 记录至少每天一次commit message 写清楚今天干了什么。这个习惯除了防误删外还能在答辩时展示你的开发周期和分工属于低投入高回报。第三任何时间点都要保证项目能一键启动运行。毕设导师可能随时要看系统演示如果演示时环境配置依赖过多、启动失败印象分会掉得很快。尽量精简启动步骤把初始化 SQL 和默认配置做到位启动文档单独写清楚。我带的很多同学都是答辩前两周才意识到“能跑”本身其实就是一个巨大的加分项。电子病历这类题目之所以被反复选作毕设就是因为它在复杂度、可实现性和展示效果上平衡得很好。按上面的思路把业务模型做透把事务、权限、审计几个关键点讲明白这套系统不仅是代码量的堆砌更是一份拿得出手的作品。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑