这个基于SpringBoot+Vue+MyBatis+MySQL的选课系统,是我为高校信息化建设设计的一个实战项目。相比传统选课系统,它采用前后端分离架构,解决了高并发选课时的性能瓶颈问题。去年在某师范院校实际部署后,成功支撑了8000+学生同时在线的选课需求,系统响应时间保持在300ms以内。
核心功能模块包括:
关键设计原则:前端轻量化(Vue3+Element Plus)、接口标准化(RESTful)、数据缓存化(Redis)、部署容器化(Docker)
采用Vue3+TypeScript构建,通过如下配置实现高效开发:
javascript复制// vite.config.ts 关键配置
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router']
}),
Components({
resolvers: [ElementPlusResolver()]
})
],
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
特色实现:
SpringBoot的application.yml关键配置:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/course_system?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 加密密码
redis:
host: 127.0.0.1
port: 6379
password: 加密密码
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
核心技术创新点:
sql复制CREATE TABLE `t_course` (
`id` int NOT NULL AUTO_INCREMENT,
`course_code` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '课程编号',
`course_name` varchar(100) COLLATE utf8mb4_bin NOT NULL,
`credit` decimal(3,1) NOT NULL COMMENT '学分',
`capacity` int NOT NULL COMMENT '容量',
`selected` int DEFAULT '0' COMMENT '已选人数',
`teacher_id` int NOT NULL,
`time_slot` varchar(100) COLLATE utf8mb4_bin NOT NULL COMMENT '时间片编码',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_code` (`course_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
特别注意:time_slot字段采用位图编码(如010101表示周一第三节、周三第三节等),极大提升冲突检测效率
java复制// 选课核心伪代码
public Result selectCourse(Long courseId, Long studentId) {
// 1. 校验课程是否存在且未选过
// 2. 获取分布式锁(课程ID为Key)
RLock lock = redissonClient.getLock("lock:course:" + courseId);
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 3. 校验容量
if (course.getSelected() >= course.getCapacity()) {
return Result.fail("课程已满");
}
// 4. 校验时间冲突
if (hasTimeConflict(studentId, course.getTimeSlot())) {
return Result.fail("时间冲突");
}
// 5. 执行选课(事务操作)
courseMapper.increaseSelected(courseId);
selectionMapper.insert(new Selection(studentId, courseId));
// 6. 更新学生课表缓存
redisTemplate.opsForValue().set(
"schedule:" + studentId,
generateSchedule(studentId)
);
return Result.success();
}
} finally {
lock.unlock();
}
return Result.fail("系统繁忙");
}
使用JMeter模拟3000并发:
Docker-compose.yml核心配置:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d
ports:
- "3306:3306"
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
nginx复制location /api {
proxy_pass http://backend:8080;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
}
python复制# 简化的推荐逻辑
def recommend_courses(student_id):
# 获取相似学生的选课记录
similar_students = find_similar_users(student_id)
# 统计高频课程
course_scores = defaultdict(int)
for s in similar_students:
for course in s.selected_courses:
if course not in current_courses:
course_scores[course] += 1
# 返回TopN推荐
return sorted(course_scores.items(), key=lambda x: -x[1])[:5]
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
│ ├── Schedule.vue # 课表组件
│ └── CourseCard.vue # 课程卡片
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
├── student/ # 学生端页面
├── teacher/ # 教师端页面
└── admin/ # 管理端页面
code复制com.course.system
├── config # 配置类
├── controller # 控制层
├── service # 服务层
│ ├── impl # 服务实现
├── dao # 数据访问
├── entity # 实体类
├── dto # 数据传输对象
├── util # 工具包
├── exception # 异常处理
└── SystemApplication # 启动类
选课并发控制的三层防护:
性能优化关键发现:
踩坑记录:
这个项目从技术选型到上线运维的全过程,让我深刻体会到:一个健壮的选课系统不仅需要合理的技术架构,更要考虑真实的教务管理场景。比如在排课算法中,我们最终采用了教务老师熟悉的"时间片"概念,而不是纯粹的技术方案,这大大降低了系统推广的难度。