1. 项目背景与核心需求
这个学生课程评价系统是我去年指导的一个计算机专业本科毕业设计项目,现在把完整的设计思路和源码分享出来。在高校教学管理中,课程评价一直是教务工作的重点和难点。传统纸质问卷方式存在数据统计慢、结果反馈滞后等问题,而市面上通用的在线表单工具又缺乏针对教学评价的专业功能。
我们开发的这套系统主要解决三个痛点:
- 实现学生匿名评价与教师查看结果的分离机制
- 自动生成多维度的课程质量分析报告
- 支持自定义评价指标模板管理
系统采用B/S架构,前端用Vue+ElementUI实现响应式布局,后端基于SpringBoot+MyBatis技术栈,数据库选用MySQL 8.0。特别在权限控制方面做了精细设计,确保学生只能看到自己需要评价的课程,教师只能查看自己所授课程的评价结果。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 技术选型考量
选择SpringBoot而非传统SSM框架主要基于:
- 内嵌Tomcat简化部署(特别适合毕设演示场景)
- 自动配置减少XML编写(学生更易上手)
- 丰富的starter依赖(快速集成Redis、邮件等服务)
前端选用Vue.js而非jQuery的原因是:
- 组件化开发便于功能模块复用
- 双向数据绑定简化表单处理逻辑
- 生态丰富(ElementUI完美匹配管理系统需求)
2.2 数据库设计要点
核心表关系设计:
sql复制CREATE TABLE `eval_questionnaire` (
`id` int NOT NULL AUTO_INCREMENT,
`course_id` int NOT NULL COMMENT '关联课程ID',
`template_id` int NOT NULL COMMENT '评价模板ID',
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`status` tinyint DEFAULT '0' COMMENT '0未开始 1进行中 2已结束',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `eval_answer` (
`id` bigint NOT NULL AUTO_INCREMENT,
`questionnaire_id` int NOT NULL,
`question_id` int NOT NULL,
`student_id` varchar(20) NOT NULL,
`score` tinyint DEFAULT NULL COMMENT '1-5分制评分',
`comment` varchar(500) DEFAULT NULL COMMENT '文字评价',
`submit_time` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_student_question` (`questionnaire_id`,`question_id`,`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意的点:
- 评价记录表使用联合唯一索引防止重复提交
- 所有时间字段统一用datetime类型(避免时区问题)
- 字符集强制使用utf8mb4(支持emoji评价)
3. 核心功能实现
3.1 匿名化处理机制
虽然系统需要记录学生提交记录(防止重复评价),但展示给教师时会做脱敏处理。关键实现逻辑:
java复制// 评价结果脱敏处理
public List<EvalResultVO> getCourseResults(Integer courseId) {
List<EvalAnswer> answers = answerMapper.selectByCourse(courseId);
return answers.stream().map(answer -> {
EvalResultVO vo = new EvalResultVO();
vo.setQuestionId(answer.getQuestionId());
vo.setScore(answer.getScore());
vo.setComment(answer.getComment());
// 学号脱敏处理:2020210001 -> 2020****01
vo.setStudentId(maskStudentId(answer.getStudentId()));
return vo;
}).collect(Collectors.toList());
}
private String maskStudentId(String originalId) {
if(originalId == null || originalId.length() < 6) {
return "******";
}
return originalId.substring(0,4) + "****"
+ originalId.substring(originalId.length()-2);
}
3.2 评价模板动态配置
通过JSON格式存储问题模板,前端动态渲染评价表单:
json复制{
"version": "1.0",
"questions": [
{
"id": 1,
"type": "score",
"title": "教师授课准备是否充分",
"options": ["非常差", "较差", "一般", "良好", "优秀"]
},
{
"id": 2,
"type": "text",
"title": "对本课程的其他建议",
"maxLength": 300
}
]
}
后端使用Jackson的JsonNode处理动态解析:
java复制public String generateFormHtml(String templateJson) {
JsonNode root = objectMapper.readTree(templateJson);
StringBuilder html = new StringBuilder();
for (JsonNode question : root.path("questions")) {
String type = question.path("type").asText();
if("score".equals(type)) {
html.append(buildScoreQuestion(question));
} else if("text".equals(type)) {
html.append(buildTextQuestion(question));
}
}
return html.toString();
}
4. 典型问题解决方案
4.1 并发提交控制
为防止网络延迟导致重复提交,采用前端+后端双重控制:
- 前端提交后禁用按钮(Vue指令实现)
javascript复制Vue.directive('prevent-reclick', {
inserted(el, binding) {
el.addEventListener('click', () => {
if(el.disabled) return;
el.disabled = true;
setTimeout(() => el.disabled = false, 3000);
});
}
})
- 后端数据库唯一索引约束(见2.2表设计)
- 添加Redis分布式锁(集群部署时使用)
java复制public boolean submitEvaluation(EvalAnswer answer) {
String lockKey = "eval_lock:" + answer.getQuestionnaireId()
+ ":" + answer.getStudentId();
try {
// 尝试获取锁,有效期3秒
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
if(locked != null && locked) {
return answerMapper.insert(answer) > 0;
}
throw new RuntimeException("操作过于频繁");
} finally {
redisTemplate.delete(lockKey);
}
}
4.2 大数据量导出优化
当需要导出整学期评价数据时,采用分页查询+流式导出:
java复制@GetMapping("/export")
public void exportData(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=eval_data.xlsx");
try(ExcelWriter writer = EasyExcel.write(response.getOutputStream())
.head(EvalExportVO.class).build()) {
int pageNum = 1;
Page<EvalAnswer> page;
do {
page = answerService.pageByCondition(new Page<>(pageNum, 1000));
writer.write(convertToExportVO(page.getRecords()),
EasyExcel.writerSheet("评价数据").build());
pageNum++;
} while (page.hasNext());
}
}
5. 部署与扩展建议
5.1 最小化部署方案
对于课程数<50的小型应用,推荐配置:
- 1核2G云服务器(学生优惠机型即可)
- MySQL 8.0社区版
- 前端打包后通过Nginx部署
nginx复制server {
listen 80;
server_name eval.yourschool.edu.cn;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
}
}
5.2 扩展方向建议
- 增加自然语言处理模块:对学生文字评价进行情感分析
python复制# 示例:使用SnowNLP进行简单情感分析
from snownlp import SnowNLP
def analyze_comment(comment):
s = SnowNLP(comment)
return {
'sentiment': s.sentiments, # 0-1之间的情感值
'keywords': s.keywords(3) # 提取前3个关键词
}
- 对接学校统一认证系统(如CAS/OAuth2)
- 增加移动端小程序入口(Uniapp跨平台方案)
这个项目在实现时特别注意了教学场景的实际需求,比如:
- 评价期结束后自动邮件提醒教师查看结果
- 提供对比分析功能(教师可以查看自己历年课程评价变化)
- 管理员后台能实时查看各课程评价进度
源码中包含了完整的API文档和部署指南,对于计算机专业学生来说,既可以直接作为毕设项目,也可以在此基础上进行功能扩展。我在项目仓库的README里特别标注了几个容易出错的配置点,包括跨域处理、日期格式序列化等常见坑点。
