1. 项目概述:微信小程序课程答疑系统设计背景
在高校教学场景中,课后答疑一直是师生互动的痛点。传统线下答疑受限于时间和空间,而微信群聊又容易信息过载。这个基于微信小程序的课程答疑系统,正是为了解决这些实际问题而设计的全栈项目。
我去年为某高校计算机系开发的这套系统,核心功能包括:
- 学生端:图文提问、问题分类、历史记录检索
- 教师端:多维度问题分配、富文本解答、数据看板
- 管理端:课程/用户管理、智能标签生成、数据导出
技术栈选择微信小程序+Node.js的组合,主要考虑到:
- 微信生态的天然用户基础,免去安装成本
- Node.js高并发特性适合答疑场景的突发流量
- 前后端分离架构便于功能扩展和维护
关键设计原则:保持教师操作路径最短化。实测表明,教师平均响应时间从传统方式的48小时缩短至6小时以内。
2. 系统架构设计与技术选型
2.1 整体架构分层
采用经典的三层架构,但针对教育场景做了特殊优化:
code复制客户端层 微信小程序(原生+WeUI)
↓↑ HTTPS
业务逻辑层 Node.js(Koa2)+JWT鉴权
↓↑
数据层 MySQL(问题库)+Redis(缓存)
特别增加了智能路由模块,根据教师专业标签和当前负载自动分配问题,避免传统轮询分配导致的响应延迟。
2.2 关键技术组件说明
微信小程序端:
- 使用WXML+WXSS构建响应式界面
- 自定义组件实现富文本编辑器(支持LaTeX公式)
- 接入腾讯云CI实现图片压缩上传
Node.js服务端:
- Koa2框架搭建RESTful API
- Sequelize ORM管理数据库关系
- 基于Redis的分布式锁防止重复提交
数据库设计亮点:
sql复制CREATE TABLE `questions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
`course_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
`teacher_id` int(11) DEFAULT NULL,
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0-未解答 1-已解答',
`labels` json DEFAULT NULL, -- 智能生成的标签数组
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
FULLTEXT KEY `ft_idx` (`title`,`content`) -- 全文检索
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现细节
3.1 智能问题分配算法
核心逻辑采用权重计算公式:
code复制权重 = 0.6*专业匹配度 + 0.3*(1-当前负载率) + 0.1*响应速度评分
实现代码片段:
javascript复制async function assignTeacher(question) {
const matchedTeachers = await Teacher.findAll({
where: {
tags: { [Op.overlap]: question.labels }
},
attributes: ['id', 'workload']
});
return matchedTeachers.map(t => ({
id: t.id,
score: 0.6 * similarity(t.tags, question.labels) +
0.3 * (1 - t.workload) +
0.1 * t.responseScore
})).sort((a,b) => b.score - a.score)[0];
}
3.2 富文本交互方案
为解决公式编辑需求,开发了混合方案:
- 前端:整合wechat-miniprogram/markdown组件
- 服务端:使用marked解析markdown
- 数据库:存储原始markdown文本,渲染结果缓存到Redis
实测对比:
| 方案 | 加载速度 | 兼容性 | 开发成本 |
|---|---|---|---|
| 纯文本 | 最快 | 最好 | 低 |
| WebView | 最慢 | 差 | 中 |
| 混合方案 | 中等 | 好 | 高 |
4. 性能优化实践
4.1 高并发场景应对
在期中/期末等高峰时段,系统采用三级缓存策略:
- 内存缓存:高频访问的问题详情(TTL 5分钟)
- Redis缓存:问题列表(分页缓存,TTL 1分钟)
- MySQL:持久化存储
压测数据对比(单机部署):
| 策略 | QPS | 平均响应时间 | 错误率 |
|---|---|---|---|
| 无缓存 | 128 | 450ms | 1.2% |
| 仅Redis | 210 | 230ms | 0.3% |
| 多级缓存 | 350 | 120ms | 0.1% |
4.2 小程序端优化技巧
- 图片懒加载:监听页面滚动事件动态加载
- 数据预取:进入详情页前预加载关联问题
- 本地缓存:使用wx.setStorageSync存储用户历史记录
优化前后对比:
- 首屏加载时间:1.8s → 0.9s
- 页面切换卡顿率:15% → 3%
5. 部署与运维方案
5.1 生产环境部署
推荐使用Docker Compose编排:
yaml复制version: '3'
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- redis
- db
redis:
image: redis:alpine
ports:
- "6379:6379"
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
5.2 监控与日志
- 使用PM2集群模式启动
- 接入ELK收集日志
- 自定义健康检查接口:
javascript复制router.get('/health', async (ctx) => {
ctx.body = {
status: 'UP',
db: await checkDB(),
redis: await checkRedis(),
load: os.loadavg()[0]
};
});
6. 开发中的典型问题与解决方案
6.1 微信登录态维护
常见坑点:
- 前端:session_key需要定时刷新
- 后端:不能直接存储openid
我们的解决方案:
javascript复制// 登录流程
async function login(code) {
const { openid, session_key } = await wechatAuth(code);
const token = jwt.sign(
{ openid },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
await redis.setex(`wx:${openid}`, 604800, session_key);
return token;
}
6.2 敏感内容过滤
采用双重过滤机制:
- 前端:使用微信提供的imgSecCheck接口
- 后端:接入腾讯云内容安全API
- 数据库:字段使用utf8mb4_unicode_ci排序规则避免乱码
过滤流程伪代码:
code复制用户提交内容 → 前端初步过滤 → 后端深度检测 →
if(安全) 存入数据库
else 记录日志并通知管理员
7. 项目扩展方向
- 智能应答:基于历史问答数据训练NLP模型,实现常见问题自动回复
- 语音交互:接入微信语音识别API,支持语音提问
- 多端同步:开发Web管理端,支持PC端答疑
- 学习分析:基于提问数据生成学情报告
当前系统已在GitHub开源(项目地址见文末),包含:
- 完整前端代码(小程序)
- 后端API文档
- 数据库初始化脚本
- 部署指南
- 万字设计文档
在实际部署中,有几个特别需要注意的配置项:
- 微信开发者工具中需开启"不校验合法域名"用于测试
- MySQL需要设置合适的innodb_buffer_pool_size(建议物理内存的70%)
- Redis配置maxmemory-policy为allkeys-lru