1. 项目背景与核心功能
这个选题管理系统是一个典型的教学管理类Web应用,采用目前主流的SpringBoot+Vue前后端分离架构。我在实际开发教育类系统时发现,课程选题管理是高校课程设计中长期存在的痛点——传统Excel表格管理方式存在版本混乱、权限管控难、数据统计不便等问题。
系统主要解决三个核心场景:
- 教师端:发布课程设计选题、审核学生选题、查看选题统计
- 学生端:浏览可选题目、提交选题申请、查看审核状态
- 管理员端:用户权限管理、系统参数配置、数据备份导出
提示:这类管理系统开发时最容易忽视院系-专业-班级的多级关联关系,建议在数据库设计阶段就建立完善的层级模型。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈选型解析
2.1 后端技术组合
SpringBoot 2.7.x + MyBatis-Plus的组合是经过多个教育项目验证的稳定方案:
- 采用Lombok减少样板代码(实测节省30%编码量)
- 使用Hutool工具类处理日期/字符串转换
- 接口文档使用Knife4j替代原生Swagger(教学场景下文档可读性更重要)
数据库选型MySQL 8.0而非5.7的原因:
- 窗口函数便于生成选题统计报表
- JSON字段支持存储动态表单配置
- 更好的UTF-8mb4支持(存储学生姓名中的生僻字)
2.2 前端架构设计
Vue 3.x + Element Plus的组合考虑:
- 采用Composition API写法提升代码组织性
- 使用Vite构建速度比Webpack快3-5倍(对教学演示很关键)
- 特别添加了ECharts用于可视化选题分布
javascript复制// 典型API请求示例
const fetchTopics = async () => {
loading.value = true
try {
const res = await axios.get('/api/topics', {
params: { page: pagination.value.page }
})
topicList.value = res.data.records
} finally {
loading.value = false
}
}
3. 数据库关键设计
3.1 核心表结构
sql复制CREATE TABLE `sys_topic` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL COMMENT '选题名称',
`description` text COMMENT '详细要求',
`teacher_id` bigint NOT NULL,
`max_students` int DEFAULT '1' COMMENT '最大可选人数',
`selected_count` int DEFAULT '0',
`status` tinyint DEFAULT '0' COMMENT '0未审核 1已审核',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 性能优化要点
- 在selection_record表建立(student_id, topic_id)联合唯一索引
- 为status字段添加普通索引(列表页过滤条件)
- 使用触发器自动更新selected_count字段
踩坑提醒:MySQL 8.0默认的caching_sha2_password认证方式会导致部分旧客户端连接失败,建议开发环境改用mysql_native_password
4. 典型业务逻辑实现
4.1 选题申请流程
java复制@Transactional
public Result applyTopic(Long studentId, Long topicId) {
// 校验选题是否存在且未满员
SysTopic topic = topicMapper.selectById(topicId);
if (topic == null || topic.getStatus() != 1) {
return Result.fail("选题不可选");
}
if (topic.getSelectedCount() >= topic.getMaxStudents()) {
return Result.fail("该选题已满");
}
// 检查是否重复申请
LambdaQueryWrapper<SelectionRecord> wrapper = new LambdaQueryWrapper<>()
.eq(SelectionRecord::getStudentId, studentId)
.eq(SelectionRecord::getTopicId, topicId);
if (selectionMapper.selectCount(wrapper) > 0) {
return Result.fail("请勿重复申请");
}
// 创建申请记录
SelectionRecord record = new SelectionRecord();
record.setStudentId(studentId);
record.setTopicId(topicId);
record.setApplyTime(LocalDateTime.now());
selectionMapper.insert(record);
return Result.success();
}
4.2 批量导入优化
使用EasyExcel处理Excel导入时,要注意:
- 添加@ExcelIgnoreUnannotated防止字段映射错误
- 使用监听器模式处理大数据量导入
- 在finally块中删除临时文件
5. 部署与运行指南
5.1 环境准备
后端要求:
- JDK 17(实测11会有反射警告)
- Maven 3.8+
- MySQL 8.0(需提前执行schema.sql)
前端要求:
- Node.js 16+
- 建议使用yarn安装依赖(npm有时会报peer依赖错误)
5.2 常见启动问题
- 端口冲突:修改application.yml中的server.port
- 数据库连接失败:检查spring.datasource配置
- Vue跨域问题:配置proxyTable或使用Nginx反向代理
yaml复制# 典型配置示例
spring:
datasource:
url: jdbc:mysql://localhost:3306/topic_db?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
6. 扩展开发建议
- 添加WebSocket通知功能(选题状态变更实时提醒)
- 集成Redis缓存热门选题数据
- 开发微信小程序端(使用uni-app跨平台方案)
- 使用Quartz实现定时备份选题数据
我在实际部署时发现,教学场景下特别需要导出PDF格式的选题汇总表。推荐使用itext7配合Thymeleaf模板生成,比POI更稳定且格式更精美。具体实现时要注意中文字体嵌入问题,建议将思源宋体ttf文件放在resources/fonts目录下。
