1. 项目背景与需求分析
高校学科竞赛作为培养学生创新能力、实践能力和团队协作精神的重要载体,近年来在高等教育领域扮演着越来越重要的角色。通达学院作为一所应用型本科院校,每年组织参与的各类学科竞赛超过50项,参与学生达2000余人次。传统的纸质申报和Excel表格管理方式已经无法满足当前的管理需求,主要存在以下痛点:
- 信息孤岛现象严重:竞赛通知、报名、评审、获奖等环节数据分散在不同部门的文件柜和电脑中
- 流程效率低下:从竞赛发布到结果公示平均需要15个工作日,涉及6个部门的纸质材料传递
- 数据统计困难:年度竞赛数据分析需要人工汇总,耗时且容易出错
- 师生体验差:学生需要反复提交相同材料,教师评审工作量大且难以追溯
基于这些痛点,我们决定开发一套集竞赛发布、报名、评审、公示、统计于一体的综合管理平台。系统需要实现以下核心目标:
- 建立统一的竞赛信息门户,实现全流程线上化管理
- 支持多角色协同(学生、教师、评委、管理员)
- 提供智能化的数据统计与分析功能
- 与学校现有教务系统实现数据对接
- 支持移动端访问,提升用户体验
2. 技术选型与架构设计
2.1 技术栈选型依据
经过对当前主流技术方案的对比分析,我们最终确定了以下技术栈组合:
后端技术栈:
- Spring Boot 2.7.3:提供快速开发能力和丰富的starter依赖
- Spring Security:实现细粒度的权限控制
- MyBatis-Plus 3.5.1:简化数据库操作
- Redis 6.2:缓存热点数据和会话管理
- MinIO:分布式文件存储服务
- Activiti 7.1.0:工作流引擎支持复杂审批流程
前端技术栈:
- Vue 3.2 + Element Plus:构建现代化的管理后台
- ECharts 5.3:数据可视化展示
- Axios:HTTP请求处理
- Vue Router:前端路由管理
数据库:
- MySQL 8.0:主业务数据库
- Redis:缓存和会话存储
基础设施:
- Docker 20.10:容器化部署
- Nginx 1.21:反向代理和负载均衡
- Jenkins:持续集成与部署
选择这些技术的主要考虑因素包括:
- 团队技术储备:团队成员对Java和Vue技术栈有丰富经验
- 社区活跃度:所有选型技术都有活跃的社区支持和持续更新
- 性能需求:预计系统高峰期并发量在500-1000之间
- 可维护性:清晰的架构分层和模块化设计
- 扩展性:能够方便地集成学校其他信息系统
2.2 系统架构设计
系统采用典型的分层架构设计,从下到上分为:
基础设施层:
- 物理服务器/云服务
- 容器化平台(Docker)
- 文件存储(MinIO)
- 消息队列(RabbitMQ)
数据层:
- MySQL关系型数据库
- Redis缓存
- 搜索引擎(Elasticsearch)
服务层:
- 基础服务(用户、权限、日志等)
- 核心业务服务(竞赛管理、报名、评审等)
- 工作流引擎(Activiti)
- 定时任务(Quartz)
应用层:
- Web管理后台
- 移动端H5
- 微信小程序
- API网关
表现层:
- PC浏览器
- 移动浏览器
- 微信生态
架构设计的关键决策点包括:
- 前后端分离:便于团队并行开发和独立部署
- 微服务化:核心模块服务化,但考虑到项目规模,采用单体架构+模块化设计
- 缓存策略:多级缓存(Redis+本地缓存)应对高并发场景
- 安全设计:基于RBAC的权限控制+接口级鉴权
3. 核心功能模块实现
3.1 竞赛管理模块
作为系统的核心模块,竞赛管理实现了从创建到归档的全生命周期管理。主要功能点包括:
竞赛创建:
- 多级分类体系(学科竞赛/创新创业竞赛/技能竞赛)
- 富文本编辑器支持复杂格式的竞赛通知
- 附件上传(支持PDF、Word、Excel等格式)
- 自定义报名表单字段配置
java复制// 竞赛实体类核心字段设计
public class Competition {
private Long id;
private String title; // 竞赛名称
private Integer type; // 竞赛类型
private String content; // 竞赛详情(HTML)
private LocalDateTime startTime; // 开始时间
private LocalDateTime endTime; // 结束时间
private Integer maxTeamMember; // 最大团队成员数
private Integer status; // 状态(0-未开始 1-进行中 2-已结束)
private List<CompetitionAttachment> attachments; // 附件列表
private List<FormField> customFields; // 自定义报名字段
}
报名管理:
- 团队报名支持(1-N人组队)
- 报名表自动生成(基于配置的字段)
- 报名资格校验(年级、专业等限制)
- 报名状态实时更新
评审管理:
- 多阶段评审流程配置
- 在线评分表设计
- 评委分配与权限控制
- 分数自动汇总与排名
获奖管理:
- 奖项等级配置
- 证书模板设计
- 批量导出获奖名单
- 获奖公示与异议处理
3.2 用户权限系统设计
系统采用RBAC(Role-Based Access Control)模型进行权限控制,主要实体关系如下:
code复制用户(User) 1-n 用户角色(UserRole) n-1 角色(Role)
角色(Role) 1-n 角色权限(RolePermission) n-1 权限(Permission)
权限控制的具体实现要点:
- 接口级权限:基于Spring Security的@PreAuthorize注解
- 数据权限:通过MyBatis拦截器实现部门数据过滤
- 前端权限:Vue路由守卫+按钮级权限指令
java复制// 权限校验示例
@PreAuthorize("hasRole('TEACHER') && @competitionService.isInCharge(#compId)")
@PostMapping("/review/submit")
public Result submitReview(@PathVariable Long compId, @RequestBody ReviewForm form) {
// 评审提交逻辑
}
3.3 工作流引擎集成
对于复杂的多级审批流程(如竞赛立项审批、获奖结果公示审批等),系统集成了Activiti工作流引擎。关键实现步骤:
- 流程定义:使用BPMN 2.0标准设计审批流程图
- 表单设计:动态表单与流程变量绑定
- 任务分配:基于角色或特定人员的任务分配策略
- 历史追溯:完整的流程实例历史记录
典型的学生参赛审批流程:
code复制开始 → 学生提交报名 → 指导教师审核 → (如需)院系审核 → 竞赛管理员确认 → 结束
4. 关键技术问题与解决方案
4.1 高并发报名场景优化
在热门竞赛开放报名时,系统面临的主要挑战:
- 短时间内大量用户同时提交报名
- 团队报名需要保证数据一致性
- 报名资格校验的实时性要求
解决方案:
- 采用Redis分布式锁控制并发报名
- 使用消息队列异步处理资格校验
- 数据库读写分离+连接池优化
java复制public Result handleRegistration(RegistrationDTO dto) {
// 获取分布式锁
String lockKey = "comp:reg:" + dto.getCompId();
try {
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
return Result.fail("系统繁忙,请稍后重试");
}
// 校验报名资格
if (!qualificationService.check(dto.getUserId(), dto.getCompId())) {
return Result.fail("不符合报名条件");
}
// 处理报名逻辑
return registrationService.processRegistration(dto);
} finally {
// 释放锁
redisTemplate.delete(lockKey);
}
}
4.2 文件存储与管理
系统需要处理多种文件类型:
- 竞赛通知附件(PDF/Word)
- 参赛作品(代码/文档/视频)
- 评审材料
- 获奖证书
技术方案:
- 使用MinIO搭建分布式文件存储集群
- 文件分块上传支持大文件传输
- 文件预览服务(Office转PDF、PDF转图片)
- 完善的权限控制和访问日志
yaml复制# MinIO配置示例
minio:
endpoint: http://minio.cluster.local
accessKey: ${MINIO_ACCESS_KEY}
secretKey: ${MINIO_SECRET_KEY}
bucket:
public: competition-public
private: competition-private
4.3 数据统计与分析
系统提供多维度的数据统计功能:
- 竞赛参与度分析(按院系/专业/年级)
- 获奖情况统计
- 教师指导工作量统计
- 历史数据对比分析
技术实现:
- 使用Elasticsearch存储统计指标
- 定时任务每日生成统计快照
- 基于ECharts的可视化展示
- 支持自定义报表导出
java复制// 统计服务示例
public class StatsService {
public CompetitionStats getCompetitionStats(Long compId) {
// 从ES获取基础数据
SearchResponse response = elasticsearchClient.search(...);
// 计算各项指标
CompetitionStats stats = new CompetitionStats();
stats.setTotalParticipants(response.getHits().getTotalHits().value);
stats.setDepartmentDistribution(calculateDepartmentDist(response));
stats.setGradeDistribution(calculateGradeDist(response));
return stats;
}
}
5. 系统部署与运维
5.1 容器化部署方案
系统采用Docker Compose进行容器编排,主要服务包括:
- 应用服务(Spring Boot)
- MySQL数据库
- Redis缓存
- MinIO文件存储
- Nginx反向代理
dockerfile复制# Spring Boot应用Dockerfile示例
FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
5.2 监控与日志
为确保系统稳定运行,实现了以下监控措施:
- Prometheus + Grafana监控JVM指标和业务指标
- ELK日志收集与分析
- 关键操作审计日志
- 异常报警(邮件/企业微信)
5.3 性能优化实践
系统上线后进行的性能优化措施:
- Nginx配置Gzip压缩和静态资源缓存
- Spring Boot Actuator健康检查
- 数据库索引优化
- 热点数据缓存策略调整
- JVM参数调优
6. 项目成果与经验总结
系统自上线以来,取得了显著的成效:
- 竞赛管理效率提升:平均处理时间从15天缩短至3天
- 师生满意度提高:用户调研满意度达92%
- 数据准确性:年度统计报表错误率降至0.1%以下
- 扩展性验证:已成功对接学校教务系统和统一身份认证
在项目开发过程中积累的主要经验:
- 复杂表单设计:采用JSON Schema定义表单结构,前端动态渲染
- 工作流集成:Activiti与业务系统的深度整合方案
- 安全防护:XSS过滤、SQL注入防护、CSRF防御的综合方案
- 移动端适配:基于Vue的响应式设计与微信小程序同步开发
对于类似系统的开发者,我的建议是:
- 提前规划好数据模型,特别是多对多关系的处理
- 设计灵活的权限系统,预留扩展空间
- 重视文件管理需求,尽早确定存储方案
- 做好性能测试,特别是高并发场景
- 建立完善的监控体系,便于问题排查
