基于SpringBoot+Vue的眼科患者随访管理系统设计与实现全解析
高校里每年这个时候最热闹的群一定是各种毕设互助群。一堆人拿着差不多的题目问“有没有现成的系统”“哪个方向好过”“SpringBoot和SSM到底选哪个”然后另一堆人蹲在网盘链接里找源码。说句实话医疗类管理系统在毕设选题里一直很吃香尤其是眼科患者随访这类垂直场景——业务链条清晰、角色划分明确、数据模型不复杂但又有足够的表间关系可以讲非常适合用来体现一个学生从需求分析到系统落地的完整能力。如果你正在为选题发愁或者已经选了这个方向但不知道从哪下手这篇文章就拆给你看一个基于SpringBootVue的眼科患者随访管理系统到底应该怎么做评审老师关心什么以及我踩过的坑和最终沉淀下来的方案。1. 为什么眼科随访是个“性价比很高”的毕设选题先别急着看代码搞清楚选题逻辑比什么都重要。毕设选题有一个隐性规则既不能太简单到没东西写也不能太复杂到做不完。眼科患者随访管理系统恰好卡在中间属于那种“看起来有专业壁垒实际上实现难度适中”的题目。1.1 业务视角这个系统到底在解决什么问题眼科手术和别的科室有个明显区别——术后随访的依从性直接决定手术效果。比如白内障术后、屈光手术后患者需要在术后1天、3天、7天、1个月、3个月这些时间节点回来复查测视力、查眼压、做裂隙灯检查评估恢复情况。但现实情况是很多患者出院之后压根想不起来复查或者复查数据散落在纸质病历和Excel表里医生根本做不了系统性追踪。随访管理系统的核心价值就是把这条线串起来给患者建立档案根据手术类型自动生成随访计划到时间了提醒患者回来复查复查完把数据录入系统医生可以随时查看某位患者完整的恢复曲线也能筛出“该复查但没来”的失访人群做干预。这些需求放在毕设里足够划分出几个像样的功能模块而且每一个模块都有明确的业务意义——答辩的时候你不是在背需求文档而是能讲清楚“这是为了解决什么实际问题”。1.2 技术视角为什么是SpringBoot Vue这套组合如果你去翻最近三年的毕设题目SpringBoot Vue几乎成了标准答案。原因有三个SpringBoot极大降低了SSM时代的配置成本内嵌Tomcat、自动装配、starter机制让一个学生能把主要精力放在业务代码而不是各种XML配置上。Vue的前后端分离模式更贴近企业实际开发流程而且Vue本身的上手曲线比较平缓配合Element UI或者Ant Design Vue做出来的界面不会太寒酸。这套技术栈属于“市场主流”网上资料多、面试也问做完了可以直接写进简历不算白费功夫。至于为什么不用SSM、不用JSP、不用Spring Cloud微服务——记住毕设不是炫技是证明你具备系统开发的基本素养。单体应用 前后端分离 关系型数据库完全够了。1.3 工作量视角如何把题目控制在一个学期能完成的范围内眼科患者随访管理系统听起来很专业但剥开来看核心模块就那么几个系统管理用户、角色、菜单、患者信息管理、随访计划管理、随访记录管理、数据统计。每一个模块都是CRUD的变体但只要你愿意往细节里做工作量是能“控盘”的。我当时给自己划了几条硬性边界不做移动端只做Web端响应式布局保证浏览器可用就行。不做消息推送随访提醒用站内通知 简单的到期筛选列表实现。不做复杂的权限模型基于Spring Security JWT做RBAC角色就三种管理员、医生、护士。不做复杂的报表图表用ECharts展示趋势就行不用接大数据那套。把边界划清楚你就知道接下来每一步该往哪儿使劲了。2. 前期规划从需求分析到技术选型的落地路径这个阶段最忌讳的事就是拿到题目就开写。以前我带过一个学弟上来就建工程、写实体类写了三个星期发现表结构设计得不对推倒重来心态直接崩了。正确顺序是先想清楚“有哪些人要用这个系统”“这些人分别要干什么”“数据从哪里来到哪里去”然后再谈建表、写接口。2.1 用户角色和场景梳理随访管理系统的用户角色并不复杂核心就是三类管理员负责系统基础数据维护包括医生账号的开通与禁用、科室信息的维护、系统参数的配置偶尔也要能查所有数据做全局管理。医生核心使用者。负责给患者建档、制定或调整随访计划、录入每次随访的检查数据、查看患者的历史随访记录和趋势图、关注失访名单。护士一般在医生录入之前负责预约排程和基础信息的登记也可以代替医生记录一些常规随访信息但关键诊断数据还是需要医生确认。有了角色和场景再去画用例图、写需求文档就有抓手了不会写出一堆空话套话。2.2 技术栈选型每一层我做了什么选择为什么这里把我的最终技术清单和选型理由列出来你可以直接抄作业层次选型理由后端框架SpringBoot 2.7.x稳定、资料多比3.x更兼容主流教程避免版本坑ORMMyBatis-Plus单表CRUD不用写SQL内置分页插件省时间安全框架Spring Security JWT前后端分离下无状态认证的经典方案答辩有讲头数据库MySQL 8.0主流关系型数据库资料丰富前端框架Vue 3 ViteVue 3是当前主流Vite启动和打包比Webpack快得多UI组件库Element Plus后台管理系统的UI标配中规中矩不出错图表ECharts可视化随访趋势、统计报表开源免费接口文档Knife4j自动生成Swagger文档方便自测也让老师看得清楚有两点我特别想提醒版本问题是毕设的血泪教训区。SpringBoot 3.0以上要求JDK 17很多学校的教学环境还停在JDK 8。如果你不想折腾各种兼容性问题老老实实选SpringBoot 2.7 JDK 8 MyBatis-Plus 3.5.x。别追求新版本稳定压倒一切。为什么不用Redis如果你的系统里没有明显的缓存需求或分布式锁需求就不要硬加。加了Redis之后一方面要额外处理缓存与数据库的一致性另一方面答辩老师很可能会追问“缓存穿透、雪崩怎么解决”给自己挖坑。2.3 项目结构和开发流程划分项目结构上我采用的是标准的Maven多模块单体结构eye-followup-system/ ├── backend/ # 后端工程 │ ├── src/main/java/com/eye/followup/ │ │ ├── controller/ # 控制层 │ │ ├── service/ # 业务层 │ │ ├── mapper/ # 数据访问层 │ │ ├── entity/ # 实体类 │ │ ├── dto/ # 数据传输对象 │ │ ├── vo/ # 视图对象 │ │ ├── config/ # 配置类 │ │ ├── common/ # 公共类统一返回结果、异常处理等 │ │ ├── security/ # Spring Security相关配置 │ │ └── utils/ # 工具类 │ └── src/main/resources/ │ ├── mapper/ # XML映射文件 │ └── application.yml # 配置文件 └── frontend/ # 前端工程 ├── src/ │ ├── api/ # 接口请求封装 │ ├── assets/ # 静态资源 │ ├── components/ # 公共组件 │ ├── router/ # 路由配置 │ ├── stores/ # 状态管理Pinia │ ├── views/ # 页面视图 │ └── utils/ # 工具类axios封装等 └── package.json开发顺序我建议按这条线走先搭数据库表 → 后端生成实体和基础CRUD → 实现认证和权限 → 实现核心业务模块 → 后端接口自测 → 前端搭建框架 → 前端对接接口 → 联调 → 美化 → 写文档。环节之间是先后依赖的跳步后期一定会返工。核心流程规划往往决定项目的成败。但落实到系统里所有业务流程的起点是一张设计合理的关系模型——下面进入整个项目的地基环节。3. 数据库设计这张表结构让我的系统赢在了起点数据库设计是答辩老师几乎必问的部分。一个设计合理的库不仅能让开发事半功倍还能在论文里画出漂亮的ER图做亮点。这块我前前后后改了四版最后沉淀下来的核心表结构你可以照着用。3.1 核心表清单与角色权限设计我先说权限这部分因为它很容易被做low。很多学生的做法是直接在用户表里加一个role字段用1、2、3区分管理员、医生、护士然后在代码里写if(user.getRole()1)做判断。这样做不是不行但答辩的时候老师一问“如果以后要加一个视光师角色但权限介于医生和护士之间你怎么改”你就得去改代码。更稳妥的方案是标准RBAC模型用户表sys_user、角色表sys_role、菜单表sys_menu、用户角色关联表sys_user_role、角色菜单关联表sys_role_menu。用户表里面不存角色只存账号密码和基本信息角色通过关联表关联到用户菜单表里面的每条记录对应前端的一个路由或页面按钮角色菜单关联表决定某个角色能看到哪些菜单、操作哪些按钮。这个模型在Spring Security里支持得很好而且实现起来也没多复杂。数据库初始化的时候往菜单表里插好记录然后用一个接口根据当前用户ID查出他拥有的所有菜单和权限标识前端根据这个动态渲染路由和按钮v-if后端再用Spring Security的PreAuthorize注解做接口级校验双保险。其他核心表设计如下表名核心字段说明patient_infoid, patient_no, name, gender, birth_date, phone, id_card, address, allergy_history, create_time患者档案patient_no为用户可读的编号建议规则如“YZ日期流水号”surgery_recordid, patient_id, eye_type(左/右), surgery_type, surgery_date, doctor_id, hospital_name, notes手术记录一个患者可有多次手术一对多followup_planid, patient_id, surgery_id, plan_date, plan_type(术后1天/7天/1个月等), status(待随访/已完成/已逾期), actual_date, followup_doc_id随访计划——系统自动根据手术日期生成这是业务核心followup_resultid, plan_id, patient_id, check_date, vision_left, vision_right, intraocular_pressure_left, intraocular_pressure_right, slit_lamp_result, fundus_result, doctor_advice, create_time随访结果记录一次计划对应一条结果sys_userid, username, password, real_name, dept_id, phone, status, create_time系统用户sys_roleid, role_name, role_code, remark角色sys_menuid, menu_name, parent_id, path, component, perms, icon, sort, visible菜单/权限表sys_user_roleuser_id, role_id关联表sys_role_menurole_id, menu_id关联表operation_logid, user_id, operation, method, params, ip, cost_time, create_time操作日志可选但推荐答辩加分项3.2 为什么要有“随访计划”和“随访结果”两张表这是整个系统设计里我自己最满意的一处。一开始我也想过把随访计划和随访结果合并成一张表后来实际模拟业务场景时发现行不通计划是“预期”结果是对“预期”的执行。不是每个计划都会被执行患者可能爽约可能提前可能推迟。一条随访计划可能被多次更新状态待随访 → 已通知 → 已完成 / 已逾期这些状态变更需要独立追踪。从统计角度你需要知道“有多少计划到期了”“执行率是多少”“逾期率是多少”这些统计都得基于计划表的生命周期来计算。所以我把计划表和结果表分开计划表只负责“安排”和“状态”结果表只负责“数据沉淀”。两个表通过plan_id关联一条计划最多对应一条结果。这样设计无论是写业务代码还是做报表统计思路都清晰很多。3.3 字段类型和索引设计上的几个细节几个容易犯低级错误的点必须记下来手机号别用int。手机号11位int根本装不下而且手机号不应该参与计算。用varchar(20)物理上不强制唯一因为存在家属代替登记的“共享手机号”但建议在业务层做重复提醒。金额、视力等数值注意精度。视力记录精确到小数点后一位或两位数据库用DECIMAL(4,2)不要用float否则浮点误差在报表里会非常尴尬。眼压值一般是整数但也可能带小数统一用DECIMAL更安全。所有表都要有create_time和update_time。MyBatis-Plus的TableField(fill FieldFill.INSERT)配合MetaObjectHandler自动填充业务代码里不用手动set省很多事。外键不要物理加靠逻辑关联。这一点可能和很多教程教的不一样——实际上企业开发中几乎不用物理外键因为影响插入效率和后续维护灵活性。你只需要在关联字段上建普通索引然后在代码里保证引用的完整性就行。但注意论文里画ER图时把关联关系画上该讲的逻辑还是要讲清楚。随访计划的到期筛选要建联合索引。最常用的查询是“某医生名下的所有患者今天有哪些随访计划到期”所以followup_plan表的(doctor_id, plan_date, status)建一个联合索引实测查询性能差很多。3.4 初始化数据的处理技巧系统的运行离不开初始数据我的做法是这样的准备一个init-data.sql里面包含管理员账号admin、一个演示医生账号、一个演示护士账号以及对应的菜单权限数据。数据库导入项目压缩包之后只要执行一次这个脚本系统就能登录。菜单数据建议设计成树形用parent_id关联前端拿到之后递归渲染成侧边栏。权限标识用system:user:add、patient:info:edit这种风格配合Spring Security的方法级校验非常好用。不要偷懒在application.yml里配置ddl-auto: update让Hibernate自动建表。我们用MyBatis-Plus表结构应该用SQL文件明确维护这样评审老师看你的项目文档时能直接把你设计的表看清。数据库搞定之后后端核心模块的实现顺序就变得有章可循了。我习惯从最硬的骨头——「认证授权」——开始啃。4. 后端核心模块实现从认证鉴权到业务闭环的写法拆解后端是整个系统的发动机。这一部分我挑几个核心模块讲实现思路和关键代码不会贴全套源码但核心骨架和容易踩坑的点都给你交代清楚。4.1 基于JWT的登录认证与权限控制前端Vue项目调用后端接口最常见的方案是用户输入账号密码 → 后端验证 → 返回JWT令牌 → 前端把令牌存到localStorage → 之后每次请求在Header里带Authorization: Bearer token→ 后端拦截器校验令牌有效性并解析出用户身份。SpringSecurity里要做的核心配置用一个自定义过滤器JwtAuthenticationTokenFilter在UsernamePasswordAuthenticationFilter之前做令牌校验Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { Autowired private JwtUtils jwtUtils; Autowired private UserDetailsServiceImpl userDetailsService; Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token request.getHeader(Authorization); if (StringUtils.hasText(token) token.startsWith(Bearer )) { token token.substring(7); String username jwtUtils.getUsernameFromToken(token); if (username ! null SecurityContextHolder.getContext().getAuthentication() null) { UserDetails userDetails userDetailsService.loadUserByUsername(username); if (jwtUtils.validateToken(token, userDetails)) { UsernamePasswordAuthenticationToken authentication new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } } filterChain.doFilter(request, response); } }再配合自定义的RestAuthenticationEntryPoint处理未认证请求返回JSON自定义的RestAccessDeniedHandler处理无权限请求返回JSON而不是默认的重定向到登录页。这两个Handler是很多教程容易漏掉的如果不自定义前后端分离项目里一旦token过期前端收到的就是一段HTML而不是标准JSON排查半天查不出来。密码存储方式用BCryptPasswordEncoder加密别用MD5。这也是老生常谈了但答辩时依然有人栽在这儿。BCrypt每次加密结果都不一样但matches方法可以做校验安全性远超MD5而且Spring Security原生支持。4.2 患者管理与随访计划的业务规则实现这是系统的“业务灵魂”也是论文里可以重点展开的算法逻辑。患者建档这块本身不复杂无非是常规的增删改查但有一个点值得讲患者编号生成规则。我用的是“YZ” yyyyMMdd 四位流水号比如YZ202506120001。实现方式是查当天最大编号然后1再补零。这里不能直接SELECT MAX(id)1因为删过数据之后会发生冲突正确做法是查当天创建的记录里最大的patient_no取末尾四位数加一。用一个事务方法包装Transactional public String generatePatientNo() { String today LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); // 20250612 String prefix YZ today; String maxNo patientMapper.selectMaxPatientNoByPrefix(prefix); int next (maxNo null ? 0 : Integer.parseInt(maxNo.substring(maxNo.length() - 4))) 1; return prefix String.format(%04d, next); }随访计划自动生成是整个系统最有“业务感”的逻辑。规则是这样建档时如果录入了手术记录手术日期、手术类型系统自动根据手术类型配置好的随访节点生成多条followup_plan记录。比如白内障手术的随访节点默认是术后1天、7天、30天、90天。生成计划的代码用LocalDate.plusDays()算出计划日期然后批量插入。要做得细致一点还可以在同一天只生成一条计划避免重复。伪代码如下public void generateFollowUpPlans(Long surgeryId) { SurgeryRecord surgery surgeryMapper.selectById(surgeryId); ListFollowUpPlan plans new ArrayList(); // 根据手术类型获取随访节点配置 ListInteger offsetDays configService.getFollowUpOffsets(surgery.getSurgeryType()); for (Integer offset : offsetDays) { FollowUpPlan plan new FollowUpPlan(); plan.setPatientId(surgery.getPatientId()); plan.setSurgeryId(surgery.getId()); plan.setPlanDate(surgery.getSurgeryDate().plusDays(offset)); plan.setPlanType(术后 offset 天); plan.setStatus(待随访); plans.add(plan); } followUpPlanService.saveBatch(plans); }这里就体现出配置化思维的好处如果以后医院想调整某个手术类型的随访节点只要改配置数据不用改代码。论文里可以专门用一小节写这套配置化设计扣中“系统可维护性”这个得分点。4.3 随访结果录入从表单提交到趋势图的数据流转随访结果录入页面长这样护士或医生选择一条待随访的计划 → 进入录入页面 → 填写左右眼视力、眼压、裂隙灯检查结果、诊断建议 → 点击提交 → 系统更新随访计划状态为“已完成” → 同时写一条随访结果记录 → 患者360视图里的趋势图自动更新。这个流程涉及两张表的写操作需要放在一个事务里。只要记住一点改状态必须带条件更新防止并发重复提交导致状态覆盖。我用UPDATE followup_plan SET status 已完成 WHERE id ? AND status 待随访返回影响行数为1才算成功否则提示“该计划已被处理”。趋势图的数据来自followup_result表的按时间排序记录。后端一个接口GetMapping(/patient/{patientId}/vision-trend) public Result getVisionTrend(PathVariable Long patientId, RequestParam String eyeType) { ListFollowupResultDTO results followupResultMapper.selectTrendByPatientId(patientId); // 过滤出对应的眼睛数据补充到图表结构 return Result.success(results); }前端用ECharts折线图展示横轴是复查日期纵轴是视力值。图上还能用一条参考线标出0.8的“标准视力线”一眼就能看出患者恢复情况。4.4 异常处理、日志与统一返回这些细节决定“代码规范度”评审老师不一定有耐心看完全部代码但打开Controller第一眼看到的是RString这种统一返回结构再往下看有没有全局异常处理基本就能判断你的代码水平。我的做法统一返回体用ResultT包含code、message、data三个字段。Controller不直接try-catch所有异常抛给RestControllerAdvice全局异常处理器。业务异常用自定义的BusinessException里面带错误码。操作日志用AOP切片做自定义Log注解配合SpEL表达式解析方法参数把操作人、操作类型、请求参数、耗时写入日志表。这个AOP切片看起来复杂实际代码量不大可以在论文里单独列一节。我还加过一个细节所有Controller的接口路径统一以/api/开头配合前端的axios baseURL。这样以后做网关、做权限拦截都方便。后端完成之后整个人会轻松一大半因为最难啃的业务规则都通了。但前端这块如果不细心一样会把体验拖垮。接下来我按前端的关键模块讲讲怎么做到“能看又能跑”的标准。5. 前端落地Vue3 Element Plus怎么搭出能打的面子前端是老师第一眼看到的东西。说句实在话一个界面丑陋的系统代码写得再好首因效应也会打折扣。反过来说界面清爽、交互顺手哪怕有些小功能没实现到位老师对你的容忍度都会高不少。5.1 前端工程化配置和路由权限控制Vue3项目用Vite初始化几行命令搞定npm create vuelatest frontend cd frontend npm install npm install axios vue-router pinia element-plus element-plus/icons-vue echarts重点说一下路由权限控制。这是前端的一个核心考点不同角色登录后看到不同的菜单。我的方案是“动态路由”方案登录成功后后端返回该用户拥有的菜单列表树形结构每个菜单项对应一个路由的name和path。前端把固定路由如登录页、404页和动态路由分开。动态路由在用户登录后通过router.addRoute()动态添加。在路由全局前置守卫里判断如果没有token就跳登录页如果有token但没有菜单数据就拉取菜单并动态添加路由刷新页面时路由已经持久化到Pinia里配合localStorage不会出现刷新后白屏。按钮级权限用自定义指令v-permission传权限标识作为参数如果没有权限就从DOM里移除按钮。这套方案不是最复杂的但很稳定且代码量适中。比我见过的一些“把所有菜单都写在路由表里用v-if隐藏”的方案高级得多也比用前端角色字符串写死的方案灵活。5.2 核心页面设计患者列表、随访日历和患者360视图页面设计上我按“使用频率”来分配精力患者列表页是医生打开系统第一个看到的页面。设计要点是搜索条件丰富姓名、手机号、手术类型、建档时间区间表格列清晰患者编号、姓名、性别、年龄、联系电话、最近手术类型、当前状态操作区放置“建档”“查看”“编辑”“随访记录”按钮。搜索区域用el-card包裹表格用el-table分页用el-pagination。页面的数据量不大不需要虚拟滚动但分页逻辑必须做对。随访日历页是体现系统“智能”的地方。我用el-calendar组件做月视图把当月所有待随访、已完成、已逾期的计划用不同颜色的badge标在日期上。点击某一天右侧面板显示当天的计划列表每条计划有“患者姓名、计划类型、联系电话、状态、操作按钮”。这个页面一出来整套系统的业务感就上来了——它直观地告诉使用者“今天该联系谁”。日历数据接口按月份范围拉取GET /api/followup-plan/calendar?year2025month6doctorIdxxx患者360视图是单患者页面的别名集中展示一位患者的全部信息基础档案、手术历史、随访时间线、视力趋势图、眼压趋势图、历次医嘱。前端用标签页el-tabs组织这些信息块。时间线用el-timeline组件一条条记录按时间倒序排列状态用不同颜色区分。这个页面的完整程度直接影响答辩展示效果我建议把能想到的信息都整合进去。5.3 axios封装、请求拦截和防重复提交axios不封装直接到处用是前端代码里很掉价的行为。我的封装思路创建service.js实例设置baseURL: /api超时时间10000ms。请求拦截器里从localStorage取token加到Authorization头。不取lStorage而用Pinia刷新页面后Pinia状态丢失取不到token所以一定要用localStorage兜底。响应拦截器里判断res.data.code是否等于200相等就返回res.data.data否则弹出ElMessage.error(message)。如果code等于401token过期清除本地身份数据并跳转登录页。做一个简单的防重复提交处理在封装的request函数里如果5秒内发起相同URL和相同参数的请求直接拦截掉提示“操作太频繁”。实现方式可以维护一个Map记录上次请求时间戳代码不超过二十行但能有效改善双击按钮产生的重复数据。5.4 前端联调和打包部署的几个坑前后端联调阶段坑主要集中在跨域和打包路径上。这个问题有两种解法开发环境跨域Vite的server.proxy配置把/api代理到http://localhost:8080这样前端调用/api/xxx就能正常访问后端避免CORS问题。后端允许跨域在SpringBoot里配置CorsFilter或者使用CrossOrigin。这种方式简单但我个人不太推荐在项目中全局放开跨域因为安全性较差。你只需要在本地开发时用Vite代理就够了。打包部署的时候Vue项目npm run build生成dist目录后端可以用两种方式托管方式一把dist目录里的内容直接复制到SpringBoot的src/main/resources/static下打成单个jar包运行。这是最简单的部署方案也适合交给老师演示双击jar包就行。方式二用Nginx单独托管前端静态文件后端jar包单独跑加一层反向代理。这种方式更真实但答辩现场演示需要多开一个Nginx万一环境不对容易翻车。我自己最后选了方式一把前端打包结果放进后端一个jar包搞定全部功能演示的时候省心不少。前端能跑了系统基本成形。但一个能跑的系统离“能过答辩”还差最后一段路——那就是打磨细节、准备好容易被追问的“硬核问题”。6. 答辩前的自查清单功能演示的顺序设计与评审追问预案很多学生功能做得没问题但答辩时手忙脚乱讲到一半老师问了个冷门问题直接卡壳。这块我整理一份我自己的“答辩前自查清单”照着过一遍能大幅降低翻车概率。6.1 功能演示务必按“故事线”走不要功能菜单一个个点过去那样太散。要按用户故事串起来以管理员身份登录展示首页的数据统计面板今日待随访数量、本周已完成随访数量、患者总数、手术总数一句话概括系统价值“这是一个为眼科术后患者提供全过程随访管理的平台”。进入患者管理新增一个模拟患者录入基本信息并添加一条手术记录。注意这时候别着急演示其他功能而是强调“提交建档后系统根据手术类型自动生成了4条随访计划”。切到随访计划页面展示自动生成的记录说明计划来源和状态流转。然后模拟给一条计划录入随访结果页面跳转到患者360视图视力趋势图出现了一个新数据点。演示一下权限控制用护士账号登录尝试访问“系统管理”菜单页面菜单直接不显示如果手动敲URL访问接口则前端提示无权限。这是技术亮点建议放在后面压轴。最后打开接口文档页面Knife4j展示所有接口的在线调试能力。这个页面不需要特别演示细节但能让老师知道你的接口文档是规范的。6.2 评审老师爱问的几个问题提前把答案准备好问题参考回答思路为什么选SpringBoot而不是SSM自动配置减少开发成本内嵌容器省去外部Tomcat生态丰富社区活跃更适合快速迭代的中小型系统JWT和Session有什么区别为什么选JWTSession需要服务端存储集群环境下要共享JWT无状态、服务端不需要存会话数据适合前后端分离和水平扩展。缺点是token体积大但本项目数据量小不受影响。如果随访计划到期没执行系统怎么处理每天定时任务扫描计划状态把“待随访”且plan_date 今天的改为“已逾期”生成失访提醒列表供医生关注。这里我想要强调可以补充一个Scheduled的定时任务实现是加分项。报表里的数据是怎么算出来的描述SQL聚合逻辑比如统计执行率已完成计划数/到期计划数到期计划数是状态为已完成已逾期的总和。建议在系统里加上一个统计页面用ECharts展示。系统的安全性怎么做密码BCrypt加密接口JWT鉴权方法级权限校验参数校验用ValidatedSQL用MyBatis-Plus预编译防注入前端路由守卫和按钮权限双重控制。数据库为什么用物理外键回答前要先想好你的实际用法如果你没开物理外键要不说逻辑外键要不就承认当初为灵活性做逻辑外键。但更稳妥的是在表里保留逻辑外键字段不建实际约束解释为“牺牲数据库约束换取业务层灵活性同时便于分库分表”。6.3 代码层面提前清理和优化的项目这个环节看着不起眼但绝对能影响印象分删掉无用的System.out.println换成logback日志。统一代码风格缩进、命名、空行全部过一遍controller和service的命名保持一致。数据库脚本提供初始化数据确保老师导入SQL后可以直接登录。README文档写清楚项目简介、技术栈、环境要求、启动步骤、默认账号、项目结构说明。Word版论文之外README是你留给评审老师最高的第一印象资产。例外处理别把错误堆栈直接抛给前端响应体只返回message。堆栈打到服务端日志里就好。这些动作不会花太多时间但对“代码规范”这项评分维度的帮助立竿见影。系统能跑通、答辩能讲清楚之后这套项目其实还可以继续往前走。最后我额外讲两个你在基础功能之外值得花时间做的“加分设计”同时把整个开发周期的时间管理经验分享给你。7. 加分设计与时间管理让这个项目超出“普通毕设”一档7.1 定时任务 邮件提醒从“被动查询”到“主动通知”做完核心功能后我发现一个体验上的硬伤医生每天要主动打开系统看“今天有哪些随访计划”如果忘了打开就漏掉患者了。这不符合真实场景。于是加了一个Scheduled定时任务每天早上9点扫描当天待随访计划给负责医生发送提醒邮件。引入spring-boot-starter-mail配置一下发送方邮箱再写一个简单的JavaMailSender工具方法就好。这个功能的关键点是邮件正文不要只列计划编号要包含患者姓名、联系电话、计划类型、预计检查项目让医生在邮件里就能判断优先级。有的同学可能会想加短信通知患者我劝你不要碰——接入短信服务需要企业认证个人开发者很难搞定而且涉及资费这超出毕设范畴了。用邮件提醒医生已经足够证明你理解业务痛点。7.2 数据统计让系统从“记录工具”升级为“管理工具”统计页面的设计思路是给管理者用的按月统计新增患者数量、手术数量、随访执行率、复查视力达标率。执行率是重点计算公式随访执行率 已完成随访计划数 / 到期计划数 × 100%其中到期计划数 已完成 已逾期。这个口径要写在论文里因为老师一定会问“为什么分母不含未到期计划”——正确答案是“未到期计划还没到时间它们不应该被计入执行率的评价范围否则月末统计会把未来计划误伤成未执行”。用ECharts柱状图展示月度趋势饼图展示随访状态分布待随访、已完成、已逾期。数据直接从followup_plan表按状态group by得到SQL非常简单但业务意义很强。7.3 开发周期怎么排才不至于熬夜按照我踩过的坑一个合理的周期安排是这样的阶段时间主要产出需求分析与开题1周需求文档、用例图、ER图初稿数据库设计与后端基础2周建表SQL、SpringBoot工程、登录注册核心业务模块2周患者管理、随访计划、结果录入前端页面开发2周所有页面、接口对接自动化任务与统计1周定时任务、统计报表系统测试与修Bug1周功能测试、边界用例论文撰写2周论文初稿到定稿演示准备与预答辩3天PPT、演示环境、答辩演练加起来大约11周。如果你从拿到题目的第一天就开始动手这个节奏是够用的。最怕的情况是前六周都在“想”和“拖”最后三周靠通宵补代码那样写出来的系统后期几乎不可维护答辩时也讲不清细节。最后分享一个我个人的体会做毕设最大的收获不是那个“优”或者“良”而是你完整经历了从业务问题到软件交付的闭环——包括选型时的纠结、建表时的反复、联调时的抓狂、答辩前的紧张。做完这个眼科随访系统之后再回头看SpringBoot和Vue的学习资料很多当初似懂非懂的概念突然就通了。这套经验会直接延续到你第一份实习、第一个真实项目上。