ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Spring Boot的大学生心理健康调查系统设计实战

基于Spring Boot的大学生心理健康调查系统设计实战 大概一年前我帮一个学弟折腾毕业设计题目写的是基于 Spring Boot 的大学生心理健康调查系统。他当时从某开源平台下载了一套所谓完整源码结果光是让项目正常启动就花了两天——数据库脚本版本对不上、前端请求路径写死、量表题目和统计逻辑完全脱节。最后我们坐下来重新理了一遍需求和表结构才真正把系统跑起来。后来我把这套从零梳理的思路整理成了这篇内容给正在被类似毕设题目折磨的同学做个参考。无论你是打算完全自己写还是拿到一套源码想改造成自己的东西这篇文章都能帮你在动手前先想清楚这个系统到底要做什么、怎么做才不像玩具项目。我见过太多人把这类题目当成问卷网 登录注册来做答辩时被老师一问你的系统对辅导员有什么实际价值就卡壳。心理健康调查系统的本质不是收集答案而是通过量表把学生的心理状态量化再让老师能及时发现需要关注的对象。这个定位想清楚了后面所有设计都不会跑偏。1. 先搞清楚这是个调查系统还是量表系统需求边界决定工作量1.1 我在选题后先做的功能清单拆解这类毕设题目看起来简单实际上一开始就混淆了两个概念普通问卷调查和心理量表测量。普通问卷问的是事实比如你每天睡几个小时心理量表测的是状态比如最近两周你是否感到情绪低落。两者的区别在于量表必须有评分规则、维度划分和结果解释不然调查完只能导出一堆 Excel什么结论都得不到。我当时给 A 同学拆需求时先把系统分成了五个模块系统管理学生、辅导员、管理员账号、量表管理题目、选项、维度、计分规则、调查任务发布问卷、设置时间、指定对象、作答与提交防重复、断点记录、结果分析维度得分、预警判定、趋势报表。这五个模块就是完整系统的核心骨架。在此基础上再考虑次要功能消息通知提醒未作答学生、导出按班级导出报告、数据显示雷达图、条形图。次要功能的优先级不要一开始就做先把主线流程跑通。A 同学一开始想加论坛、加心愿墙我直接劝他删掉——毕设评审看重的是逻辑完整性和技术深度不是功能数量。1.2 这类系统最容易画蛇添足的三个地方第一盲目模仿问卷平台做自定义表单拖拽。心理量表是标准化的题目、选项、算分规则都必须固定拖拽编辑器除了消耗时间没有任何实际用途。你要做的是量表配置不是表单设计器。第二把结果分析做成对每题逐个统计。真正的心理量表是按维度算分的比如一个抑郁自评量表可能包含 20 道题每 10 道题属于一个维度最后算的是维度均分和总分。逐个统计题目对于心理评估没有任何意义。第三预警功能只会弹红字。预警不是说这个人得分高而是得分超过某个阈值后系统要把这个信息以合适的方式推送给指定角色同时还要考虑学生隐私。这块如果做不好答辩时最容易被追问。2. Spring Boot 前后端分离的架构选择为什么我最终这样搭2.1 后端工程分层与目录设计选型上我没有犹豫直接用 Spring Boot 作为后端框架。原因很简单它内置 Tomcat、自动配置、起步依赖丰富毕业生最容易在最短时间内把工程跑起来。我见过用 SSM 手写一堆 XML 配置的同学不是说不行而是调试周期太长容易把心态搞崩。工程结构我推荐按功能分包而不是按三层架构分包。很多教程喜欢让建controller、service、mapper三个包结果到后期找某个功能的代码要翻三个地方。我实际用的是按业务模块分包com.example.psychsurvey ├── common # 统一返回结果、全局异常、工具类 ├── config # 权限拦截、跨域、Swagger配置 ├── module │ ├── auth # 登录、验证码 │ ├── user # 用户管理 │ ├── scale # 量表与题目管理 │ ├── survey # 调查任务发布 │ ├── answer # 作答与进度 │ ├── report # 统计分析 │ └── notice # 通知提醒这样改起来有个好处给系统加一个导出报告功能时你只需要在report包里改动不会误伤量表模块。毕设答辩时老师让你现场改需求这种结构会给你省很多事。2.2 调查系统与普通 CRUD 项目不同的设计点普通管理系统是增删改查 权限心理调查系统多了一个完全不同的东西业务状态流转。一个调查任务从草稿到发布中再到已结束每个状态下允许的操作完全不同。草稿可以改题目发布中不能改题但可以追加学生已结束只能看统计。这个状态机的设计比增删改查本身更能体现你对业务的理解。前端我选择的是 Vue Element UI。如果你拿到一套现成源码大概率也是这个组合。Spring Boot 提供接口前端通过 axios 调用用 JWT 做登录态管理。前后端分离的好处是答辩演示时前端可以单独跑在开发服务器上后端哪怕换一台电脑重新打包前端代码也不用动。不过前后端分离有个坑跨域配置必须提前想好。我在配置类里加了全局跨域支持允许前端开发服务器访问后端接口。很多同学前后端代码都对就是联调时死活不通八成都出在这个配置上。3. 数据库表设计的几个关键权衡3.1 量表版本与题目组的建模心理健康量表有个特点同一个量表会定期修订题目顺序可能调整甚至删除个别题目。如果你把题目直接写死在调查任务表里一旦量表改版历史数据就全毁了。所以数据库设计上必须把量表版本单独抽出来。我设计了四张核心表scale量表主表存名称、类型、适用人群、scale_version版本表存版本号、题数、说明、scale_question题目表所属版本、题干、所属维度、scale_option选项表所属题目、选项文本、分值。作答记录关联的是scale_version的 id而不是量表主表 id。这样量表更新后旧问卷查出来依然能正确评分。这里还要注意维度字段。心理量表一般把题目分成几个维度比如情绪困扰人际关系学业压力。维度放在scale_question表里每个题目挂一个维度编码统计时按维度分组聚合非常方便。3.2 匿名作答与登录作答能否兼容这是我在做需求分析时被问住过的问题如果系统强制学生登录后再作答那学生会不会因为担心被老师看见而不愿意真实填写如果完全匿名老师又怎么知道哪些学生需要关注我的方案是后台关联前台匿名。具体做法是作答记录表里有一个student_id字段但前端展示和导出时默认不显示学生姓名老师只有在预警名单里才能看到具体是哪位学生需要关注。同时系统提供两种模式一般心理普测用实名登录作答但承诺数据由指定教师查看敏感专题调查可以用匿名码作答学生凭随机码参与老师只能看到汇总统计。两种模式通过调查任务的一个字段anonymous来区分。这个设计不只是满足功能需求它体现的是隐私意识。答辩时老师很可能问学生隐私怎么保护这一个字段加一个导出控制逻辑就能回答得很好。3.3 结果解读规则的设计评分维度、预警阈值量表最核心的价值是结果解读。我用一个独立的interpret_rule表来存评分区间和对应建议。每条规则包含所属量表版本、维度编码或总分、最低分、最高分、等级描述、建议文案。比如某个量表某个维度满分是 30 分我们可以设置总分 0-10 为状态良好11-20 为存在一定困扰21-30 为需要重点关注。预警阈值在规则表里用warning_flag字段标识。计算得分时后端先把原始选项分值加总再去规则表里匹配等级。这样如果老师觉得阈值太灵敏改一下规则表的数据就行不用改代码。这个设计比把规则硬编码在 Java 里高明得多。我见过有人用if (score 20) return 预警看着没问题但业务一调整就抓瞎。4. 核心流程实现问卷发布、作答、统计报表4.1 问卷发布与截止控制的实现细节调查任务表的核心字段有任务名称、关联量表版本、发布对象可按学院/班级/指定名单、开始时间、截止时间、是否匿名。发布时系统会做两件事给范围内所有学生生成待作答记录同时生成一条站内通知提醒。生成待作答记录时要注意性能。如果一个学院有 2000 人不要在发布任务时循环 2000 次插入。正确做法是用批量插入一条 SQL 把学生 id 列表按批次写入survey_target表。我当时用 MyBatis 的foreach配合批量插入发布一个两千人的问卷只需要几百毫秒。截止控制我用了三层保障前端倒计时到了之后禁用提交按钮后端在提交接口里校验当前时间是否在窗口内数据库层给survey_task表一个end_time字段用于最终兜底。三层都在才能避免我明明截止了还能交的尴尬问题。4.2 作答保存一次性提交还是逐题保存这个问题我在做项目测试时踩过坑。一次性提交简单但学生在中途关掉浏览器之前答的二十道题全部白费很容易引起学生情绪反弹。逐题保存用户体验好但实现复杂度高还要处理半份作答记录的续答场景。我最终采用的是分段缓存 最终提交方案每答一题前端把答案放进本地状态每十题自动保存一次到后端接口是submit_partial只更新该学生的临时作答进度全部答完后调用submit_final后端校验所有题目是否已答再计算得分。断点续答时answer_record表里查 progress 状态把已答题目回填到表单里。实际实现中我状态字段用pending未开始、doing进行中、finished已完成、expired超时未交。答辩时可以讲清楚这个设计老师会认为你考虑到了真实场景中的异常情况。4.3 统计报表与趋势分析的实现思路统计报表不能光做一张总表。我把报表分成了三层第一层是任务总览显示应测人数、已测人数、完成率、预警人数第二层是维度分析按各维度均分对比各班级第三层是明细列表辅导员需要关注的重点学生名单。技术实现上我用的是聚合查询加内存计算。先查原始分数列表然后在 Service 层用 Stream 分组计算均值、标准差。对于这种答辩项目不需要引入复杂的大数据组件但要注意把计算逻辑写清楚比如标准差公式用对、均值保留两位小数等等。趋势分析这块如果只有一次调查是看不出趋势的。我预留了survey_task的批次字段同一个人多次参与同样量表时可以做纵向对比。用折线图展示某个学生或某个班级连续三次调查的维度得分变化。这个功能虽然简单但答辩效果非常好因为评委能看到系统的长期价值。5. 权限与脱敏学生、咨询师、管理员三角色5.1 基于角色的访问控制与菜单配置我用 Spring Security 加 JWT 做认证授权角色分成三种STUDENT学生、COUNSELOR辅导员/咨询师、ADMIN系统管理员。每种角色看到的菜单完全不同。学生端登录后只看到待办调查历史记录个人报告辅导员端看到我管理的学生调查任务预警名单统计报表管理员端除了这些还有量表管理用户管理系统日志。菜单权限我用一张role_menu关联表配置后端在登录接口里根据角色返回菜单树。前端拿到菜单后渲染路由后端再在接口上做权限校验双管齐下。特别注意接口权限校验不能只依赖前端隐藏按钮。我写了自定义注解RequireRole(COUNSELOR)加在 Controller 方法上通过 Spring AOP 拦截。这样就算有人绕过前端直接调接口也拿不到不在他权限范围内的数据。这个点值得在答辩时主动讲一下。5.2 敏感数据的脱敏与导出权限心理健康调查的数据敏感性比普通系统高一个量级。我在代码里做了三件事第一所有列表接口默认不返回学生姓名只返回学号后四位加星号比如2024****0235第二预警名单接口单独写了查询逻辑只有刚好带这个学生的辅导员才能看到完整姓名和手机号第三导出 Excel 时普通用户导出的是脱敏数据只有管理员可以导出全量数据。脱敏字段在数据库里其实存了完整数据是在接口返回前处理掉的。这样做有一个好处不同的接口可以按需决定脱敏粒度同一个学生对象在管理员视角是完整的在学生列表视角是脱敏的。我当时怕麻烦想直接在数据库里只存脱敏后的学号幸好没这么做否则后续做消息通知根本没法准确推送。6. 从能跑到能答辩打包部署、测试数据与演示脚本6.1 打包部署与演示环境的准备代码写完只是第一步我还花了不少时间折腾部署。Spring Boot 项目用mvn clean package打成 jar 包前端npm run build生成 dist 目录。这里要提醒一个常见问题前端打包后要手动把请求地址改成后端服务器的 IP或者配置 nginx 反向代理。很多同学在自己电脑上跑得好好的打包到服务器就全部 404就是因为前端代码里写死了http://localhost:8080。如果你没有云服务器演示时在本地跑也是可以的。但至少要把数据库脚本、初始化 SQL、账号密码写在 README 里。我这个项目初始化了三个演示账号管理员admin、辅导员counselor01、学生student01密码统一初始化后由各角色自己修改。演示时直接用学生账号做一份量表再到辅导员视角看统计结果整个流程顺畅无阻。6.2 答辩常见问题与数据准备的建议答辩前我给 A 同学列了一组高频问题并让他逐个回答为什么选 Spring Boot量表评分规则是什么跨域和安全认证怎么做的预警阈值依据是什么这些问题在正文里都有对应答案关键是要能脱稿说出来。还有一件很重要的事演示数据必须丰富。我帮他准备了一组模拟数据大约 200 名学生、3 个班级、2 个历史调查批次每个学生的作答时间随机分布。这样打开统计页面时表格有数据、图表有形状不会出现暂无数据的空页面演示观感完全不同。生成模拟数据时我写了一个小脚本用随机数生成分数并保证部分学生维度分偏高这样预警名单里也有人展示效果最好。我自己带人做毕设的一个体会是编码能力固然重要但把系统讲明白的能力在答辩里占比可能接近一半。你不需要背稿但要把每一个设计决策背后的原因说清楚——为什么这样建表、为什么用这个状态、为什么这里要限制权限。这篇文章里记录的每一个权衡点都是可以用来回答问题的素材。最后再分享一个小经验如果你拿到的源码里数据库脚本是 MySQL 的而你本地装的是 MySQL 8记得检查驱动版本和时区配置。serverTimezoneAsia/Shanghai这类小参数经常会让人在部署环节卡住。把这个配置提前在application.yml里写好能给你省下一整天的排查时间。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进