1. 项目背景与核心价值
学科竞赛作为高校人才培养的重要环节,传统的人工管理方式正面临三大痛点:报名信息混乱、评审流程不透明、数据统计效率低下。我们团队基于实际教学管理需求,采用SpringBoot+Vue技术栈开发了这套竞赛管理系统,实现了从报名到证书发放的全流程数字化管理。
这个系统最显著的特点是采用了前后端分离架构,后端使用Java生态的成熟框架保证业务稳定性,前端选用Vue.js实现响应式交互。经过两个学期的实际运行,系统已稳定支撑了37场校级竞赛,累计处理报名数据2865条,评审记录892份。
关键数据:系统将竞赛申报审批周期从平均5个工作日缩短至1.5天,评委工作量减少60%,证书发放错误率降至0.3%以下。
2. 技术架构设计解析
2.1 整体技术选型
后端技术栈采用经典的SpringBoot+MyBatis组合,主要基于以下考量:
- SpringBoot的自动配置特性大幅减少XML配置(相比传统SSM框架配置量减少70%)
- MyBatis的SQL可控性更适合复杂竞赛业务查询(特别是多表关联的统计报表)
- 内嵌Tomcat容器简化部署(只需打包成jar即可运行)
前端选用Vue2.x+ElementUI的方案,主要优势在于:
- 组件化开发效率高(复用率达65%)
- Axios拦截器完美处理HTTP状态码(401自动跳转登录页)
- Vuex管理全局状态(如用户权限、竞赛基础数据)
2.2 数据库设计要点
MySQL表设计遵循竞赛业务的核心实体关系:
sql复制CREATE TABLE `competition` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '竞赛名称',
`start_time` datetime NOT NULL COMMENT '报名开始时间',
`end_time` datetime NOT NULL COMMENT '报名结束时间',
`max_team` int DEFAULT '5' COMMENT '最大组队人数',
`status` tinyint DEFAULT '0' COMMENT '0未开始 1报名中 2已结束',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意的三个设计细节:
- 采用datetime类型精确记录时间(避免timestamp的2038年问题)
- 使用utf8mb4字符集支持emoji昵称(学生提交的团队名称常含特殊符号)
- 状态字段使用tinyint而非enum(方便后期扩展状态类型)
3. 核心功能实现细节
3.1 多级评审流程控制
系统支持院级-校级-省级三级评审,通过状态机模式实现流程控制:
java复制public enum ReviewStatus {
DEPARTMENT_REVIEW(1, "院系初审"),
SCHOOL_REVIEW(2, "校级评审"),
PROVINCE_REVIEW(3, "省级推荐"),
FINISHED(4, "评审完成");
private final int code;
private final String desc;
// 状态校验逻辑
public static boolean validTransition(int from, int to) {
return to == from + 1 || (from == 3 && to == 4);
}
}
评审流程中的三个关键技术点:
- 使用Redis存储当前状态(设置24小时过期防止死锁)
- 采用乐观锁解决并发提交问题(version字段控制)
- 评审意见使用Delta压缩算法存储(节省60%存储空间)
3.2 实时成绩看板
前端通过WebSocket实现成绩实时更新:
javascript复制// Vue组件中建立WS连接
created() {
this.socket = new WebSocket(`wss://${location.host}/ws/score`);
this.socket.onmessage = (event) => {
const data = JSON.parse(event.data);
this.$store.commit('updateScore', data);
}
}
性能优化措施:
- 使用protobuf替代JSON(数据传输量减少45%)
- 设置200ms的debounce防止频繁渲染
- 离线时自动降级为轮询模式
4. 典型问题解决方案
4.1 批量导入崩溃问题
初期使用POI处理Excel导入时频繁OOM,最终解决方案:
- 采用SAX模式解析XLSX(内存占用从500MB降至20MB)
- 分批次提交(每100条记录一个事务)
- 增加模板校验(使用Hibernate Validator)
4.2 跨院系权限控制
实现细粒度的数据权限控制:
java复制@PreAuthorize("hasRole('DEPARTMENT_ADMIN') && #deptId == authentication.details.deptId")
public List<Team> getTeamsByDept(int deptId) {
return teamMapper.selectByDept(deptId);
}
权限系统设计要点:
- 基于Spring Security的Method Security
- 缓存权限规则到Caffeine(500ms过期)
- 前端菜单动态渲染(根据roles字段过滤)
5. 部署与运维实践
5.1 生产环境配置
推荐服务器规格:
- 2核4G(支持200并发用户)
- OpenJDK 11 + JVM参数调优:
code复制-Xms512m -Xmx1024m -XX:+UseG1GC
Nginx关键配置:
nginx复制location /api {
proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 20M; # 支持大文件上传
}
5.2 监控方案
Prometheus监控指标示例:
code复制spring_http_requests_seconds_sum{uri="/api/teams",status="200",} 458.2
spring_http_requests_seconds_count{uri="/api/teams",status="200",} 1283
告警规则设置:
- API响应时间 > 1s 持续5分钟
- MySQL连接数 > 80%
- 磁盘空间 < 10%
6. 源码结构说明
项目采用标准Maven多模块结构:
code复制├── competition-admin // 后台管理模块
├── competition-api // 公共DTO定义
├── competition-common // 工具类库
├── competition-dao // MyBatis映射文件
├── competition-service // 业务逻辑实现
└── competition-web // 控制器层
前端目录关键结构:
code复制src/
├── api/ // 接口定义
├── assets/ // 静态资源
├── components/ // 公共组件
│ ├── Countdown.vue // 报名倒计时组件
│ └── ScoreChart.vue // 成绩雷达图
├── router/ // 动态路由配置
└── store/ // Vuex状态管理
开发环境快速启动:
bash复制# 后端
mvn spring-boot:run -pl competition-web
# 前端
npm run serve -- --port 8081
这个系统在实际运行中我们发现,定时任务的时间配置需要特别关注竞赛开始/结束时间点的并发压力。建议在正式竞赛前1小时进行全链路压力测试,模拟200人同时提交作品的情况。另外,评审专家的账户最好提前3天完成初始化,避免临时账户分配导致权限异常。