作为一名经历过多次学科竞赛指导的开发者,我深知传统竞赛管理方式的痛点。每次竞赛从报名到成绩公布,老师们都要处理堆积如山的纸质材料,学生们则要反复跑办公室确认信息。这种低效模式不仅消耗人力,还容易出错。去年帮学校开发这套系统时,教务处老师握着我的手说:"你们这个系统,把我们工作量减少了70%!"
这个基于SpringBoot2+Vue3的学科竞赛管理系统,核心解决三个问题:
技术选型上,后端采用SpringBoot2.7.18(LTS版本),前端使用Vue3+Element Plus,数据库为MySQL8.0。特别说明选择MyBatis-Plus而非JPA的原因:高校场景中复杂报表查询较多,MP的Wrapper条件构造器比JPA的Specification更直观易维护。
系统设计四类角色,权限控制采用RBAC模型:
权限实现关键代码:
java复制@PreAuthorize("hasRole('TEACHER') or hasRole('ADMIN')")
@PostMapping("/contest/create")
public Result createContest(@Valid @RequestBody ContestVO vo) {
// 竞赛创建逻辑
}
踩坑提醒:初期用注解控制权限时忘了加@EnableGlobalMethodSecurity,调试两小时才发现
竞赛状态流转采用状态模式实现:
mermaid复制[状态图已移除,改用文字描述]
未开始 → (到达开始时间) 报名中 → (到达结束时间) 评审中 → (评审完成) 已结束
状态变更触发逻辑:
java复制@Scheduled(cron = "0 0 0 * * ?")
public void autoUpdateContestStatus() {
// 每日检查时间节点更新状态
}
设计亮点:
评委看不到学生信息,学生看不到评委信息,关键SQL:
sql复制SELECT work_id, content FROM competition_work
WHERE contest_id = #{contestId}
ORDER BY RAND() LIMIT 10
java复制@AssertTrue(message = "评分必须在0-100之间")
public boolean isScoreValid() {
return scoreValue >= 0 && scoreValue <= 100;
}
前端采用Vue3组合式API示例:
javascript复制// 报名表单校验
const rules = {
contestId: [{ required: true, trigger: 'blur' }],
attachment: [{
validator: (_, v) => v?.size < 1024 * 1024 * 5,
message: '文件需小于5MB'
}]
}
java复制@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
使用@TableField(exist = false)+ResultMap避免N+1查询
java复制@Cacheable(key = "'contest:count:'+#contestId")
public Integer getApplyCount(Long contestId) {...}
实测数据(1000并发):
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/contest?useSSL=false&serverTimezone=Asia/Shanghai
code复制client_max_body_size 20M;
这个项目最让我自豪的是,上线半年后学校教务处主动要求扩大使用范围。有个细节值得分享:在成绩公示模块,我们加入了"异议申诉"功能,学生可以匿名提出异议,这个设计避免了很多后续纠纷。