1. 项目背景与需求分析
高校教务管理一直是教育信息化建设的核心痛点。我在参与西安工商学院课表管理系统开发时,深刻体会到传统手工排课的三大顽疾:教务老师需要手动处理上百个班级的课程安排,经常出现教室冲突;教师查询课表需要到办公室登记;学生选课高峰期系统频繁崩溃。这种低效的运作模式显然无法满足现代化教学管理的需求。
经过实地调研,我们梳理出几个关键需求痛点:
- 多角色协同:需要同时满足管理员排课、教师查询、学生选课三类用户的不同操作需求
- 智能排课:要求系统能自动处理教室、教师、时间段的冲突检测
- 高并发保障:选课高峰期的系统稳定性直接影响教学秩序
- 数据可视化:校领导需要直观查看全校课程分布和资源利用率
2. 技术架构设计
2.1 整体架构方案
采用前后端分离架构是经过多次技术论证后的决定。这种架构模式相比传统单体应用有三个显著优势:
- 开发效率:前后端可以并行开发,通过API文档约定接口规范
- 性能优化:前端静态资源可通过CDN加速,后端专注业务逻辑
- 技术栈灵活:前后端可以独立选择最适合的技术方案
具体技术选型如下表所示:
| 层级 | 技术栈 | 选型理由 |
|---|---|---|
| 前端 | Vue.js + ElementUI | 组件化开发效率高,生态完善 |
| 后端 | SpringBoot 2.7 | 快速构建RESTful API,企业级支持 |
| ORM | MyBatis-Plus | 兼顾灵活性和开发效率 |
| 数据库 | MySQL 8.0 | 事务支持完善,高校场景数据量适中 |
| 缓存 | Redis 6 | 应对选课高峰期的并发访问 |
2.2 关键技术实现
2.2.1 JWT认证方案
采用JWT+Redis的双重认证机制解决传统Session方案的分布式问题。具体实现要点:
java复制// JWT生成示例
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
关键细节:设置合理的过期时间(建议2小时),配合Redis记录令牌状态,实现安全的强制下线功能。
2.2.2 智能排课算法
基于遗传算法改进的排课方案主要处理以下约束条件:
- 硬约束:教室容量、教师时间冲突、课程时间要求
- 软约束:教室距离、课程间隔等优化目标
算法核心流程:
- 初始化种群(随机生成可行解)
- 适应度计算(冲突检测)
- 选择、交叉、变异操作
- 迭代优化直至满足终止条件
3. 核心功能实现
3.1 数据库设计优化
3.1.1 主要表结构
用户表采用垂直分表设计,将基础信息与权限分离:
sql复制CREATE TABLE `sys_user` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8mb4_bin NOT NULL,
`password_hash` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`real_name` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
`role_type` tinyint NOT NULL COMMENT '0-学生 1-教师 2-管理员',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
3.1.2 索引优化
针对高频查询场景建立复合索引:
- 课表查询:
(teacher_id, week_range) - 选课操作:
(course_id, is_active)
3.2 后端关键代码
3.2.1 排课冲突检测
java复制@Transactional
public ScheduleResult createSchedule(ScheduleDTO dto) {
// 1. 基础校验
validateSchedule(dto);
// 2. 冲突检测
boolean isConflict = scheduleMapper.checkConflict(
dto.getTeacherId(),
dto.getClassTime(),
dto.getWeekRange(),
dto.getLocation());
// 3. 持久化
if(!isConflict) {
Schedule entity = new Schedule();
BeanUtils.copyProperties(dto, entity);
scheduleMapper.insert(entity);
}
return new ScheduleResult(!isConflict);
}
事务处理要点:@Transactional注解要明确指定rollbackFor异常类型,避免静默回滚。
3.3 前端交互实现
3.3.1 课表可视化
使用Vue+ECharts实现动态课表:
vue复制<template>
<div ref="chart" style="width:100%;height:400px"></div>
</template>
<script>
export default {
mounted() {
this.initChart();
},
methods: {
initChart() {
const chart = echarts.init(this.$refs.chart);
chart.setOption({
tooltip: {...},
visualMap: {...},
calendar: {...},
series: [...]
});
}
}
}
</script>
4. 系统部署方案
4.1 容器化部署
采用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6-alpine
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
4.2 性能调优
通过JMeter压测后实施的优化措施:
- Nginx配置静态资源缓存
- MySQL连接池参数优化
- Redis缓存热点数据
- 接口响应时间监控
5. 常见问题排查
5.1 典型问题汇总
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 选课提交失败 | 乐观锁冲突 | 增加重试机制 |
| 课表加载慢 | 未使用分页 | 实现后端分页查询 |
| JWT过期 | 令牌有效期设置过短 | 动态调整有效期 |
5.2 排课冲突误报
遇到一个典型案例:系统频繁报告物理实验室冲突,实际检查发现是课程表classroom_req字段的枚举值不一致。解决方法:
- 统一数据字典管理
- 增加字段值校验逻辑
- 完善冲突检测日志
6. 项目总结与扩展
在实际部署运行半年后,系统日均处理3000+次课表查询,选课高峰期支持500+并发请求。有几个值得分享的经验:
- 缓存策略:课表数据采用两级缓存(Redis+本地缓存),缓存过期时间根据业务特点动态设置
- 监控体系:集成Prometheus监控关键指标,如接口响应时间、数据库连接池状态
- 扩展建议:后续可增加微信小程序端,方便师生移动端查询
对于想要二次开发的同学,建议重点关注智能排课算法的优化空间。现有的遗传算法在处理超大规模课程组合时(如全校性选修课)仍有性能瓶颈,可以考虑引入模拟退火等优化算法。