简介:这是一套面向计算机专业本科生的医患档案管理系统毕设级实战源码,专为Java初学者、毕业设计与课程设计需求者打造,解决传统纸质档案管理效率低、查询难、协同弱等痛点,助力快速交付高分项目。资源包共384个文件,29.24MB,涵盖83个核心Java后端模块(SpringBoot框架)、37个Vue前端页面组件、21个JS交互逻辑、16个JPG/PNG界面截图及1个完整SQL数据库脚本,辅以bat部署脚本、yml配置、详细开发文档与MP4演示视频,结构清晰、注释充分,开箱即用。已有168人学习下载,所有模块均经严格调试,支持本地一键运行。读者可直接获取含前后端分离架构、RBAC权限控制、电子档案增删改查、医生-患者双向档案关联等完整功能的可运行系统,并配套部署指南、技术栈说明与典型问题排错提示,显著降低毕设落地门槛。
1. 医患档案系统不是“增删改查练习册”,而是SpringBoot+Vue协同治理真实业务边界的典型落地场景
很多Java初学者拿到这套“医患档案管理系统”源码时,第一反应是:又一个CRUD demo?但实际拆开update-password.vue.bak和IndexMain.vue.bak这些带.bak后缀的备份文件,会发现它们并非冗余——而是开发过程中反复迭代留下的权限校验分支、多角色路由守卫、患者敏感信息脱敏逻辑的演进痕迹。这个系统真正解决的是医疗场景下医生端与患者端数据视图隔离、档案变更审计留痕、病历附件版本控制、跨角色操作权限动态收敛四个硬性约束。它面向的不是抽象的“用户管理”,而是具体到“张医生不能查看李医生负责患者的完整检验报告,但可申请协诊并触发审批流”这类颗粒度极细的业务规则。适合正在做毕设、需要体现工程规范性的计算机专业学生,也适合想用真实项目理解Spring Security + Vue Router + Element UI三者如何在权限边界上咬合的中级开发者。系统已通过MySQL 8.0.33 + JDK 17 + Vue CLI 4.5.15环境实测,部署链路明确,但关键不在“能跑”,而在“为什么这样分层、哪些字段必须加密、谁该看到哪条日志”。
2. 后端架构设计:SpringBoot如何用三层结构承载医疗数据的合规性要求
2.1 分层逻辑与医疗业务强耦合的设计动因
本系统未采用泛化的Controller-Service-DAO模板,而是将Service层拆为BusinessService(业务编排)与DomainService(领域规则),例如PatientRecordService中updateMedicalHistory()方法不直接操作数据库,而是调用MedicalHistoryValidator.validate()校验诊断编码是否符合ICD-10标准、AttachmentHandler.checkFileSize()限制CT影像上传不超过50MB——这些规则无法由通用框架自动注入,必须显式编码。这种设计源于医疗信息系统对数据语义合法性的强制要求:普通电商系统允许“库存为负”,但病历中的“血压值”若超出[0,300]mmHg范围,系统必须拦截而非记录。
提示:查看
src/main/java/com/example/medical/service/impl/PatientRecordServiceImpl.java第142行,@Transactional(rollbackFor = BusinessException.class)声明表明所有档案变更操作具备原子性,且自定义异常BusinessException会触发回滚,避免部分更新导致病历状态不一致。
2.2 数据库脚本的关键约束实现
提供的medical_db.sql脚本包含三类强制约束:
- 外键级联:
patient_record表的doctor_id关联sys_user表,但删除医生时仅设为NULL(ON DELETE SET NULL),防止误删导致患者档案丢失; - 检查约束:
patient_info表中id_card字段使用CHECK (id_card REGEXP '^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dxX]$')验证身份证格式; - 索引优化:在
patient_record表的create_time和status字段建立联合索引,支撑“查询某医生近30天待审核病历”高频查询。
执行建库脚本前需确认MySQL配置:
-- 必须启用严格模式,否则日期类型插入'0000-00-00'会被静默截断 SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';该配置确保birth_date字段输入非法值时抛出DataIntegrityViolationException而非存入脏数据。
2.3 Spring Security权限模型的医疗化改造
系统未使用@PreAuthorize("hasRole('DOCTOR')")简单注解,而是基于PermissionEvaluator实现动态权限判断。核心逻辑在MedicalPermissionEvaluator.java中:
@Override public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) { String patientId = ((PatientRecord) targetDomainObject).getPatientId(); String currentUserId = getCurrentUserId(auth); // 医生只能访问自己建档或被授权的患者档案 return patientRecordMapper.isDoctorAssigned(patientId, currentUserId) || auth.getAuthorities().stream() .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN")); }此逻辑覆盖了“张医生A可查看患者P的档案,但李医生B无权查看,除非P主动授权B协诊”这一真实场景。application.yml中security.jwt.expiration=7200(2小时)的设置,既满足移动端频繁操作需求,又规避长期Token泄露风险。
3. 前端工程实践:Vue CLI 4.5如何通过模块化设计应对医疗界面复杂性
3.1 路由守卫与角色驱动的视图隔离
router/index.js中定义的路由并非静态路径映射,而是通过meta.roles动态加载组件:
{ path: '/record', name: 'PatientRecord', component: () => import('@/views/record/PatientRecord.vue'), meta: { roles: ['DOCTOR', 'PATIENT', 'ADMIN'], keepAlive: true, title: '病历管理' } }关键在src/router/guard.js的beforeEach守卫:
router.beforeEach((to, from, next) => { const roles = store.getters.roles; if (to.meta.roles && !to.meta.roles.some(role => roles.includes(role))) { // 患者角色访问医生专属页面时,重定向至患者首页而非403 next({ path: '/patient/home' }); } else { next(); } });这种设计避免了前端路由暴露导致的越权访问,同时保证患者误点医生菜单时获得友好引导而非报错。
3.2 敏感信息处理的双重保障机制
患者身份证号、手机号等字段在PatientInfo.vue中采用双层防护:
- 展示层:使用自定义过滤器
filterIdCard进行脱敏<span>{{ patient.idCard | filterIdCard }}</span> <!-- 过滤器定义 --> export default { filters: { filterIdCard(idCard) { if (!idCard) return ''; return idCard.replace(/(\d{4})\d{10}(\d{4})/, '$1****$2'); } } } - 传输层:
api/patient.js中getPatientDetail()请求头强制添加X-Sensitive-Access: true,后端SensitiveDataInterceptor校验该Header存在才返回完整数据,防止API被爬虫直接调用。
3.3 构建脚本的环境适配逻辑
3-build.bat并非简单执行npm run build,其核心逻辑为:
@echo off set NODE_ENV=production set VUE_APP_BASE_API=http://localhost:8080/api if "%1"=="prod" ( set VUE_APP_BASE_API=https://medical-api.example.com/api ) call npm run build通过传参3-build.bat prod切换生产环境API地址,避免硬编码导致的部署失败。生成的dist/目录下index.html中<base href="/medical/">标签确保系统可部署于Nginx子路径/medical/而非根路径,适配高校服务器多项目共存场景。
4. 部署与调试:从本地运行到生产环境的四步验证法
4.1 本地启动的依赖版本锁定策略
pom.xml中SpringBoot版本固定为2.7.18(非最新版),原因在于:
- 该版本兼容JDK 17且无已知SSL握手漏洞(CVE-2023-20862);
spring-boot-starter-web与spring-boot-starter-data-jpa组合在MySQL 8.0.33下事务传播行为稳定;- 避免使用
3.x系列导致@EnableWebMvc配置失效引发Vue静态资源404。
验证步骤:
# 1. 检查JDK版本(必须17) java -version # 输出应为 openjdk version "17.0.1" # 2. 启动后端(跳过测试加快速度) mvn spring-boot:run -DskipTests # 3. 启动前端(需先安装依赖) cd frontend && npm install && npm run serve # 4. 访问 http://localhost:8080 查看登录页若出现Error creating bean with name 'entityManagerFactory',大概率是MySQL驱动版本不匹配——检查pom.xml中mysql-connector-java是否为8.0.33,旧版驱动无法解析caching_sha2_password认证插件。
4.2 数据库初始化的幂等性保障
1-install.bat执行流程:
- 创建数据库
medical_db(字符集utf8mb4,排序规则utf8mb4_0900_as_cs); - 执行
schema.sql建表(含外键约束); - 执行
data.sql插入初始数据(管理员账号admin/123456); - 关键步骤:运行
verify-integrity.sql校验主键重复、空字符串字段等数据质量项。
其中verify-integrity.sql片段:
-- 检查患者表身份证号唯一性 SELECT id_card, COUNT(*) c FROM patient_info GROUP BY id_card HAVING c > 1; -- 检查病历创建时间合理性(不能早于2000年) SELECT * FROM patient_record WHERE create_time < '2000-01-01';该脚本输出为空则表示数据初始化成功,否则需人工介入修正。
4.3 生产环境Nginx反向代理配置要点
将dist/目录部署至Nginx后,必须配置以下规则防止Vue Router History模式404:
location /medical/ { alias /var/www/medical/; try_files $uri $uri/ /medical/index.html; } # API请求透传至后端 location /medical/api/ { proxy_pass http://backend-server:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 关键:传递原始请求头,避免JWT Token丢失 proxy_set_header Authorization $http_authorization; }特别注意proxy_set_header Authorization指令——若缺失,前端携带的Bearer Token不会传递给SpringBoot后端,导致所有接口返回401。
5. 真实业务场景下的参数调优与边界处理技巧
5.1 大附件上传的超时与分片策略
系统默认支持单个病历附件≤100MB,但实际部署需调整三处参数:
- 前端:
UploadFile.vue中headers添加'X-Upload-Timeout': '300'(单位秒); - Nginx:
client_max_body_size 100M;且proxy_read_timeout 300;; - SpringBoot:
application.yml中spring: servlet: context-path: /medical web: resources: static-locations: classpath:/static/ servlet: multipart: max-file-size: 100MB max-request-size: 100MB
若遇413 Request Entity Too Large错误,需同步修改Nginx的client_max_body_size与SpringBoot的max-request-size,二者必须严格一致。
5.2 多角色登录态冲突的解决方案
当医生与患者使用同一浏览器访问时,localStorage中token可能被覆盖。系统采用domain-scoped token方案:
// 登录成功后存储token const role = response.data.role; // 'DOCTOR' or 'PATIENT' localStorage.setItem(`token_${role}`, response.data.token); // 请求拦截器中读取对应token const token = localStorage.getItem(`token_${store.getters.role}`);此设计避免角色切换时需手动清除缓存,且store.getters.role从JWT Payload中解析,确保来源可信。
5.3 数据库连接池的医疗场景适配
application.yml中HikariCP配置针对高并发查询优化:
spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000 # 关键:启用连接测试,防止MySQL wait_timeout断连 connection-test-query: SELECT 1connection-test-query参数在每次借出连接前执行SELECT 1,确保连接有效性。若省略此配置,长时间空闲后首次查询会因MySQLwait_timeout(默认8小时)超时而失败。
| 参数 | 医疗场景意义 | 常见误配后果 |
|---|---|---|
maximum-pool-size: 20 | 支持20名医生并发操作病历 | 设为50会导致连接数耗尽,新请求排队 |
idle-timeout: 600000 | 空闲连接10分钟回收 | 设为0则永不回收,内存泄漏 |
max-lifetime: 1800000 | 连接存活30分钟强制重建 | 不设值可能导致长连接状态异常 |
当系统出现HikariPool-1 - Connection is not available错误时,优先检查maximum-pool-size是否小于应用并发量,并确认MySQL的max_connections参数(默认151)是否足够。
本文还有配套的精品资源,点击获取