毕业设计选医疗报销系统这个方向的人不少,但真正能把源码、数据库、论文、部署文档一整套整理干净的,其实不多。我之前帮人带过几个类似项目,也见过不少同学最后卡在“代码能跑但讲不清”或者“功能做完了但论文不知道写什么”的状态。这套SpringBoot+Vue+MySQL的医疗报销系统,算是一个比较标准的前后端分离毕设题,覆盖了用户登录、报销申请、审核流转、统计报表这块完整业务闭环,用来做毕业设计也好,用来学全栈开发也好,都很合适。
市面上很多题目都偏“大而全”,功能表列了一堆,实际做完连审核状态机都说不明白。这个项目的思路比较务实,核心就做一件事:让用户把看病产生的费用在线提交申请,由后台管理员审核后进入报销流程,同时把审批轨迹、报销记录、统计报表沉淀下来。这个业务逻辑听起来简单,但真正落地时涉及的权限控制、状态流转、金额计算、数据回显,都是毕业答辩的高频考点。
下文我会从技术选型的原因、数据库设计、核心功能实现、部署交付到论文撰写和答辩应对,完整拆一遍这个项目。不是给你贴一堆代码就完事,而是把每个关键决策背后的“为什么”讲清楚,让你拿到手里能改、能讲、能过。
1. 项目定位与功能拆解:这套医疗报销系统到底做了什么
1.1 为什么选这个题目
医疗报销系统是典型的“业务闭环型”毕设题目,它不像纯电商或纯管理系统那样容易做成“一堆增删改查的无脑堆叠”,它有一个核心业务链:用户申请报销,后台审核,状态回写,费用统计。这一条链走完,就自然覆盖了项目开发中最重要的知识点:多角色权限、业务状态机、事务处理、数据查询统计。
同时这个领域本身离生活很近,评审老师不需要额外理解复杂的行业背景。你讲“用户看病花了三千,上传单据,管理员审核后按比例报销”,任何人三秒钟就能明白系统在做什么。毕设答辩最怕的就是评委听不懂题目,医疗报销完全没有这个障碍。
另外这个方向不是一个“一次性项目”。医保政策、报销规则、审核流程在不同单位都有差别,后续扩展空间很大。这就要求你做的不是死功能,而是“流程可配置、状态可流转、数据可统计”的一套框架。毕设里能体现这种设计意识,分数一般不会低。
1.2 角色设计与权限边界
项目采用三种角色,这样设计不是因为多一个角色显得内容多,而是因为报销业务的天然需求就是这么分的:
- 普通用户(患者/参保人):填写报销申请单、上传材料、查看自己的报销进度和历史记录、修改个人资料。他们只能操作自己的数据,不能看别人的报销单。
- 审核管理员:查看所有待审核的报销单,审核通过或驳回,填写审核意见。可以查看统计报表但不能修改用户信息。
- 系统管理员:用户管理(包括为审核员开户禁用)、公告发布、报销分类配置、系统数据总览。
这种三个角色一拆,权限控制的代码就有的写了:后端接口要按角色鉴权,前端菜单要按角色动态渲染,操作数据要按归属人过滤。这三点做好了,整个系统的安全性和业务合理性就有了,论文里写“系统设计”也更有底气。
1.3 功能模块边界
功能划分上我建议不要贪多,把以下七个模块做好就够了:
- 登录与注册模块:JWT鉴权、密码加密存储、验证码(可选)
- 个人中心:基本信息修改、密码修改
- 报销申请模块:选择报销类型(门诊/住院/药品等)、填写就诊信息、上传票据图片、提交申请
- 报销审核模块:待审列表、审核操作(通过/驳回)、填写原因说明
- 记录查询模块:按时间/状态/类型筛选自己的报销记录,查看详情
- 统计报表模块:按月度/类型统计报销金额,前端用图表展示
- 系统管理模块:用户管理、公告管理、报销类型配置
申请-审批-统计-管理,这四个板块串起来就是一条完整的业务链路,功能不多但每一环都必须走得通。比那种列了十几个模块、每个都是摆设的项目实在得多。
2. 技术选型与项目架构:为什么是SpringBoot+Vue+MySQL
2.1 后端的选型逻辑
后端用SpringBoot,不需要多解释。它是现在Java生态里最适合做中小型管理系统的框架,内置Tomcat,starter机制让依赖引入变得非常轻量,而且网上资料极多,出任何问题都能搜到解决方案。毕设场景下不用追求微服务、分布式这些“看起来高级”的东西,把单体应用做扎实,数据层、业务层、控制层分层清晰,反而是更被认可的做法。
具体版本我建议SpringBoot 2.7.x。不用最新的3.x,是因为很多网上的教程、依赖版本、插件适配都还是针对2.x写的,踩坑成本低。Java环境用JDK 8即可,稳定且兼容性最好。
持久层我推荐用MyBatis Plus(MP),不要用原生MyBatis。原因很简单:MP内置了通用的增删改查方法,你不需要为每个表写一堆重复的Mapper XML,省下的时间可以用来打磨业务逻辑。它提供的分页插件、条件构造器、逻辑删除这些功能,在毕设项目里非常实用,代码量能少百分之三四十。毕业设计的核心是展示完整业务能力,不是为了表演手工SQL技巧。
2.2 前端的设计思路
前端选Vue 2 + Element UI,主要是生态成熟稳定。Vue 2的教程数量、问题解答量远多于Vue 3,对毕设来说“查到答案”比“用最新版本”重要得多。Element UI的表格、表单、弹窗、日期选择器这些组件本身就是为管理后台设计的,页面做出来整齐大方,视觉上就很加分。
前端工程我用Vue CLI脚手架初始化项目,目录结构按views(页面)、router(路由)、api(接口请求)、components(公共组件)、utils(工具函数)拆开。页面包括登录页、布局主框架、报销申请页、审核列表页、报销记录页、统计图表页、用户管理页、公告页。
Vuex用来管理登录状态和用户信息,Axios做统一请求封装,在请求拦截器中动态附加JWT令牌,在响应拦截器中统一处理业务码和错误提示。路由守卫中检查权限,未登录跳转登录页,非管理员访问管理页则拦截提示。这部分的完整实现,是论文中“系统实现”章节的核心素材。
2.3 前后端交互与统一返回格式
前后端分离项目最重要的一件事就是约定接口规范。我用了一套统一响应体,所有接口都返回以下结构:
{ "code": 200, "message": "操作成功", "data": {} }code为200表示成功,401表示未登录或令牌过期,403表示无权访问,500表示业务错误或异常。前端Axios拦截器判断code字段,200则进入业务处理,非200则统一弹出错误信息。这样做的最大好处是前端不需要每个接口都写一遍错误处理逻辑,代码干净很多。
数据库连接池我用Druid,除了连接管理之外,它还提供监控页面(Druid Monitor),答辩时可以直接打开监控页展示SQL执行情况、活跃连接数、慢查询记录,这属于“别人没有你有”的加分点。
3. 数据库建模:核心表结构与字段设计的思路
数据库是整套系统的基础,表设计得好不好直接决定代码写起来顺不顺。建议核心表控制在7到8张以内,字段宁精勿杂,每张表都加创建时间和更新时间两个通用字段,用MyBatis Plus的自动填充功能维护。
3.1 用户表(sys_user)
CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录账号', password VARCHAR(100) NOT NULL COMMENT 'BCrypt加密后的密码', real_name VARCHAR(50) COMMENT '真实姓名', id_card VARCHAR(18) COMMENT '身份证号', phone VARCHAR(20) COMMENT '手机号', role TINYINT NOT NULL DEFAULT 1 COMMENT '角色:0管理员 1用户 2审核员', status TINYINT DEFAULT 1 COMMENT '状态:1启用 0禁用', create_time DATETIME, update_time DATETIME );密码必须用BCrypt加密,不能明文存储。Spring Security自带BCryptPasswordEncoder,直接拿来用就行。答辩时很可能被问到“系统如何保障数据安全性”,这是一个标准答案点。身份证号唯一索引可以防止同一人多账号注册,实践中可根据需要保留。
3.2 报销申请主表(reimbursement)
这是整个系统最核心的表,字段设计直接体现业务理解深度:
CREATE TABLE reimbursement ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '报销单号', user_id BIGINT NOT NULL COMMENT '申请人ID', category_id BIGINT COMMENT '报销类型ID', hospital_name VARCHAR(100) COMMENT '就诊医院', diagnosis VARCHAR(200) COMMENT '诊断说明', total_amount DECIMAL(10,2) COMMENT '总费用', insured_amount DECIMAL(10,2) COMMENT '报销金额', status TINYINT DEFAULT 0 COMMENT '状态:0待审核 1审核通过 2已驳回', apply_time DATETIME COMMENT '申请时间', review_time DATETIME COMMENT '审核时间', reviewer_id BIGINT COMMENT '审核人ID', review_remark VARCHAR(500) COMMENT '审核意见', receipt_attachment VARCHAR(255) COMMENT '票据附件路径', create_time DATETIME, update_time DATETIME );报销单号(order_no)用时间戳+随机数生成,格式类似“BX20250510xxxx”,保证业务数据可追溯,这也是答辩时可以讲的点。金额字段一律用DECIMAL(10,2),绝不能用Double或Float,否则算报销金额会有精度问题,这属于审核组成员都懂的常识。诊断说明存的是文本或JSON字符串,取决于是否需要结构化,毕设直接用文本最省事。票据附件路径存的是上传后的文件访问路径,文件本体存在服务器本地目录,这里只存相对路径,避免数据库体积膨胀。
3.3 辅助表
报销类型表(reimbursement_category)用于配置门诊、住院、药品等类别,系统管理员可以动态维护。公告表(sys_notice)保存标题、内容、发布时间。操作日志表(operation_log)记录关键操作:谁在什么时候查了什么、审了什么。日志表看起来是“额外工作”,但它对论文测试章节和答辩都有用,能展示你考虑了操作留痕的安全意识。
3.4 表关系的组织
用户表与报销表是一对多关系,通过user_id关联。报销表与类型表是多对一关系。日志表和用户表是弱关联,仅记录用户名和操作内容,不建外键也可以。毕设项目我建议不要建物理外键,而是通过代码逻辑维护数据一致性。理由有两个:一是MyBatis Plus配合逻辑外键更好写,二是论文中可以写“基于应用层维护数据一致性,提升数据库写入性能”,这是个说得通的取舍。
4. 核心功能模块实现:从登录到报销审核的全链路
4.1 登录鉴权与JWT方案
登录接口接收用户名和密码,先查用户是否存在,再用BCrypt验证密码,验证通过后生成JWT令牌返回前端。令牌里包含userId、username和role,设置两小时过期时间:
String token = Jwts.builder() .setSubject(user.getUsername()) .claim("role", user.getRole()) .claim("userId", user.getId()) .setExpiration(new Date(System.currentTimeMillis() + 7200000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();后端写一个拦截器(HandlerInterceptor)统一校验请求头里的Token,如果验证失败直接返回401。不同的路径按需配置放行规则,登录和注册接口放行,其余接口必须携带Token。这里要注意,用户状态被禁用后,即使Token没过期也应该拒绝访问,所以拦截器里不仅要验签,还要查一次数据库确认status等于1。
前端配合Vue Router的beforeEach守卫做跳转控制:没有Token跳登录页,有Token但角色不匹配跳403页面。这一套下来,登录鉴权环节就形成了闭环,答辩时可以从“为什么用JWT而不是Session”这个问题展开:JWT无状态、适合前后端分离、支持跨域。对比Session的“服务端存储、需要Cookie配合”来说明,基本上就能把一个常见答辩问题答得很完整。
4.2 报销申请流程与附件上传
报销申请页是用户使用频率最高的页面。表单字段包括报销类型、医院名称、诊断说明、总费用金额、票据附件。提交后,后端做两次校验:第一次是必填字段校验,第二次是金额合理性校验(总额必须大于0;如果用户填写的报销金额大于总费用,直接拒绝,因为逻辑上说不通)。这两层校验要在前端做一次(体验友好),后端也要做一次(数据安全),不能只信任前端拦截。
附件上传我采用本地磁盘存储方案:配置一个上传目录(比如项目根目录下的upload/),按日期分子目录,用UUID重命名文件,避免文件名冲突。文件大小限制为5MB以内,只允许jpg、png、pdf格式。后端上传接口返回文件访问的相对路径,前端把路径放进隐藏字段,随报销单一起提交。
这里要补一个很多人会忽略的点:如果用户提交了附件但是重复提交了报销单,上一张单的附件就成了垃圾文件。建议加一个简单的定时任务或逻辑判断,定期清理“超过24小时仍未关联业务记录的孤儿文件”,这个细节写在论文创新点里也挺好看。
4.3 审核模块与状态机
审核是整个系统的核心业务逻辑。所有申请表会首先进入“待审核”列表,审核员点击通过或驳回,系统状态流转只有三条主线:待审核到通过、待审核到驳回、驳回后用户重新提交回到待审核。
每条流转线在同一时刻只能有一个方向,不可能出现“又通过又驳回”的情况。后端实现时我用了状态字段的比较判断:执行更新SQL时,UPDATE语句里带着status=0的条件,利用数据库行锁保证并发下不会被重复审核,同时修改行数为0时返回“该单据已被处理”的错误提示。这就是典型的乐观锁思路,说给评审老师听,他能判断出你知道并发操作风险。
驳回流程设计上不是简单把状态改掉就完事,审核意见(review_remark)是必填的。用户在“我的报销记录”里看到被驳回后,能查看原因,修改信息后重新提交。这里重新提交不要新生成一条记录,而是复用原记录把状态改回待审核,同时清空上一次的审核信息。这样做的好处是用户的报销历史是连续的,统计报表不会因为它被驳回过就多出一堆无效单。
4.4 报销金额计算规则
医疗报销不可能100%报销,否则系统没有任何业务难度。我设计的规则是:报销金额 = 总费用 × 报销比例,报销比例由报销类型决定,比如门诊30%、住院70%、药品50%。类型表的字段结构就包含一个比例字段,管理员改比例,所有后续单据自动按新比例计算。
这个设计特意避开了“硬编码比例”的偷懒做法,让报销规则变成可配置项,从架构上就比写死常量显得成熟。计算放在后端接口里,提交报销单时后端拿到总金额和类型ID,查询类型比例算出报销金额,再落库存储。前端显示给用户看的是计算后的预估结果,实际金额以服务端为准,避免用户篡改请求参数。
4.5 统计报表与图表展示
统计报表使用ECharts绘制,这是管理后台的“面子工程”,视觉冲击力强,答辩效果好。我做了三个图表:每月报销总额的折线图、各报销类型的饼图分布、近七天申请量的柱状图。
后端统计接口使用SQL的GROUP BY和聚合函数,在时间维度上按月分组计算。这里要注意跨年问题,如果月份统计不做年份区分,2024年1月和2025年1月会混在一起,所以分组条件要带上DATE_FORMAT(create_time, '%Y-%m')。为了前端好处理,后端直接返回一个对象数组,前端循环映射成ECharts需要的格式即可。SQL就是几条简单的聚合查询,不复杂,但对业务分析能力的要求很明确,论文测试章节里放上生成的图表截图非常加分。
5. 部署交付:从源码到能演示的完整环境搭建
5.1 后端打包启动
打包SpringBoot项目,直接mvn package打成jar包。发布环境我建议不要用IDE直接跑,而是用java -jar的方式启动,这是生产环境的标准姿势,答辩演示时也更稳:
mvn clean package -DskipTests java -jar target/medical-reimbursement.jar --spring.profiles.active=prod项目里至少配置dev和prod两个profile,prod环境连接服务器MySQL,配置改成生产库的地址和账号。启动参数可以加-Dfile.encoding=UTF-8避免Linux下乱码,后台上线后可以通过查看日志确认启动没有报错。注意数据库连接初始化必须在jar包启动前完成,第一次启动脚本可以写成一个简单的Shell脚本,包括建库、导入SQL、启动jar三步操作。
5.2 前端构建与Nginx托管
前端代码开发完成后,执行npm run build,生成dist静态目录。发布时把dist目录内容拷贝到服务器上,用Nginx托管静态文件,并配置反向代理把/api路径转发到后端地址:
server { listen 80; server_name localhost; root /opt/medical/frontend; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files $uri $uri/ /index.html这行最重要,Vue是单页应用,刷新非根路径时必须回退到index.html,否则路由会404。这个坑几乎每个新手都会踩,答辩现场如果评委手滑刷新了某个子页面,404了会很尴尬。
5.3 数据库初始化
数据库初始化文件要包含建库语句、建表语句、初始数据三部分。初始数据至少要有:一个管理员账号(admin)、一个审核员账号、两个普通用户账号(密码统一为123456,存BCrypt加密后的字符串)。同时插入几个不同状态的报销单,这样一登录系统就能立刻看到数据,不用现场现填表单,演示节奏会顺畅很多。
SQL文件中的密码哈希需要提前用加密工具生成,不要在部署文档里让用户自己加密。部署文档写清楚MySQL版本要求(建议5.7+)、字符集设置(utf8mb4)、导入步骤,确保一个零基础的同学按文档操作十分钟内能把环境跑起来。
5.4 部署文档的编写
部署文档不要写成流水账,要分环境、分步骤、带结果验证。我的习惯是每完成一步就补一句“看到什么结果说明成功了”,比如:
- 执行数据库导入命令后,用
show tables能看到8张表 - 启动jar后,日志最后出现“Started Application in xxx seconds”表示启动成功
- 访问Nginx配置的IP地址,能看到登录页并且能登录
这样写的文档才是真正可验收的交付物。部署文档质量高,在毕业设计整体评分中的隐性帮助比想象中大,因为这直接体现了工程化交付能力。
6. 常见问题与排查实录:实操中踩过的坑
6.1 前端端口冲突与代理配置
Vue开发环境默认跑在8080端口,SpringBoot后端默认也是8080,两个一启动就把端口占了。解法是改前端的devServer端口为8081,并在vue.config.js里配置代理:
module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };配置成功后,前端请求写成/api开头,开发时自动转发到后端,不需要用完整地址。很多同学前后端联调联不通,八成是这里没配对。
6.2 跨域请求拦截的规范处理
即便开发环境有了代理,生产环境Nginx也配了转发,后端依然要开跨域配置。我直接在WebMvc配置类里写一个CorsFilter,允许本地开发端口访问,但同时设定允许的header和方法范围,不要直接放行所有来源。避免被问到跨域安全问题时无话可答。
6.3 金额精度损失
如果报销金额字段用了Double类型,统计合计时或多次计算时会看到类似19.999999这种脏数据,decimal精度会出问题。发生后端的计算和数据库存储全部改用BigDecimal,前端展示时再toFixed(2)保留两位小数,炼狱问题就此终结。
6.4 图片上传后刷新丢失
开发环境下本地存储的文件路径是相对路径,前端回显时需要拼上后端地址。比如文件存为/upload/2025/05/xxx.jpg,前端根据使用环境拼成http://localhost:8080/upload/2025/05/xxx.jpg。所以上传功能返回的路径建议直接存完整URL,或者前后端统一约定一个文件访问前缀常量,否则图片会刷新后消失。
6.5 版本不兼容问题
SpringBoot 2.7.x搭配MyBatis Plus 3.5.x是经过验证的组合,搭配Druid 1.2.x也正常。如果你非要升级到SpringBoot 3.x,那么MyBatis Plus需要换用3.5.3.2版本以上的对应starter,否则启动会报“Failed to configure a DataSource”之类的错误。毕设没特殊需求,规规矩矩用2.x版本最省事,不用花时间做无意义的版本适配。
6.6 答辩高频问题梳理
最后准备几个答辩高频问题的回应思路,供参考:
- “报销金额为什么不在用户提交时确定?”:因为报销比例可能动态调整,管理员改比例后旧数据不受影响,新提交的单据按新规则计算,这体现系统扩展性。
- “如果两个人同时审核同一张单怎么办?”:更新SQL带状态条件,行级锁保证只有一个请求能成功,另一个会提示单据已被处理。
- “Token过期后前端怎么处理?”:Axios响应拦截器收到401后跳转登录页并清除本地用户信息,这是统一的全局处理。
- “报表数据量大怎么优化?”:SQL加时间索引、聚合查询在MySQL端完成而非查出全部记录内存计算,量级大时还能加缓存层。
7. 论文写作与资料整合的实用建议
7.1 论文结构
毕设论文建议包含六个核心章节:绪论(背景和意义、国内外现状)、需求分析(业务需求、功能需求、用例建模)、系统设计(架构设计、功能模块设计、数据库设计)、系统实现(每个核心模块的实现思路和关键代码)、系统测试(功能测试与性能测试)、总结(项目收获与不足)。
7.2 画图用图
论文配的最重要的几张图,建议花时间画细:
- 系统架构图:画前后端分离、各层之间的关系,分展示层、应用层、数据层
- 功能结构图:树状图展示七大模块
- 报销业务流程图:申请到审核到反馈的完整流程
- 数据库ER图:标注主外键关系
- 时序图:展示用户提交报销申请时前端与后端交互的过程
可以用ProcessOn或draw.io画图,导出为高分辨率PNG。流程图和时序图尤其重要,评委看图能快速理解系统全貌,答辩时你照着图讲逻辑也更顺畅。
7.3 测试章节的写法
测试章节不要只写“功能都正常”,要有测试用例表格。每条用例包含编号、测试步骤、预期结果、实际结果、结论。测试类型覆盖功能性测试(正常流程、异常流程)、权限测试(普通用户访问审核接口应被拦截)、数据合法性测试(金额填负数被后端拒绝)。有异常流程的测试记录,比全绿的功能测试更有说服力,因为它证明你想过“系统会怎样出错”。
7.4 文档格式
部署文档建议写成一个独立的Markdown文件,包含环境要求、安装步骤、项目运行说明、常见问题几个部分。在项目根目录放一个友好的README.md,这个好习惯会让毕业设计的整体交付感提升一个档次。
8. 一些自己在实际带项目过程中的体会
最开始强调的东西,现在值得再说一次:做毕设项目,重要的不是功能有多少,而是整个链路是否完整。很多人报名说“我的系统有推荐算法、有消息推送、有在线支付”,听起来很厉害,但打开代码发现每个功能都只做了三分之一,一被追问就支支吾吾,这个分数反而没有“功能不多但每个都扎实”的项目高。
医疗报销系统最大的优势在于业务核心清晰、流程完整。只要你把申请、审核、状态流转、统计报表这四件事做好做透,每一块都自己能写代码、能讲清楚原理,这就是一个超出平均水平的毕业设计。
最后一个小建议:项目全部开发完之后,一定把整套环境和数据完整删掉重新部署一遍,按部署文档从零开始走一次流程,全程计时。如果超过半小时还没跑起来,说明部署文档还有坑;如果在五分钟内完成并且数据完整、图片能显示、三大角色都能正常登录,这个项目才算真正交付完成。这个预演的体验,会让答辩现场的你稳得不像第一次演示。