1. 项目概述
校园竞赛管理系统是高校信息化建设的重要组成部分,旨在解决传统竞赛管理过程中存在的效率低下、信息孤岛等问题。这个基于SSM框架的系统实现了从竞赛发布、报名、评审到结果公示的全流程数字化管理,为师生提供了便捷的参赛体验,同时减轻了教务人员的工作负担。
我在实际开发中发现,这类系统最核心的价值在于打通了教务处、院系、学生三方之间的信息壁垒。通过半年时间的迭代开发,系统已经稳定支撑了校内12类学科竞赛的全程管理,累计处理报名数据3800余条。下面将详细分享这个项目的技术实现细节和实战经验。
2. 技术架构设计
2.1 SSM框架选型
采用Spring+SpringMVC+MyBatis的组合主要基于以下考量:
- Spring的IoC容器管理服务层组件,通过声明式事务保证数据一致性
- SpringMVC的注解驱动开发模式简化控制器编写
- MyBatis的灵活SQL映射满足复杂查询需求
特别在竞赛评审环节,需要处理多表关联查询(如参赛作品与评委打分记录),MyBatis的动态SQL功能显著提升了开发效率。以下是核心配置示例:
xml复制<!-- MyBatis映射文件片段 -->
<select id="getContestWithJudges" resultMap="contestResultMap">
SELECT c.*, j.judge_name, j.title
FROM contest c LEFT JOIN contest_judge cj ON c.id=cj.contest_id
LEFT JOIN judge j ON cj.judge_id=j.id
WHERE c.id=#{id}
</select>
2.2 数据库设计要点
数据库采用MySQL 8.0,主要表结构包括:
- 竞赛基础表(contest):存储竞赛名称、时间、规则等元数据
- 用户表(user):区分管理员、评委、学生三种角色
- 报名表(registration):记录学生参赛信息
- 评审表(judging):保存评委打分及评语
特别注意建立了完善的索引策略:
sql复制ALTER TABLE registration
ADD INDEX idx_contest_user (contest_id, user_id);
这个复合索引极大提升了高频查询(如检查用户是否已报名)的性能,在压力测试中使相关查询响应时间从120ms降至15ms。
3. 核心功能实现
3.1 多级审核工作流
竞赛管理涉及院系初审、教务处终审的多级流程,采用状态机模式实现:
java复制public enum ContestStatus {
DRAFT(0), DEPARTMENT_REVIEW(1),
SCHOOL_REVIEW(2), PUBLISHED(3),
ARCHIVED(4);
// 状态转换校验逻辑
public boolean canTransferTo(ContestStatus next) {
switch(this) {
case DRAFT: return next == DEPARTMENT_REVIEW;
case DEPARTMENT_REVIEW:
return next == SCHOOL_REVIEW || next == DRAFT;
// 其他状态转换规则...
}
}
}
实际开发中遇到的坑:最初未考虑并发场景下的状态覆盖问题,后来通过乐观锁机制解决:
java复制@Update("UPDATE contest SET status=#{status}, version=version+1
WHERE id=#{id} AND version=#{version}")
int updateStatusWithLock(Contest contest);
3.2 文件评审模块
支持作品文档在线提交与评审是系统的关键需求。技术实现要点:
- 使用Apache Commons FileUpload处理多文件上传
- 文件存储采用"年/竞赛ID/用户ID"的目录结构
- 通过PDF.js实现浏览器端文档预览
存储方案对比测试:
| 方案 | 上传速度 | 读取速度 | 成本 |
|---|---|---|---|
| 本地存储 | 快 | 快 | 低 |
| 七牛云 | 中 | 快 | 中 |
| FastDFS | 慢 | 中 | 高 |
最终选择本地存储+定期备份的方案,主要考虑教育网内传输速度优势。
4. 安全与性能优化
4.1 权限控制体系
采用RBAC模型结合Shiro框架,特别注意竞赛数据权限的特殊需求:
- 院系管理员只能管理本院系发起的竞赛
- 评委只能查看被分配的参赛作品
- 学生只能看到已公开的竞赛信息
权限注解示例:
java复制@RequiresRoles(value={"judge"}, logical=Logical.AND)
@RequiresPermission("contest:score")
public void submitScore(ScoreVO vo) {
// 评委提交评分
}
4.2 高并发应对策略
在报名截止前1小时通常会出现访问高峰,我们通过以下措施保障系统稳定:
- 报名接口采用Redis分布式锁
- 热点数据缓存(竞赛基本信息)
- 静态资源CDN加速
压力测试结果(JMeter):
| 并发用户数 | 平均响应时间 | 错误率 |
|---|---|---|
| 500 | 320ms | 0.1% |
| 1000 | 580ms | 0.5% |
| 2000 | 1200ms | 2.3% |
5. 部署实践
5.1 环境配置建议
推荐的生产环境配置:
- 服务器:4核8G内存(可支撑2000并发)
- JDK:OpenJDK 11
- Tomcat:9.0.x版本
- MySQL配置优化:
ini复制innodb_buffer_pool_size = 2G max_connections = 300
5.2 容器化部署
使用Docker-compose编排服务:
yaml复制version: '3'
services:
app:
image: tomcat:9-jdk11
ports: ["8080:8080"]
volumes:
- ./webapps:/usr/local/tomcat/webapps
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
6. 典型问题排查
-
文件上传失败:
- 检查Tomcat的max-file-size配置
- Linux系统注意存储目录权限
- 文件名校验避免特殊字符
-
报名数据不一致:
- 确认事务注解@Transactional生效
- 检查MyBatis的flushCache配置
- 验证数据库隔离级别(推荐READ_COMMITTED)
-
界面加载缓慢:
- 合并CSS/JS文件
- 启用Gzip压缩
- 检查Nginx的keepalive配置
7. 扩展功能建议
根据实际运营反馈,后续可考虑增加:
- 微信小程序端接入
- 智能分组算法(平衡评委工作量)
- 查重功能(基于文本相似度分析)
- 数据分析看板(参赛趋势可视化)
在数据库设计阶段预留的extension字段,现在正好可以用于存储这些新功能需要的扩展属性。这也是我建议大家在设计初期就要考虑的扩展性问题 - 字段冗余好过结构僵化。