1. 项目背景与核心需求
在大学校园里,学科竞赛是培养学生创新能力和实践能力的重要途径。但传统的人工管理方式存在诸多痛点:报名表堆积如山、信息核对耗时费力、成绩统计容易出错。去年我参与某高校数学建模竞赛组织时,仅处理300份纸质报名表就耗费了整整一周时间,更不用说后续的成绩汇总工作了。
这套基于SpringBoot+Vue的学科竞赛管理系统正是为解决这些问题而生。系统采用前后端分离架构,后端使用SpringBoot提供RESTful API,前端用Vue.js构建交互界面,实现了从竞赛发布、报名、评审到成绩统计的全流程数字化管理。
2. 技术架构设计
2.1 后端技术选型
SpringBoot 2.7.x作为后端框架是经过多重考量后的选择:
- 自动配置特性大幅减少了XML配置,比如数据库连接池默认使用HikariCP
- 内嵌Tomcat服务器简化部署,只需打包成jar即可运行
- 与MyBatis的整合非常顺畅,通过@MapperScan注解就能自动扫描映射接口
数据库选用MySQL 8.0,主要考虑到:
- 高校IT部门通常已有MySQL运维经验
- 事务ACID特性保证报名数据的一致性
- JSON字段支持方便存储竞赛详情等半结构化数据
2.2 前端技术方案
Vue 3.x + Element Plus的组合提供了良好的开发体验:
- Composition API使代码组织更灵活
- Element Plus的表格组件完美适配大量报名数据的展示
- Axios拦截器统一处理401认证过期等场景
特别值得一提的是采用的多环境配置方案:
// env.development VUE_APP_API_BASE=http://localhost:8080 // env.production VUE_APP_API_BASE=/api3. 核心功能实现
3.1 竞赛报名模块
报名流程的状态机设计是关键:
public enum RegistrationStatus { PENDING(0, "待审核"), APPROVED(1, "已通过"), REJECTED(2, "已拒绝"); // 省略getter和构造方法 }数据库表设计特别注意了并发控制:
CREATE TABLE `competition_registration` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `competition_id` BIGINT NOT NULL COMMENT '关联竞赛ID', `student_id` VARCHAR(20) NOT NULL COMMENT '学号', `team_name` VARCHAR(50) COMMENT '团队名称', `status` TINYINT DEFAULT 0 COMMENT '0-待审核 1-已通过 2-已拒绝', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY `idx_competition_student` (`competition_id`, `student_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 评审打分模块
采用策略模式实现评分计算:
public interface ScoringStrategy { BigDecimal calculateTotal(ScoreDTO score); } @Component public class DefaultScoringStrategy implements ScoringStrategy { @Override public BigDecimal calculateTotal(ScoreDTO score) { return score.getTechnical() .add(score.getInnovation()) .add(score.getPresentation()); } }4. 关键问题与解决方案
4.1 高并发报名场景
在热门竞赛开放报名时,出现了严重的超卖问题。我们通过以下方案解决:
- 数据库层面添加唯一索引防止重复报名
- 使用Redis分布式锁控制报名流程:
public boolean register(Long competitionId, String studentId) { String lockKey = "reg:" + competitionId + ":" + studentId; try { Boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS); if (Boolean.TRUE.equals(locked)) { // 执行报名逻辑 } } finally { redisTemplate.delete(lockKey); } }4.2 文件上传优化
报名时需要提交作品附件,我们做了以下优化:
- 使用MinIO替代本地存储
- 前端实现分片上传
- 后端添加MD5校验避免重复上传
5. 部署实践
5.1 后端部署
采用Docker Compose部署方案:
version: '3' services: app: image: openjdk:17-jdk ports: - "8080:8080" volumes: - ./app.jar:/app.jar command: java -jar /app.jar depends_on: - redis - mysql mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - mysql_data:/var/lib/mysql redis: image: redis:6 ports: - "6379:6379"5.2 前端部署
配置Nginx实现静态资源服务和API反向代理:
server { listen 80; server_name competition.example.com; location / { root /var/www/html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend:8080; proxy_set_header Host $host; } }6. 扩展功能
6.1 微信通知集成
通过微信公众号模板消息发送审核结果通知:
public void sendWechatNotice(String openId, String status) { String templateId = "审核结果通知模板ID"; Map<String, Object> data = new HashMap<>(); data.put("status", status); wechatClient.sendTemplateMsg(openId, templateId, data); }6.2 数据分析看板
使用ECharts实现的竞赛数据可视化:
// 参赛人数趋势图 const option = { xAxis: { type: 'category', data: ['周一','周二','周三','周四','周五'] }, yAxis: {type: 'value'}, series: [{ data: [120, 200, 150, 80, 70], type: 'bar' }] };7. 踩坑记录
- Vue路由history模式需要后端配合配置,否则刷新会404。解决方案:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/{path:[^\\.]*}") .setViewName("forward:/index.html"); } }MyBatis批量插入性能优化:改用BatchExecutor并合理设置rewriteBatchedStatements参数
跨域问题解决方案:精确配置CORS而非简单允许所有来源
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("https://competition.example.com"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/api/**", config); return new CorsFilter(source); }这套系统在某高校实际运行一个学期后,管理效率提升显著:原本需要3天处理的报名工作现在2小时即可完成,成绩统计错误率降为零。后续计划加入智能组队、往届数据分析等功能,进一步发挥系统价值。