1. 项目背景与核心价值
高校心理咨询系统是当前数字化校园建设中的重要一环。随着大学生心理健康问题日益受到关注,传统线下咨询模式暴露出诸多痛点:预约难、隐私保护不足、咨询师资源分配不均、评估流程繁琐等。我们团队基于SpringBoot和微信小程序开发的这套系统,正是为了解决这些实际问题。
微信小程序作为载体具有天然优势:无需安装、即用即走,符合大学生使用习惯;同时依托微信生态,能实现无缝的用户身份认证。后端选择SpringBoot框架,则是看中了其快速开发、微服务友好的特性,特别适合高校这种需要快速迭代、多系统对接的场景。
心理评估模块是整个系统的核心创新点。传统纸质问卷评估方式效率低下,数据难以统计分析。我们将评估流程数字化,实现:
- 动态题库管理(根据不同评估维度自动组卷)
- 实时数据分析(自动生成可视化报告)
- 智能预警机制(对高风险结果自动触发干预流程)
提示:系统设计中特别注意了《精神卫生法》相关合规要求,所有评估数据匿名化处理,咨询师端仅能看到脱敏后的分析结果。
2. 技术架构设计解析
2.1 整体技术栈选型
前端层:
- 微信小程序(主体)
- TDesign组件库(界面统一规范)
- ECharts(评估数据可视化)
后端层:
- SpringBoot 2.7(基础框架)
- Spring Security(权限控制)
- MyBatis-Plus(数据持久化)
- Redis(会话缓存/问卷缓存)
- RocketMQ(异步消息处理)
数据库:
- MySQL 8.0(主业务数据)
- MongoDB(非结构化评估数据存储)
选型考量:
- 微信小程序比H5有更好的用户体验和API支持
- 放弃Vue+Web方案是为了降低学生使用门槛
- RocketMQ比ActiveMQ更适合高并发评估提交场景
- MongoDB的文档结构完美匹配动态问卷需求
2.2 关键架构决策
双Token认证机制:
java复制// 认证服务核心逻辑
public AuthResult login(LoginDTO dto) {
// 1. 微信code换openid
String openid = wechatService.code2openid(dto.getCode());
// 2. 生成业务token(短时效)
String accessToken = JwtUtil.generate(openid, 2 * 60 * 60);
// 3. 生成刷新token(长时效)
String refreshToken = JwtUtil.generate(openid, 7 * 24 * 60 * 60);
// 4. Redis记录token关系
redisTemplate.opsForValue().set(
"refresh:" + openid,
accessToken,
7, TimeUnit.DAYS);
return new AuthResult(accessToken, refreshToken);
}
评估数据分片设计:
sql复制-- 评估记录主表
CREATE TABLE eval_main (
id BIGINT PRIMARY KEY,
user_id VARCHAR(32) COMMENT '脱敏用户标识',
status TINYINT COMMENT '0-进行中 1-已完成',
created_at DATETIME
) PARTITION BY RANGE (TO_DAYS(created_at)) (
PARTITION p202301 VALUES LESS THAN (TO_DAYS('2023-02-01')),
PARTITION p202302 VALUES LESS THAN (TO_DAYS('2023-03-01'))
);
-- 评估详情文档(MongoDB)
{
"evalId": "123456",
"answers": [
{
"questionId": "Q005",
"score": 4,
"dimension": "depression"
}
],
"analysis": {
"depression": {
"score": 18,
"level": "moderate"
}
}
}
3. 核心功能实现细节
3.1 动态问卷引擎
业务流程图:
- 管理员配置题库(标注问题维度、权重)
- 学生发起评估时:
- 系统根据用户画像(年级、性别等)筛选问题
- 从各维度题库随机抽题(保证评估全面性)
- 生成唯一评估ID并缓存题目结构
- 提交时:
- 校验答题完整性
- 触发异步评分任务
关键实现:
java复制// 动态组卷服务
public EvalPaper generatePaper(UserInfo user) {
// 1. 获取基础题库
List<Question> pool = questionMapper.selectByTags(
user.getGrade(), user.getGender());
// 2. 按维度分组
Map<String, List<Question>> dimensionMap = pool.stream()
.collect(Collectors.groupingBy(Question::getDimension));
// 3. 每个维度随机选取N题
List<Question> selected = dimensionMap.values().stream()
.flatMap(list -> randomSelect(list, 5).stream())
.collect(Collectors.toList());
// 4. 生成试卷结构
return new EvalPaper(UUID.randomUUID().toString(), selected);
}
// Redis缓存试卷结构(30分钟过期)
redisTemplate.opsForValue().set(
"eval:paper:" + paperId,
JsonUtils.toJson(paper),
30, TimeUnit.MINUTES);
3.2 实时分析预警
评分算法示例(抑郁维度):
python复制# 伪代码:PHQ-9改良算法
def calc_depression(scores):
total = sum(scores['phq9_items'])
if total >= 20:
return {'level': 'severe', 'action': '紧急干预'}
elif total >= 15:
return {'level': 'moderate', 'action': '建议咨询'}
else:
return {'level': 'normal', 'action': '持续观察'}
预警触发逻辑:
- 消息队列消费评估结果
- 调用规则引擎判断风险等级
- 高风险案例直接创建咨询工单
- 中等风险发送心理委员通知
4. 典型问题解决方案
4.1 小程序端常见坑
图片上传失败排查:
- 检查
wx.chooseImage的sizeType配置 - 确保服务器域名已在微信后台配置
- 临时路径转存技巧:
javascript复制// 正确示例
wx.uploadFile({
url: 'https://yourdomain.com/upload',
filePath: tempFilePaths[0],
name: 'file',
formData: {'evalId': '123'},
success(res) {
console.log(res.data)
}
})
登录态维护方案:
javascript复制// 封装请求拦截器
const request = (options) => {
return new Promise((resolve, reject) => {
if (needRefreshToken(options.url)) {
refreshToken().then(newToken => {
options.header['Authorization'] = newToken
wx.request(options)
})
} else {
wx.request(options)
}
})
}
4.2 服务端性能优化
评估提交防重设计:
java复制@Transactional
public SubmitResult submitEval(EvalSubmitDTO dto) {
// 1. 分布式锁防重
String lockKey = "eval:submit:" + dto.getEvalId();
boolean locked = redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS);
if (!locked) throw new BizException("操作过于频繁");
try {
// 2. 幂等校验
if (evalMapper.exists(dto.getEvalId())) {
return SubmitResult.duplicate();
}
// 3. 异步处理主逻辑
mqProducer.send(new EvalMessage(dto));
return SubmitResult.success();
} finally {
redisLock.unlock(lockKey);
}
}
MongoDB查询优化:
java复制// 创建索引示例
@Document(collection = "eval_details")
@CompoundIndexes({
@CompoundIndex(name = "eval_dimension_idx",
def = "{'evalId': 1, 'analysis.dimension': 1}")
})
public class EvalDetail {
// 字段定义
}
5. 部署与运维实践
5.1 宝兰德中间件适配
关键调整项:
- 数据源配置(替换Druid连接池)
yaml复制# application-bes.yaml
bes:
datasource:
url: jdbc:besql://127.0.0.1:1688/testdb
driver-class-name: com.bes.enterprise.jdbc.Driver
validation-query: SELECT 1 FROM DUAL
- RocketMQ适配改造
java复制// 消息生产者配置
@Bean
public Producer besProducer() {
DefaultMQProducer producer = new DefaultMQProducer("EVAL_GROUP");
producer.setNamesrvAddr("besmq://127.0.0.1:9876");
producer.setVipChannelEnabled(false); // 关键配置
return producer;
}
5.2 监控体系建设
Prometheus监控指标:
java复制// 评估相关指标
@RestController
public class EvalController {
private final Counter submitCounter = Counter.build()
.name("eval_submit_total")
.help("Total evaluation submissions")
.register();
@PostMapping("/eval/submit")
public Result submit(@RequestBody EvalDTO dto) {
submitCounter.inc();
// 业务逻辑
}
}
日志收集方案:
code复制filebeat.inputs:
- type: log
paths:
- /var/log/psych/*.log
fields:
app: psych-service
output.logstash:
hosts: ["logserver:5044"]
6. 项目演进方向
-
AI辅助分析:引入NLP技术处理开放式问题
- 情感分析(识别潜在危机)
- 话题聚类(发现共性困扰)
-
多模态评估:
- 语音情绪识别(通过小程序录音)
- 书写特征分析(压力水平预测)
-
隐私计算应用:
- 联邦学习(跨校数据协同)
- 差分隐私(统计报表发布)
注意:所有演进方案必须通过伦理委员会评审,确保符合《个人信息保护法》要求。我们目前正在与法学院合作开发专门的合规审查模块。
