
很多计算机专业的朋友在做毕业设计选题时都会纠结一个问题既要考虑题目本身的工作量能不能撑起一篇论文又要考虑技术栈是不是有含金量、答辩的时候好不好演示。今天我想讲的这个题目我在带项目的时候见过很多次也被问过很多次——Java SpringBoot 做中学生心理健康管理系统也就是一个 Web 版的心理测评平台加学生心理档案管理系统。这个题目选得很有代表性它不只是一个“增删改查”的普通管理系统还涉及测评流程、量表计分、档案生成、数据可视化这些比较有文章可做的模块用来当毕业设计展开空间很大也不至于做到一半发现没东西可写。这个系统面向的使用对象大体上分成三类学生、班主任或心理教师、系统管理员。学生登录后能在线完成心理测评问卷、查看自己的测评报告教师端可以创建测评任务、查看班级学生的心理档案、处理预警信息管理员负责维护基础数据比如学生信息、量表题库、角色权限等。技术实现上后端用 SpringBoot前端用 Web 页面数据存 MySQL缓存和会话看需要选择 Redis。整套东西做下来既能锻炼业务抽象能力也能把 SpringBoot 的常用功能完整过一遍。我下面会把我认为这个系统最值得花心思的几个环节拆开讲包括整体设计、数据库表怎么建、测评计分怎么实现、档案和预警怎么联动、以及实操过程中常见的坑。准备照着这个思路做毕业设计的话可以直接参考。1. 项目整体思路与技术选型解析1.1 为什么选“中学生心理健康管理系统”做毕业设计选题目首先要想清楚一个问题你选的题目能不能让答辩老师一眼看出“这个学生是真的做了系统分析而不是套了一个管理系统的壳子”。中学生心理健康管理系统恰好符合这个标准原因有三点。第一业务场景真实存在需求逻辑清晰。中学阶段的心理健康问题一直受关注学校通常需要定期组织心理测评记录学生心理健康状态对异常情况进行干预。这个业务链路天然包含“测评任务发布—学生答题—自动计分—生成档案—异常预警—教师干预”的完整闭环每一步都能对应到系统功能。第二核心逻辑有计算含量。心理测评不是学生答完题就结束了量表都有计分规则。比如常用的90项症状自评量表通常称为SCL-90每个题目按1到5分计最后要算出总分、总均分、阳性项目数还要按因子归类统计。把这些规则在代码里实现就比普通的增删改查有深度。第三数据展示有亮点。测评结果可以用雷达图展示九个因子得分用折线图展示某位学生多次测评的趋势用柱状图展示班级整体情况。答辩现场一打开大屏看可视化效果直观也方便讲数据背后的业务含义。1.2 技术栈选型分析SpringBoot MyBatis-Plus MySQL技术栈方面这个项目最稳妥的组合就是 SpringBoot MyBatis-Plus MySQL再根据前端方案选择搭配 Thymeleaf 或者 Vue。先说说 SpringBoot 为什么是首选。它内嵌了 Tomcat不用单独部署容器打出一个 jar 包就能跑演示的时候非常方便。另外 SpringBoot 的自动配置机制足够成熟官方文档和网上的资料量也大遇到问题容易查到解决方案。这些特性对毕业设计来说很重要因为你要把主要精力放在业务逻辑上而不是花两周时间折腾环境配置。MyBatis-Plus 是 MyBatis 的增强工具提供单表 CRUD 的通用方法不用自己写繁琐的 SQL。测评系统的实体类不少学生、用户、量表、题目、测评记录、作答明细、预警记录……有 MyBatis-Plus 的 BaseMapper 兜底基础数据接口能很快搭完把时间省下来写计分引擎和业务规则。数据库选 MySQL 是约定俗成的选择。中小规模数据量下它足够稳定大学实验室和云服务器也都比较容易部署。如果答辩老师问为什么不用 Oracle 或者 PostgreSQL可以回答说项目定位在轻量级部署场景MySQL 成本和维护门槛更适合中学信息化环境。前端方案这里有两种路线我都试过第一种是 Thymeleaf 服务端渲染。SpringBoot 对 Thymeleaf 的支持很完善页面模板和后端 Java 代码在同一个工程里不需要处理跨域问题部署也简单。适合前端基础薄一点的同学。第二种是前后端分离Vue 打包之后放进 SpringBoot 的 static 目录。热词里有人搜“vue打包放进springboot中”说明这条路也有不少人走。Vue 做交互体验确实好页面跳转和数据展示更流畅但你需要额外处理跨域、接口鉴权、构建部署这些环节。我的建议是如果时间充裕且对 Vue 有一定基础用前后端分离能加分如果目标是先把系统功能做完整、少踩坑Thymeleaf 足够。下面我按前后端分离的方案来讲因为这部分涉及的知识点更全面试或者答辩的时候也能多聊两句。提示不管你选哪种前端方案后端接口的设计都要尽量 RESTful 化这样哪怕最后前端临时要改后端也不用重写。1.3 角色权限与核心业务流程梳理这个系统的角色权限设计我建议划分成三种管理员、教师、学生。管理员管理全校基础数据教师负责测评任务和档案查看学生只能做测评和看自己的报告。权限控制的实现方案有两种层次。简单做法是用拦截器或者 Spring AOP 校验登录状态和角色编码适合表单登录的传统模式。规范做法是用 Spring Security 或者 Sa-Token 这类安全框架支持注解鉴权代码更优雅。毕业设计阶段如果对安全框架不够熟用拦截器完全够用但你要在论文里写清楚设计的思路。业务主流程可以这样概括管理员维护班级和学生信息导入量表题库。教师创建测评任务选择量表、指定参与班级、设定开始和结束时间。学生在有效期内登录系统完成测评。系统根据量表计分规则计算出各因子分和总分自动写入心理档案。如果得分超过预警阈值系统自动生成预警记录并通知教师。教师在待办列表查看预警信息进行约谈干预并记录处理结果。这个流程里最关键的业务点是“测评任务”和“心理档案”之间的关系。一次测评产生一条测评记录多次测评记录汇聚成一份心理档案档案展示的是学生心理状态的历次变化轨迹而不只是某一次的分数。1.4 功能模块清单与工作量分配按照上面的流程系统可以拆成下面几个模块登录注册学生账号由管理员批量导入教师账号由管理员创建注册入口一般不开给学生。学生管理班级信息、学生基本信息、账号状态的维护支持 Excel 导入导出。量表题库管理维护量表名称、题目内容、选项分值、因子归属、计分规则。测评任务管理创建任务、分配班级、控制时间、查看完成进度。在线测评学生答题界面、自动保存、交卷确认。测评报告计算总分和因子分用 ECharts 展示表格、雷达图、趋势图。心理档案管理按学生维度汇总测评历史形成档案卡片。预警管理设置因子分阈值产生预警记录跟踪处理状态。系统管理用户管理、角色权限、操作日志。这些模块全部完成再配合论文里的需求分析、数据库设计、系统测试几章工作量是相当饱满的。答辩的时候按模块演示每讲一个模块都能对应到论文里的一节逻辑也容易说清楚。2. 数据库设计与核心表结构详解2.1 从业务流程反推数据库表先画流程再建表数据库设计最忌讳上来就建表。拿到题目先画业务流程图把实体和关系找出来再设计表结构这样不会漏表字段设计也有依据。这个系统里主要的实体包括用户、学生、班级、量表、题目、测评任务、任务班级关联、测评记录、作答明细、预警记录。实体关系大致是这样一个班级包含多个学生一个量表包含多道题目一次测评任务关联多个班级一个学生参加一次任务产生一条测评记录一条测评记录包含多道题目的作答明细。确定实体关系后表结构的设计就会很自然。下面我给出核心表的字段设计和建表SQL这套结构我实测过多次覆盖功能完整也方便扩展。2.2 核心表结构设计说明先看用户表。用户表存登录账号信息包含用户ID、用户名、密码、角色、状态等字段。密码我建议用 BCrypt 加密存储这是 Spring Security 里自带的支持不要明文存密码。学生信息表单独建存学号、姓名、性别、年级、班级ID、出生日期、手机号等。为什么要单独建而不是全塞进用户表因为学生信息是业务数据用户表是账号数据二者关注点不同。后续导入导出学生名单操作的都是学生信息表登录认证的时候只查用户表。量表表和题目表是测评系统的核心。量表表存量表名称、类型、题目数量、计分方式、预警阈值说明等题目表存题目内容、所属量表、选项类型、选项分值、所属因子。因子的概念很重要SCL-90 这种量表把题目分到九个因子下比如躯体化、强迫症状、人际关系敏感等每个因子包含若干道题计分时要按因子分别汇总。测评任务表和任务班级关联表负责测评的调度。任务表记录任务名称、量表ID、开始时间、结束时间、创建人、状态关联表记录一个任务对应了哪些班级这样同一个任务可以被多个班级同时参加。测评记录表和作答明细表记录学生的答题过程。测评记录表存学生ID、任务ID、量表ID、开始时间、提交时间、总分、总均分、阳性项目数、状态作答明细表存每道题的答案和分值属于测评记录表的下级明细。预警记录表是业务闭环的关键。触发预警时系统在这里插入一条记录包含学生ID、测评记录ID、预警类型、预警分数、处理状态、处理人、处理内容。2.3 建表SQL与字段设计要点下面是核心表的建表SQL我按实际项目经验给出一个可直接参考的版本。-- 用户表 CREATE TABLE t_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录用户名, password VARCHAR(100) NOT NULL COMMENT BCrypt加密密码, real_name VARCHAR(20) NOT NULL COMMENT 真实姓名, role VARCHAR(20) NOT NULL COMMENT 角色ADMIN/TEACHER/STUDENT, status TINYINT DEFAULT 1 COMMENT 状态 1启用 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT 用户表; -- 班级表 CREATE TABLE t_class ( id BIGINT PRIMARY KEY AUTO_INCREMENT, class_name VARCHAR(50) NOT NULL COMMENT 班级名称如高一(1)班, grade VARCHAR(20) NOT NULL COMMENT 年级, head_teacher VARCHAR(20) COMMENT 班主任姓名 ) COMMENT 班级表; -- 学生信息表 CREATE TABLE t_student ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(20) NOT NULL COMMENT 姓名, gender TINYINT COMMENT 性别 1男 2女, class_id BIGINT NOT NULL COMMENT 班级ID关联t_class, birth_date DATE, phone VARCHAR(20), status TINYINT DEFAULT 1, user_id BIGINT COMMENT 关联的登录用户ID ) COMMENT 学生信息表; -- 量表信息表 CREATE TABLE t_scale ( id BIGINT PRIMARY KEY AUTO_INCREMENT, scale_name VARCHAR(100) NOT NULL COMMENT 量表名称, scale_type VARCHAR(50) COMMENT 量表类型如SCL-90/MHT/SDS, question_count INT COMMENT 题目数量, scoring_method VARCHAR(20) COMMENT 计分方式如FACTOR按因子计分, description VARCHAR(500), status TINYINT DEFAULT 1 ) COMMENT 量表信息表; -- 题目表 CREATE TABLE t_question ( id BIGINT PRIMARY KEY AUTO_INCREMENT, scale_id BIGINT NOT NULL COMMENT 所属量表ID, question_content VARCHAR(500) NOT NULL COMMENT 题目内容, option_type TINYINT DEFAULT 1 COMMENT 选项类型 1五级评分, factor_code VARCHAR(50) COMMENT 所属因子编码如F1, sort_order INT COMMENT 题目序号 ) COMMENT 题目表; -- 测评任务表 CREATE TABLE t_assessment_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_name VARCHAR(100) NOT NULL, scale_id BIGINT NOT NULL COMMENT 使用的量表ID, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, create_by BIGINT COMMENT 创建人ID, status TINYINT DEFAULT 0 COMMENT 0未开始 1进行中 2已结束, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT 测评任务表; -- 测评记录表 CREATE TABLE t_assessment_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT 学生ID, task_id BIGINT NOT NULL COMMENT 任务ID, scale_id BIGINT NOT NULL, total_score DECIMAL(6,2) COMMENT 总分, average_score DECIMAL(4,2) COMMENT 总均分, positive_count INT COMMENT 阳性项目数, status TINYINT DEFAULT 0 COMMENT 0未提交 1已提交, start_time DATETIME, submit_time DATETIME, UNIQUE KEY uk_student_task (student_id, task_id) ) COMMENT 测评记录表; -- 作答明细表 CREATE TABLE t_answer_detail ( id BIGINT PRIMARY KEY AUTO_INCREMENT, record_id BIGINT NOT NULL COMMENT 测评记录ID, question_id BIGINT NOT NULL COMMENT 题目ID, answer_value INT COMMENT 选项值, factor_code VARCHAR(50) COMMENT 因子编码冗余方便统计 ) COMMENT 作答明细表; -- 预警记录表 CREATE TABLE t_warning_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, record_id BIGINT NOT NULL COMMENT 测评记录ID, warning_type VARCHAR(50) COMMENT 预警类型如F1因子分超标, warning_score DECIMAL(6,2) COMMENT 预警分数, suggestion VARCHAR(500) COMMENT 系统建议, handle_status TINYINT DEFAULT 0 COMMENT 0待处理 1已处理, handle_content VARCHAR(500), handle_by BIGINT COMMENT 处理人ID, handle_time DATETIME ) COMMENT 预警记录表;字段设计上有几个容易踩的坑我提醒一下。时间字段要区分创建时间、更新时间、业务时间不要混着用。比如测评记录的 start_time 和 submit_time 都有业务含义你不能用 create_time 替代。状态字段建议用 tinyint不要用 varchar 存一堆语义不清的字符串。因子编码字段要在作答明细表里冗余一份否则做因子统计的时候要反复关联题目表SQL 写起来很痛苦查询性能也受影响。成绩相关的字段建议用 decimal不要用 float 或 double。计分过程中涉及平均值、均分这类小数float 的精度问题在特定场景下会出幺蛾子decimal 更可控。3. 核心功能实现测评计分、档案管理与预警机制3.1 量表计分引擎设计从原始分值到因子分计分引擎是整个系统最有技术含量的部分。我说的“引擎”不是简单算一个总分而是要支撑不同量表的计分规则。学生在页面上一道题一道题作答最终保存在 t_answer_detail分数需要按规则聚合。以 SCL-90 为例它包含90道题目每道题1到5分得分越高表示症状越明显。计分包括这几个指标总分是90道题得分之和总均分是总分除以90阳性项目数是指得分大于等于2的题目数量。同时题目按因子归属分成九类每个因子得分等于该因子下所有题目得分之和除以该因子题目数。这个逻辑写起来不复杂但不要把它散落在 Controller 里。我建议单独设计一个 ScoreCalculator 接口不同量表实现不同的计分策略用简单工厂模式去获取计算器。这样做的好处是以后往系统里加新量表只要实现接口不影响已有代码。核心计分逻辑可以这样组织public class Scl90ScoreCalculator implements ScoreCalculator { private static final int POSITIVE_THRESHOLD 2; // 阳性判定阈值 Override public ScoreResult calculate(ListAnswerDetail answerList) { // 按因子分组汇总得分和题目数 MapString, FactorScore factorMap new HashMap(); int total 0; int positiveCount 0; for (AnswerDetail detail : answerList) { int value detail.getAnswerValue(); total value; if (value POSITIVE_THRESHOLD) { positiveCount; } FactorScore fs factorMap.computeIfAbsent(detail.getFactorCode(), k - new FactorScore(k, 0, 0)); fs.addScore(value); } ScoreResult result new ScoreResult(); result.setTotalScore(total); result.setAverageScore(Math.round(total * 100.0 / answerList.size()) / 100.0); result.setPositiveCount(positiveCount); result.setFactorScores(new ArrayList(factorMap.values())); return result; } }这个计算器的输入是从数据库查出来的作答明细输出是一个结构化的计分结果。整套逻辑不依赖具体业务场景可复用性强也方便写单元测试。答辩的时候能主动提“我为计分逻辑写了单元测试”会是一个不错的加分点。注意量表题目数量多答题页面要支持分页或者滚动加载并定时自动保存作答进度。否则学生答到一半误关页面数据全丢教师端就会收到一堆半成品记录。3.2 测评报告的生成与心理档案的自动更新测评报告和档案之间是什么关系报告是一次测评的结果呈现档案是一个学生历次报告的历史汇总。设计的时候要区分开。测评报告的内容一般包括本次测评总分和均分各因子得分及参考范围雷达图展示因子得分文字性说明和建议。这里的参考范围需要提前配置好比如某因子平均分大于等于2.5就提示“需关注”。心理档案的逻辑是学生每次提交测评后系统自动查询该学生的历史测评记录更新档案卡片。档案卡片展示内容包括学生基本信息、测评次数、最近一次测评日期、历次因子得分趋势、预警历史。这样教师在查看某个学生时一眼就能看到他的整体心理状态变化。批量生成档案数据的时候要注意性能。如果全校几千个学生逐个实时查询测评记录页面会非常慢。实际做法是档案页面默认只加载列表点击某个学生再进入详情页详情页的测评历史按时间倒序分页查询避免一次性取出全部数据。如果还想更快可以把最近一次测评的概要字段冗余到学生档案表里连表查询都省了。3.3 预警机制从分数到要处理的任务预警机制做得好不好直接决定这个系统是不是真的“可用”。中学心理测评的核心目标就是把潜在需要关注的学生筛出来所以评完分之后必须有预警流程。预警规则的实现思路是在计分结果出来之后遍历每个因子分判断是否超过预设的预警阈值。比如因子均分大于等于2.5或者总分超过160分系统就认为该学生需要关注。满足任意规则就在 t_warning_record 插入一条预警记录状态为待处理。预警记录还要有“处理闭环”。教师看到待处理列表后可以点击处理填写约谈结果、处理措施状态更新为已处理。这个闭环很重要因为学校心理健康工作的要求是“有筛查、有干预、有跟踪”系统如果不能记录干预结果整个业务的完整性就断掉了。设计预警的时候可以加一个“预警等级”字段分为一般关注、重点预警两级。预警等级不是拍脑袋定的要由规则引擎计算得出比如超过第一档阈值是一般关注超过第二档阈值是重点预警。这个细节写到论文里能体现出你对业务的理解深度。public WarningRecord buildWarningRecord(Student student, ScoreResult score) { WarningRecord warning new WarningRecord(); ListFactorScore overFactors score.getFactorScores().stream() .filter(f - f.getAverage() WARNING_LEVEL1) .collect(Collectors.toList()); if (!overFactors.isEmpty()) { warning.setStudentId(student.getId()); warning.setWarningType(buildWarningType(overFactors)); warning.setWarningScore(score.getTotalScore()); warning.setSuggestion(buildSuggestion(overFactors)); warning.setHandleStatus(0); // 如果存在超过更高级别阈值的因子标记为重点预警 boolean serious overFactors.stream() .anyMatch(f - f.getAverage() WARNING_LEVEL2); warning.setWarningLevel(serious ? 2 : 1); return warning; } return null; }3.4 数据可视化用 ECharts 让测评结果会说话心理测评系统如果只用表格展示分数体验会非常枯燥。加入 ECharts 之后整个系统的完成度马上提高一档。使用最多的图表是雷达图用来展示九个因子的得分。雷达图的指标是各因子名称数值是各因子的均分这样的图形能直观看出学生哪个维度偏离正常范围。ECharts 雷达图配置不复杂关键是后端要把数据组装成图表需要的格式。// 返回给前端的雷达图数据结构 public MapString, Object buildRadarData(ScoreResult score) { MapString, Object map new HashMap(); ListString indicators new ArrayList(); ListBigDecimal values new ArrayList(); for (FactorScore fs : score.getFactorScores()) { indicators.add(fs.getFactorName()); values.add(fs.getAverage()); } map.put(indicators, indicators); map.put(values, values); return map; }前端拿到接口返回的数据直接用 ECharts 渲染option { title: { text: 心理测评因子分析 }, radar: { indicator: indicators.map(name ({ name: name, max: 5 })), radius: 65% }, series: [{ type: radar, data: [{ value: values, name: 因子得分 }], areaStyle: { opacity: 0.2 } }] };除了雷达图还可以做班级总体的因子平均分柱状图一个学生多次测评结果的总分折线图以及各年级心理预警人数的统计图。这些页面加在一起演示的时候连续打开几个可视化页面答辩老师对系统印象会明显不一样。4. 实操过程从零开始搭建并实现完整闭环4.1 环境准备与项目初始化实操部分我按前后端分离的流程来讲因为这是目前最常见的做法也最容易遇到问题。后端环境需要 JDK 8 或 JDK 17、Maven 3.6 以上、MySQL 5.7 或 8.0、IDEA。这里有个容易踩的坑SpringBoot 3.x 要求 JDK 17 以上如果你本机装的是 JDK 8就要选择 SpringBoot 2.7.x。热词里有人搜“springboot版本太高”大概率就是版本和 JDK 不匹配导致的。创建工程的时候我建议直接用 Spring Initializr。选好项目类型为 Maven语言 Java打包方式 jarJava 版本按本机环境依赖先勾选 Spring Web、MySQL Driver、Lombok。MyBatis-Plus 需要手动引入依赖SpringBoot 3.x 要用 mybatis-plus-spring-boot3-starter这个要注意区分。前端部分如果要用 Vue可以直接用 Vue CLI 或 Vite 创建工程。npm 镜像源建议设置成国内源否则依赖下载慢到你怀疑人生。Vue 工程开发阶段通过代理转发请求到后端解决跨域问题。// vite.config.js 中的代理配置示例 module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };前端工程开发完毕后执行npm run build把生成的 dist 目录里的文件拷贝到后端项目的 src/main/resources/static 下再启动后端就可以通过同一个端口访问前端页面。这就是热词里“vue打包放进springboot中”的实际做法。4.2 后端核心代码结构参考后端项目建议按照 controller、service、mapper、entity、common 这几个包组织。entity 对应数据库表mapper 继承 MyBatis-Plus 的 BaseMapperservice 写业务逻辑controller 提供接口。登录认证我推荐使用 Sa-Token 或者自己写一个简单的 JWT 工具类。用拦截器校验请求头中的 token解析出用户ID和角色。这样好处是不用引入过于复杂的 Spring Security 配置对新手友好而且答辩演示也直观。Component public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录接口 String path request.getRequestURI(); if (path.startsWith(/api/auth)) { return true; } String token request.getHeader(Authorization); if (token ! null JwtUtil.verify(token)) { request.setAttribute(userId, JwtUtil.getUserId(token)); request.setAttribute(role, JwtUtil.getRole(token)); return true; } response.setStatus(401); return false; } }控制器层接口设计遵循 RESTful 风格。测评相关的核心接口大致如下POST /api/assessment/start 开始测评创建测评记录POST /api/assessment/submit 提交答案触发计分GET /api/assessment/records 当前学生的测评历史GET /api/report/radar 获取某次测评的雷达图数据GET /api/warning/list 预警列表教师端使用PUT /api/warning/handle 处理预警提交答案的接口是整个系统最关键的接口。学生端把答案数组传过来后端要做几个动作校验任务是否在有效期内逐条保存作答明细调用计分引擎计算分数更新测评记录生成预警记录。这几个动作要放在同一个事务里不然会出现答案存了但分数没算的脏数据。Transactional(rollbackFor Exception.class) public Long submitAnswer(SubmitRequest request) { AssessmentRecord record getRecord(request.getRecordId()); // 1. 保存作答明细 insertAnswerDetails(request); // 2. 调用计分引擎 ScoreResult score scoreCalculator.calculate(detailList); // 3. 更新测评记录 updateRecordScore(record, score); // 4. 生成预警 WarningRecord warning buildWarningRecord(record, score); if (warning ! null) { warningMapper.insert(warning); } return record.getId(); }4.3 页面交互流程从测评任务到档案查看页面设计不用追求花哨但要保证业务链路顺畅。我按重要程度说一下页面结构和操作路径。学生端首页展示“待完成测评”列表。学生点击某个测评任务进入答题页面。答题页面我建议采用“分块作答”的方式比如每页显示10道题底部有进度条和上一题下一题的按钮。这样做的原因是题目太长一次性加载出来既慢又容易让答题者疲劳。教师端核心页面是测评管理、预警处理、学生档案。测评管理页面展示已创建的测评任务和完成进度进度可以用“已提交人数/应参加人数”来表示这个功能需要一条统计 SQL 分组查询不算复杂但很实用。学生档案页面是教师端最常用的页面。教师搜索学生姓名或学号进入详情页从上到下依次展示学生基础信息、历次测评总览、因子趋势图、预警历史。这个页面集中展示了系统的数据关联能力答辩演示时优先讲它。管理员端主要负责基础数据维护可以做成一个包含多个 Tab 的后台页面分别管理班级、学生、量表、题库。学生导入功能建议用 EasyExcel 或者 POI 实现 Excel 模板的解析这里可以单独作为论文里“系统实现”的一个亮点。4.4 打包部署与答辩演示准备部署环节有一个非常实用的方案适合毕业设计展示。在后端项目的 application.yml 里配置好 MySQL 地址、端口等参数然后用 Maven 打包出可运行的 jar 包。mvn clean package -DskipTests打包完成后把 dist 前端文件和 resources/static 合并或者将前端拷贝进 jar就可以直接运行java -jar mental-health-system.jar个人笔记本上用这个方式演示足够。如果答辩现场网络不稳定还可以把 MySQL 数据库导出成 SQL 文件在本地恢复保证演示环境不依赖外部网络。数据库初始化建议准备好数据库脚本包括建库、建表、插入基础数据。基础数据至少要有2个管理员账号、若干教师账号、几个班级、几十个学生账号、一套完整的90道量表题目以及几条现成的测评记录和预警记录。这样演示的时候打开系统就有内容可看不用现场造数据。很多同学这一步没做答辩时系统里空空荡荡体验就很差。注意准备一份“演示脚本”很重要。把演示路径写下来比如先登录管理员导入班级再切换教师发布任务再切换学生完成测评最后回到教师端查看雷达图和预警每一步大概点击什么位置。答辩前自己按脚本演练三五遍现场就不容易卡壳。5. 常见问题与排查技巧实录5.1 启动阶段常见问题项目启动报错是出现频率最高的问题。第一个常见问题是端口被占用。SpringBoot 默认端口是8080如果本机有别的程序占了启动会报Port already in use。排查方法很简单改 application.yml 里的 server.port或者关掉占用进程。演示前一定要确认端口不被占用。第二个问题是 MySQL 连接不上。常见原因是数据库版本与服务配置不一致或者说 MySQL 驱动版本和数据库版本不匹配。注意 MySQL 8.0 的驱动是com.mysql.cj.jdbc.Driver连接 URL 要加上时区参数serverTimezoneAsia/Shanghai否则启动时会报时区错误。第三个问题是 MyBatis-Plus 版本和 SpringBoot 版本不匹配。SpringBoot 3.x 的项目引入了 MyBatis-Plus 3.5.3 以前的版本会出现启动报错、Mapper 扫描不到之类的问题。解决办法是使用mybatis-plus-spring-boot3-starter并且版本选新一些的。如果项目用的是 SpringBoot 2.x则用mybatis-plus-boot-starter。5.2 测评和计分环节的常见问题测评环节最容易遇到的坑是数据状态不一致。比如学生答题过程中关闭了页面测评记录的状态还是“未提交”但作答明细已经存了一部分。重新进入测评页面时要能判断这个记录关联的明细数据是否存在存在就继续答题而不是重新开始。实现方式是提交答案前先查询 t_answer_detail 是否已有该 recordId 的记录。计分环节容易出问题的点是因子编码。题目表里的 factor_code 字段如果录入不一致比如同一量表下有的写“F1”有的写“f1”或者前两题是“躯体化”后两题是“躯体化因子”计分时因子分组就会出错。解决思路是在录入题库的时候对因子名称做下拉选择用统一编码不开放手工输入同时在测试阶段对每个量表跑一遍全量作答数据核对因子总数是否和标准量表一致。还有一个跟四舍五入相关的问题。总均分保留两位小数如果用 float 计算后再格式化部分数值会有精度问题。建议所有分数计算用 BigDecimal保留位数的取舍规则也要统一论文里写清楚用的是“四舍五入”不然答辩时被问到小数规则会回答得含含糊糊。5.3 权限与数据安全注意事项心理健康数据属于敏感信息这是一定要注意的点。系统里学生测评分数、预警记录这些内容不能让普通学生互相查看。我建议做两个层面的控制第一层是接口权限。教师端和学生的接口严格分离学生端接口只允许访问自己的数据查询条件强制带上登录用户的ID不要写一个查询所有测评记录的接口让前端自己过滤。我在实际项目里见过有同学把所有测评数据一股脑返回给前端然后前端根据当前用户过滤这是非常危险的做法稍微懂点网络知识的人改一下请求参数就能看到别人的数据。第二层是页面权限。前端根据角色渲染菜单没有权限的入口直接不展示但前端隐藏只是用户体验问题真正的安全必须由后端兜底。论文里可以专门写一小节“数据安全设计”把这两层控制方式讲清楚答辩老师通常都会认可。密码加密方面建议用 BCrypt。手动写一个 MD5 加盐的工具类虽然也能用但没有 BCrypt 成熟容易被问出破绽。Spring Security 的BCryptPasswordEncoder可以直接拿出来用不需要完整引入 Spring Security 全家桶。5.4 性能优化与数据量扩展测评系统正常使用场景下并发量不会太高但有两个点需要优化不然数据量上升后会明显变慢。第一个是列表查询的 N1 问题。比如查询测评记录列表时如果先查出所有记录再循环查询每个学生姓名会产生大量 SQL。解决方法是关联查询或者用 MyBatis-Plus 的selectBatchIds批量查询学生信息然后内存中组装。这个问题在答辩时经常被问到提前解决掉会显得你考虑过性能问题。第二个是统计报表的查询优化。比如要展示各班级预警人数柱状图用 group by 加左关联就能实现。注意给外键字段加上索引t_answer_detail.record_id、t_assessment_record.student_id、t_warning_record.student_id 这几个字段都要建索引。MySQL 在数据量小的时候有没有索引看不出差别但演示时如果造了上千条数据加中间件日志观察 SQL 执行计划有索引和没索引差异就出来了。另外自动保存答案的接口会被高频调用建议前端做防抖每30秒或每题作答后延迟几秒再保存减轻后端压力。也可以引入 Redis 把答题草稿存到缓存里最终提交时才真正写入 MySQL。这个方案在论文里写出来会比较加分但要注意 Redis 不是必须的如果环境安装不了 Redis直接用 MySQL 也能正常运行不要因为非核心组件卡住主流程。说起来我见过不少同学做这个题目到最后功能都做完了但演示时只演示了登录、增删改查完全没有把“测评闭环”讲出来。其实这个题目最大的亮点在于那条业务链发布测评任务学生在线答题系统自动计分异常数据进预警教师处理干预历次数据沉淀成档案。你只要把这条链在论文里、在演示里讲清楚整个系统的价值就立住了。我个人的习惯是在测试阶段用一套完整的模拟数据走两三遍全流程从管理员发布任务开始一路跑到教师查看预警过程中把所有问题都记录下来。这样既能把代码调稳也能逼着自己把系统里面每个功能的细节串起来答辩的时候不至于被细节问题问住。这算是做这个题目最有价值的一部分收获。