☰
基于SpringBoot的中学生心理健康管理系统设计与实现
2026/10/6 19:34:23 网站建设 项目流程

很多计算机专业的朋友在做毕业设计选题时都会纠结一个问题:既要考虑题目本身的工作量能不能撑起一篇论文,又要考虑技术栈是不是有含金量、答辩的时候好不好演示。今天我想讲的这个题目,我在带项目的时候见过很多次,也被问过很多次——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(List<AnswerDetail> answerList) { // 按因子分组,汇总得分和题目数 Map<String, 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(); List<FactorScore> 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 Map<String, Object> buildRadarData(ScoreResult score) { Map<String, Object> map = new HashMap<>(); List<String> indicators = new ArrayList<>(); List<BigDecimal> 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,打包方式 jar,Java 版本按本机环境,依赖先勾选 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 的 BaseMapper;service 写业务逻辑;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 要加上时区参数serverTimezone=Asia/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 性能优化与数据量扩展

测评系统正常使用场景下并发量不会太高,但有两个点需要优化,不然数据量上升后会明显变慢。

第一个是列表查询的 N+1 问题。比如查询测评记录列表时,如果先查出所有记录,再循环查询每个学生姓名,会产生大量 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 也能正常运行,不要因为非核心组件卡住主流程。

说起来,我见过不少同学做这个题目到最后,功能都做完了,但演示时只演示了登录、增删改查,完全没有把“测评闭环”讲出来。其实这个题目最大的亮点在于那条业务链:发布测评任务,学生在线答题,系统自动计分,异常数据进预警,教师处理干预,历次数据沉淀成档案。你只要把这条链在论文里、在演示里讲清楚,整个系统的价值就立住了。我个人的习惯是在测试阶段用一套完整的模拟数据走两三遍全流程,从管理员发布任务开始,一路跑到教师查看预警,过程中把所有问题都记录下来。这样既能把代码调稳,也能逼着自己把系统里面每个功能的细节串起来,答辩的时候不至于被细节问题问住。这算是做这个题目最有价值的一部分收获。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询