公司动态
基于Spring Boot+Vue的学生心理咨询评估系统设计与实现
简介本资源是一套面向高校计算机专业毕业生与全栈开发初学者的实战型心理咨询系统源码聚焦学生心理健康服务场景解决校园心理评估数字化、咨询流程线上化与师生协同管理难题。压缩包共338个文件含70个Java后端业务逻辑与控制器代码、33个Vue组件实现响应式前端界面如评估量表填写页、结果分析看板、161个SVG图标资源支撑UI细节辅以SQL建表脚本、YML配置、BAT启动脚本及PPT开题文档等完整交付材料总大小19.99MB。已有104人学习下载资源结构清晰包含可直接运行的前后端分离工程SpringBootVue提供SAS/SDS/EPQ等权威心理量表集成方案、JWT权限控制、加密传输与咨询记录跟踪模块附带.bak备份文件便于版本比对适合用于毕设开发、课程设计或心理健康类应用二次开发。 记得去年有个学弟抱着选题表来找我说自己打算做“学生心理咨询评估系统”当毕业设计Spring Boot加Vue问我要从哪下手。我反问他你想做的是一个“能填问卷的网站”还是一个“真能评估心理状态的系统”他愣了一下说感觉差不多。其实差太多了。那一次交流之后我就发现很多同学把这类题目的难点想偏了——重点根本不在登录、增删改查这些常规功能而是藏在测评背后那套评估逻辑里。这篇博文就把这个项目的完整拆解思路写出来。从需求边界、技术选型、数据库设计到评估引擎实现、前端交互、安全和部署再到我实际开发中踩过的坑全部分享给你。适合正在做毕业设计、打算做全栈项目练手或想了解“测评类系统到底怎么设计”的开发者。技术栈就是标题里那套Spring Boot Vue没有额外重的中间件主打一个能跑、能讲、能答辩。1. 需求拆解心理咨询评估系统不是简单的“增删改查”1.1 三个端口的用例边界先捋清楚系统里有谁在用。我按角色拆成了三个端分别是学生端、咨询师端和管理员端。这是这类项目第一层最容易混的地方——很多人上来就设计一个统一的用户表然后塞一个“角色”字段后面做权限控制的时候才发现到处是补丁。实际项目里我推荐从用例反推表结构先把每个角色要做的事列清楚。学生端核心用例注册、登录、修改个人资料参与心理测评填写量表题目查看自己的测评记录和评估报告查看咨询师列表发起咨询预约咨询师端核心用例查看分配到自己的学生测评数据查看学生测评报告的详细维度得分对高风险学生进行标记、添加干预记录管理自己的咨询排期、确认或拒绝预约管理员端核心用例管理学生和咨询师账号维护量表库新增、启用或停用量表查看全校测评完成率、风险分布统计等汇总数据注意一个细节咨询师查看学生报告这个动作涉及隐私和授权。系统里任何查看行为都要留日志至少要记录“谁在什么时间查看了哪个学生的报告”。我在数据库里放了单独一张audit_log表这个在答辩时是加分项。1.2 核心业务闭环从测评到干预学生心理咨询评估系统的本质是“测评—评估—干预”三个环节的闭环创建测评任务管理员创建一次全校或者针对某个班级/年级的测评任务绑定一个量表设定开始和截止时间。学生作答学生在有效时间内进入问卷页完成题目提交答案。自动评估后端按量表规则计算维度得分匹配风险等级自动生成评估报告。咨询师干预高风险学生出现在咨询师工作台咨询师可以主动联系并创建干预记录。跟踪复评学生再次参加测评后报告里要体现结果变化趋势。大多数毕业设计只做了前两步后面三部分基本留白。但如果想让项目有深度建议至少把自动评估和风险标记做完整这恰恰是这个系统的价值核心。1.3 非功能性需求别忽略并发和时间边界有些同学会问我非功能性需求要不要写进毕业设计。我的答案是不仅要写还要在答辩时主动讲出来证明你考虑过真实场景。举个例子学校举行一次心理健康普查通常集中在某几天内完成几千名学生同时或分批登录系统。虽然不像电商秒杀那样流量恐怖但瞬间打到几百个并发请求还是有压力的。评估系统的接口大多是读多写少所以我在后端做了本地缓存、数据库索引优化同时给提交测评接口做了简单的限流。这些内容在文档里写清楚答辩时能有理有据。另外一个容易忽略的是“测评时效性”。一次测评任务是有截止时间的提交答案时后端必须校验任务是否在有效期内。很多人做的时候只在页面层控制“显示问卷”和“隐藏问卷”接口层完全不校验技术上这就留了一个大洞。正确做法是后端在提交答案时重新校验时间窗口同时校验该学生是否已经被分配到这次测评任务。2. 技术选型与项目骨架为什么是Spring Boot Vue的经典组合2.1 后端技术选型理由选技术栈不能只看哪个火要看它适不适合当前项目和团队水平。Spring Boot 在校园项目里几乎是最稳妥的选择原因很实在内置Tomcat打一个jar包就能跑部署成本低起步依赖做得非常完善引入一个starter就自动把配置装配好生态成熟遇到问题随便一搜就是解决方案和JPA、MyBatis等持久层框架都整合得很顺版本上现在有个选择Spring Boot 2.7.x 还是 3.x。如果你用JDK 8直接选2.7.x这是目前兼容性最稳的版本。如果导师要求新并且你的JDK是17及以上可以上3.x。我的建议是别在版本上追求最新毕业设计时间宝贵稳定压倒一切。很多同学抱怨“springboot版本太高”导致各种兼容问题我实测下来基本都是没有认真看官方Upgrade Notes。ORM框架我选了MyBatis-Plus。理由很简单单表操作几乎不用写SQL内置分页插件代码生成器能直接生成实体、Mapper和Service的样板代码。心理测评系统大部分查询都是单表为主、联表为辅MyBatis-Plus是效率最高的选择。如果你偏好JPA也没有问题但MyBatis-Plus在答辩讲解时更容易从SQL层面展开符合国内数据访问习惯。2.2 前端技术选型理由前端这部分Vue在我这里仍然是首选。它的上手曲线比React平滑模板语法直观中文资料海量任何一个报错几乎都能搜到现成答案。具体到项目内部用Vue 2还是Vue 3如果你是最近才开始做直接用Vue 3 Element Plus。如果找到的参考代码是Vue 2 Element UI用Vue 2也不丢人关键是项目要能跑起来。状态管理用了Pinia比Vuex轻量TypeScript支持也好。路由Vue Router 4注意mode要选history还是hash这个直接关系到部署后404的问题后面踩坑章会细讲。HTTP库Axios主要用它做请求拦截和响应拦截统一处理JWT令牌和401状态。2.3 项目目录结构设计后端包结构我建议这样规划清晰且好讲com.example.psyassessment ├── common // 通用响应体、异常处理、工具类 ├── config // 配置类比如MyBatis-Plus分页、跨域、JWT拦截器 ├── controller // 控制层 ├── service // 接口层 实现层 ├── mapper // MyBatis-Plus持久层接口 ├── entity // 数据库实体 ├── dto // 前端交互数据传输对象 └── enums // 枚举比如风险等级、测评状态前端用Vue CLI或Vite创建项目后目录按功能模块分src ├── api // 按模块封装的接口请求 ├── assets // 静态资源 ├── components // 公共组件 ├── router // 路由配置 ├── store // Pinia状态 ├── views // 页面级组件 │ ├── student │ ├── counselor │ └── admin └── utils // 工具函数包括axios实例封装这个结构本身不神奇它最大的作用是让答辩时你讲述的逻辑线很清楚先指目录再说职责再展开核心代码。3. 数据库建模一张“测评记录表”藏着的设计功底3.1 核心表结构与关系数据库是评估系统的地基。我建议把表设计成如下一组按模块划分用户相关sys_user主账号表存放账号、密码、手机号、角色等student_profile学生扩展信息如学号、班级、年级、学院counselor_profile咨询师扩展信息如咨询方向、资质描述、排期状态量表相关scale量表基本信息名称、简介、维度数量、适用人群、状态scale_dimension量表维度定义比如SCL-90里包含躯体化、强迫症状、人际关系敏感等维度scale_question量表题目每道题关联一个维度、题型、分数选项测评相关assessment_task测评任务管理员创建绑定量表和人群范围assessment_record测评记录一个学生参加一次测评产生一条记录assessment_answer测评作答明细每道题的选择结果assessment_report评估报告存储计算后的维度得分和风险等级干预相关appointment预约记录intervention_record干预记录audit_log操作日志3.2 几张关键表的DDL设计思路先看量表题目表它的设计决定了问卷能不能做成动态渲染CREATE TABLE scale_question ( id bigint PRIMARY KEY AUTO_INCREMENT, scale_id bigint NOT NULL COMMENT 所属量表ID, dimension_id bigint NOT NULL COMMENT 所属维度ID, question_text varchar(500) NOT NULL COMMENT 题干, question_type tinyint NOT NULL DEFAULT 1 COMMENT 题型1单选 2多选 3评分, sort_order int NOT NULL DEFAULT 0 COMMENT 排序, option_json varchar(1000) DEFAULT NULL COMMENT 选项定义JSON数组, is_reverse tinyint NOT NULL DEFAULT 0 COMMENT 是否反向计分 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这个表里有几个字段很容易被忽略。一个是option_json它把每个题目的选项直接存成JSON字符串如[{label:没有,score:1},{label:轻度,score:2}]这样新增量表时不需要建题选项表极大简化了实现。另一个是is_reverse很多量表里会有反向计分题比如“我对未来充满希望”这类正向描述的题目反向题需要把得分翻过来再参与计算这个字段就是做这件事的。再看测评记录表它是整个系统的“事实表”CREATE TABLE assessment_record ( id bigint PRIMARY KEY AUTO_INCREMENT, task_id bigint NOT NULL COMMENT 测评任务ID, user_id bigint NOT NULL COMMENT 学生用户ID, scale_id bigint NOT NULL COMMENT 量表ID, status tinyint NOT NULL DEFAULT 0 COMMENT 0未开始 1进行中 2已完成 3已过期, start_time datetime DEFAULT NULL COMMENT 实际开始时间, submit_time datetime DEFAULT NULL COMMENT 提交时间, risk_level tinyint DEFAULT NULL COMMENT 风险等级 0低 1中 2高, total_score decimal(10,2) DEFAULT NULL COMMENT 总分或均分, create_time datetime DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表我会建议加上task_id和user_id的联合唯一索引。因为一个学生在一个测评任务里只能有一条记录数据库层面保证不会重复提交。状态字段从0到3的流转配合时间字段就是你答辩时讲“业务状态机”的素材。还有一个设计细节答案表里既要存题目ID也要冗余存选项的score值而不是提交的时候只存选项ID。这样做的好处是评估计算时不需要再回头关联题目和选项表直接SUM(score)就能出结果性能好逻辑也简单。缺点是如果量表规则改动历史记录和答案对不上——不过对毕业设计来说这个风险完全可以接受。3.3 量表维度和报告表的设计技巧量表维度表我单独拆出来了CREATE TABLE scale_dimension ( id bigint PRIMARY KEY AUTO_INCREMENT, scale_id bigint NOT NULL, dimension_name varchar(100) NOT NULL COMMENT 维度名称, dimension_code varchar(50) NOT NULL COMMENT 维度编码如DEPRESSION, sort_order int DEFAULT 0, threshold_low decimal(10,2) DEFAULT NULL COMMENT 低风险上限或触发值, threshold_high decimal(10,2) DEFAULT NULL COMMENT 高风险触发值 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;如果每个维度都要算“得分率”或者“严重程度”最好在维度表里存一个“计分规则”比如维度满分是多少分。这里的threshold_low和threshold_high就是维度级风险阈值计算时会和实际得分比较。报告表我倾向于存“计算后的结果快照”也就是维度得分、总分、风险等级、评估建议这些字段冗余存储。不要每次打开报告时现场算一遍一来慢二来一旦算错或者规则变化历史报告就全变了。快照思路在信息系统里是很常见的做法。4. 评估引擎实现让系统“懂”心理学的核心逻辑4.1 量表计分与维度聚合评估引擎是整个项目的灵魂也是答辩时最能体现技术深度的地方。它的核心逻辑并不复杂说白了是三步取出该学生本次测评的所有作答答案按题目关联的维度分组每个维度内累加得分根据维度得分匹配风险等级生成报告文本以抑郁自评量表为例假设所有题目都是1-4级评分维度是“抑郁”那么代码核心这样写public AssessmentReport generateReport(Long recordId) { // 1. 查询作答明细 ListAssessmentAnswer answers assessmentAnswerMapper.selectList( new LambdaQueryWrapperAssessmentAnswer() .eq(AssessmentAnswer::getRecordId, recordId)); Long scaleId ...; // 从记录中取得量表ID // 2. 查询量表的所有维度 ListScaleDimension dimensions scaleDimensionMapper.selectList( new LambdaQueryWrapperScaleDimension() .eq(ScaleDimension::getScaleId, scaleId)); // 3. 初始化维度得分映射 MapLong, Integer dimensionScoreMap new HashMap(); MapLong, Integer dimensionFullScoreMap new HashMap(); // 4. 分组聚合得分 for (AssessmentAnswer answer : answers) { Long dimensionId answer.getDimensionId(); int score answer.getScore(); if (answer.getIsReverse() 1) { // 反向计分4档量表假设为1-4分则 5 - score 翻转 score 5 - score; } dimensionScoreMap.merge(dimensionId, score, Integer::sum); dimensionFullScoreMap.merge(dimensionId, answer.getMaxScore(), Integer::sum); } // 5. 逐个维度判断风险等级并拼装报告 for (ScaleDimension dim : dimensions) { Integer dimScore dimensionScoreMap.getOrDefault(dim.getId(), 0); Integer fullScore dimensionFullScoreMap.getOrDefault(dim.getId(), 0); // 得分率判断 double ratio fullScore 0 ? 0 : (dimScore * 1.0 / fullScore); if (ratio dim.getThresholdHigh()) { // 高风险逻辑 } else if (ratio dim.getThresholdLow()) { // 中风险逻辑 } else { // 低风险逻辑 } } // 6. 汇总总风险等级取所有维度中最高等级 // 7. 写入 report 表并返回 }这个代码里有三个细节值得展开说。第一是反向计分的处理我在实体里冗余了一个is_reverse字段聚合时判断并翻转分数。第二是“维度满分”的概念如果不同维度的题目数量不同拿原始得分直接跨维度比较是没有意义的我的做法是先算得分率维度得分 / 该维度所有题目满分总和再和阈值比较。第三是做dimension_id冗余答案表里直接存了题目所属的维度ID聚合时省去一次关联查询这也是典型的时间换空间取舍可以减少一次表连接。4.2 风险等级判断和报告文本生成维度得分出来了接下来是风险等级。这里我采用的是“最严重决定法”如果任何一个维度达到高风险则整体风险等级即为高风险如果所有维度都低风险则整体为低风险。中间情况取最高的那个级别。这个策略简单、解释成本低也符合心理评估中“关注异常信号”的取向。等级判断之后还要生成一段报告文本。这部分不需要自然语言生成的复杂技术用规则模板拼接即可。比如String advice ; if (riskLevel 2) { advice 你当前部分维度得分偏高建议尽快预约咨询师进行面对面交流同时注意规律作息和情绪觉察。; } else if (riskLevel 1) { advice 你当前处于一般状态部分维度存在轻度波动建议关注自身情绪变化适当进行放松练习。; } else { advice 你目前的心理状态整体稳定请继续保持良好的生活习惯和社交节奏。; }这里有个非常重要的边界系统生成的内容只能叫“评估建议”不能叫“诊断结论”。真正的心理诊断必须由专业人员完成。所以在报告的底部我会固定展示一行免责声明“本报告由系统基于量表得分自动生成结果仅供参考不构成医学诊断或心理治疗建议。”这句话不仅是负责任的表现在毕业设计答辩时也能体现你的职业伦理意识是加分项。4.3 规则可配置把阈值挪到数据库把风险和阈值写在代码里有一个隐患每次评估规则变化都要改代码、重新部署。我采用了数据库配置的方式把阈值字段放到维度表和量表表里管理端提供一个维护页面管理员可以调整。评估引擎每次运行时动态读取这些阈值。这样做的好处不只是“灵活”两个字能概括的。在答辩时你可以明确说这套设计让两个不同量表可以在同一个引擎下运行系统不绑定具体量表新增一个量表只需要在管理端录入题目和配置阈值就能直接支持一次新测评。这是一个“规则引擎”的雏形思想放在毕业设计里已经完全够用。5. 前端问卷与报告交互体验里的关键实现5.1 问卷页面的动态渲染问卷页是学生端使用频率最高的页面它的核心诉求是“一套代码渲染所有不同量表的题目”。前端我用一个动态题目组件来实现template div classquestion-item v-for(question, index) in questions :keyquestion.id div classquestion-title span{{ index 1 }}. /span{{ question.questionText }} /div div classquestion-options el-radio-group v-ifquestion.questionType 1 v-modelanswers[question.id] changehandleAnswerChange(question) el-radio v-foropt in JSON.parse(question.optionJson) :keyopt.label :labelopt.label {{ opt.label }}/el-radio /el-radio-group el-rate v-else-ifquestion.questionType 3 v-modelanswers[question.id] :max5 show-score /el-rate /div /div /template题目的optionJson从后端接口拿到直接解析渲染。这样前后端的数据契约只需要约定题目是单选、多选还是评分选项是一个JSON数组每项带label和score。后续添加新的量表前端一行代码都不用改。有一个交互细节值得注意学生作答途中可能会刷新页面、误关浏览器。我做了两部分处理一个是每答一题实时保存答案到本地状态Pinia同时在离开页面时把进度提交到后端状态置为“进行中”重新进入时恢复之前已选的答案。这个功能虽然多写了一些代码但对测评系统的完整体验至关重要。5.2 Axios封装与JWT拦截器前端所有请求我都走同一个Axios实例在utils/request.js里统一处理import axios from axios import { ElMessage } from element-plus import router from /router import { useUserStore } from /store/user const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器自动携带 token request.interceptors.request.use(config { const userStore useUserStore() const token userStore.token if (token) { config.headers.Authorization Bearer ${token} } return config }) // 响应拦截器统一处理错误 request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res.data }, error { if (error.response error.response.status 401) { ElMessage.warning(登录已过期请重新登录) router.push(/login) } else { ElMessage.error(error.message || 网络异常) } return Promise.reject(error) } ) export default request这一段代码是前端最值得在答辩时展示的实现之一。拦截器把“鉴权”和“错误处理”从每个页面里抽离出来页面代码只需要关心业务数据复杂度被集中管理。5.3 前端跨域与代理配置开发环境跨域是新人最容易卡住的点。我在vite.config.js里配置了开发服务器代理server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, // 后端Controller的RequestMapping里就没有/api // 所以实际请求转发到后端时去掉这个前缀 rewrite: path path.replace(/^\/api/, ) } } }这样前端代码里的/api/auth/login请求会被代理转发到http://localhost:8080/auth/login绕开了跨域限制。生产环境呢我推荐把前端打包后的dist目录直接放到Spring Boot的src/main/resources/static下这样前后端同源连Nginx都省了。这种极简部署方式对毕设演示非常友好。5.4 报告页的雷达图与趋势展示评估报告如果只有一堆文字视觉上就太单薄了。我用ECharts做雷达图展示各维度得分。雷达图是心理评估系统最常见也最适合的图表能一眼看出受测者在哪些维度偏高const chartDom document.getElementById(radarChart) const myChart echarts.init(chartDom) myChart.setOption({ radar: { indicator: dimensions.map(d ({ name: d.dimensionName, max: d.fullScore })) }, series: [{ type: radar, data: [{ value: dimensionScores, name: 本次测评 }] }] })如果学生参加过多次同量表的测评报告里还可以加一条折线图展示总分的变化趋势。这个功能在答辩时很有吸引力因为它告诉评委你考虑的不只是单次评估而是持续关注和复评的闭环。6. 安全、防作弊与答辩亮点这些细节决定项目档次6.1 登录认证与权限控制后端我用JWT做无状态认证。用户登录成功后后端签发一个有效期2小时的token前端把它存在localStorage或Pinia里。JWT的好处是服务器不保存会话状态天然适合前后端分离部署也方便水平扩展。Spring Boot里我用拦截器实现认证逻辑Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (StringUtils.hasText(token) token.startsWith(Bearer )) { token token.substring(7); try { Claims claims JwtUtil.parseToken(token); // 将用户信息放入 request attribute供后续使用 request.setAttribute(userId, claims.get(userId)); request.setAttribute(role, claims.get(role)); return true; } catch (Exception e) { // token 过期或非法 } } response.setStatus(401); return false; } }拦截器还要配合白名单使用。登录、注册、获取量表公开信息这些接口不需要认证但提交答案、查看报告、管理接口必须认证。在注册拦截器时指定excludePathPatterns比在Controller上写一堆注解更集中、更好维护。6.2 防重复提交与防代填测评提交接口要做好幂等控制。后端在生成测评记录时已经通过task_id user_id的唯一索引挡住了重复提交的极端情况。除了这个兜底我的实现里还做了一层乐观锁提交时携带record_id和当前状态只有状态为“进行中”时才能更新为“已完成”。如果状态已经是“已完成”直接返回“请勿重复提交”。防代填也是心理测评系统特有的需求。平台应当保证答卷是学生本人填写我做了两个轻量级方案一是登录令牌有效期控制二是答题过程中记录每道题的时间戳如果整份问卷完成时间过短比如少于量表设计的最短回答时间后端标记该记录为“疑似无效”提醒咨询师注意。这些都是不依赖复杂算法的实用手段。6.3 密码存储与敏感接口设计密码不使用明文存储。我用的BCryptPasswordEncoder这个算法自带盐同一个密码每次生成的哈希都不同安全性远高于简单MD5加盐。前端传密码时我用HTTPS协议保证传输层安全。如果是本地演示环境没有HTTPS至少也要保证密码不打印到日志里。学生测评报告属于敏感数据。查询接口除了JWT鉴权我还做了数据范围校验学生只能查自己的报告咨询师只能查看被分配或系统分配范围内的学生。写一个DataScopeAspect切面在Mapper层自动拼接权限条件这种“数据权限”的设计在面试里也能当亮点讲。7. 实测踩坑记录从开发到部署的坑位清单7.1 Vue history模式刷新404前端用的Vue Router如果不加配置路由是hash模式URL里有#不美观但稳。我改成history模式后页面刷新时就出现了404原因是开发服务器没有“所有未匹配路由都回退到index.html”的配置。Vite开发环境下在配置文件里加一段server: { historyApiFallback: true }生产环境如果用Spring Boot静态资源托管需要在Controller里做转发或者把路由模式改回hash。我最终为了演示省事直接用了history模式加Spring Boot内部静态资源并加了一个ForwardController把非接口路径全部转发到index.html。7.2 LocalDateTime序列化时区问题前后端通过JSON传时间字段。有个常见的坑是后端返回的LocalDateTime在浏览器里显示成2024-05-18T10:30:00这种带T的格式观感差而且如果服务器时区和客户端不一致还可能出现时间偏移。我在Spring Boot配置里统一指定了格式spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8前端再配合一个dayjs库做格式化就没有再出过时间显示的怪问题。7.3 问卷长列表渲染卡顿一份量表几十道题如果每次都走完整组件渲染页面会有明显的打开卡顿。尤其是我第一次写完使用的是大量的el-radio-group和el-rate在低配电脑上打开速度有点慢。解决办法是分页加载每页显示10-15题答完一页点“下一组”进入下一页。这样既减小了页面一次性渲染的DOM数量也天然形成了题目分段体验更接近专业问卷平台。另外一个优化是用v-memo缓存已经渲染的题目项避免状态变化时整个列表重新渲染。7.4 量表版权和免责声明问题真的做一个心理评估系统肯定会用到某种成熟量表。很多经典量表是有版权的不能直接拿来商用或公开发布。毕业设计用于教学演示一般是用“模拟量表数据”实现机制在文档里标注“量表内容仅为演示非真实量表”。另外再一次强调报告页一定要展示免责声明。我在系统里把这句话放在了报告底部固定展示“本评估结果由系统自动生成仅作为自我了解和专业咨询的参考不构成任何医学诊断或治疗建议。如有需要请联系专业心理咨询机构。”这个细节会让你的项目在评委眼里显得成熟、有责任感。7.5 打包与部署的路径坑开发完成之后打包部署有几个路径相关的小坑。前端axios的baseURL如果写死了http://localhost:8080部署到服务器上就会跨域失败。我改成相对路径/api走Nginx或Spring Boot反向代理。Spring Boot打包成jar之后前端静态资源如果放在static目录下记得清理浏览器缓存否则会看到旧资源。还有一个我踩过的坑后端接口的上下文路径。如果server.servlet.context-path设置了/psy那么前端代理目标也要对应调整否则所有接口都会404。这些配置最好在项目早期就固定下来不要做一半再改。写在最后的一点实际体会做了几个类似的项目之后我的感受是学生心理咨询评估系统这个题目覆盖面广、角色明确、业务逻辑有深度特别适合用来展示全栈开发能力。但最关键的还是要把“评估引擎”这个核心想清楚不要在简单的增删改查上打转。多看几篇代码、搭好骨架之后真正写起来其实没有想象中那么漫长。如果你也在做这个题目可以从数据库表设计开始先把记录表、答案表、维度表建好再填充评估引擎最后去打磨前端页面。遇到卡住的地方不要慌这个项目里90%的问题都有人踩过好好搜索一条条解决离一个能过答辩、能讲清楚原理的系统就不远了。本文还有配套的精品资源点击获取