基于SpringBoot的选课调查系统是一个实用的教育管理工具。
一、系统架构设计
- 技术栈选择
· 后端框架: SpringBoot 2.7+
· 安全框架: Spring Security + JWT
· 持久层: MyBatis-Plus / Spring Data JPA
· 数据库: MySQL 8.0
· 缓存: Redis
· 消息队列: RabbitMQ(可选,用于通知)
· 前端: Vue 3 + Element Plus / React + Ant Design
· 部署: Docker + Nginx
二、核心功能模块
- 用户管理模块
java
// 用户角色枚举
public enum UserRole {
STUDENT, // 学生
TEACHER, // 教师
ADMIN // 管理员
}
// 用户实体
@Entity
public class User {
@Id
private Long id;
private String username;
private String password;
private String realName;
private UserRole role;
private String email;
private String studentId; // 学号
private String department; // 院系
// ...
}
- 课程管理模块
java
@Entity
public class Course {
@Id
private Long id;
private String courseCode; // 课程代码
private String courseName; // 课程名称
private String description; // 课程描述
private Integer credit; // 学分
private Integer capacity; // 容量
private Integer enrolledCount; // 已选人数
private Long teacherId; // 授课教师
private String schedule; // 上课时间
private String location; // 上课地点
private Boolean isOpen; // 是否开放选课
// ...
}
- 调查问卷模块(核心)
java
@Entity
public class Survey {
@Id
private Long id;
private String title; // 调查标题
private String description; // 调查描述
private Long courseId; // 关联课程
private Date startTime; // 开始时间
private Date endTime; // 结束时间
private Boolean isAnonymous; // 是否匿名
private SurveyStatus status; // 状态
// ...
}
// 调查问题
@Entity
public class SurveyQuestion {
@Id
private Long id;
private Long surveyId;
private String content; // 问题内容
private QuestionType type; // 问题类型
private Integer orderNum; // 排序
private Boolean required; // 是否必答
// 选择题选项
@ElementCollection
private List<String> options;
}
// 问题类型枚举
public enum QuestionType {
SINGLE_CHOICE, // 单选题
MULTIPLE_CHOICE, // 多选题
TEXT, // 文本题
RATING, // 评分题
LIKERT_SCALE // 李克特量表
}
- 选课与调查结果模块
java
// 选课记录
@Entity
public class CourseSelection {
@Id
private Long id;
private Long studentId;
private Long courseId;
private Date selectTime;
private SelectionStatus status;
// ...
}
// 调查回答
@Entity
public class SurveyResponse {
@Id
private Long id;
private Long surveyId;
private Long studentId;
private Long questionId;
private String answer; // 回答内容(JSON格式)
private Date submitTime;
// ...
}
三、API接口设计示例
- 课程相关API
java
@RestController
@RequestMapping("/api/courses")
public class CourseController {
// 获取可选课程列表
@GetMapping("/available")
public Result<List<CourseVO>> getAvailableCourses(
@RequestParam(required = false) String keyword) {
// ...
}
// 选课
@PostMapping("/{courseId}/select")
public Result selectCourse(@PathVariable Long courseId) {
// ...
}
// 退选
@PostMapping("/{courseId}/drop")
public Result dropCourse(@PathVariable Long courseId) {
// ...
}
}
- 调查问卷API
java
@RestController
@RequestMapping("/api/surveys")
public class SurveyController {
// 创建调查问卷
@PostMapping
public Result createSurvey(@RequestBody SurveyDTO surveyDTO) {
// ...
}
// 提交调查问卷
@PostMapping("/{surveyId}/submit")
public Result submitSurvey(@PathVariable Long surveyId,
@RequestBody List<AnswerDTO> answers) {
// ...
}
// 获取调查结果统计
@GetMapping("/{surveyId}/statistics")
public Result<SurveyStatistics> getStatistics(@PathVariable Long surveyId) {
// ...
}
}
四、数据库设计
核心表结构
sql
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE,
password VARCHAR(100),
role ENUM('STUDENT', 'TEACHER', 'ADMIN'),
real_name VARCHAR(50),
student_id VARCHAR(20),
department VARCHAR(100),
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 课程表
CREATE TABLE courses (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
course_code VARCHAR(20) UNIQUE,
course_name VARCHAR(100),
teacher_id BIGINT,
credit INT,
capacity INT,
enrolled_count INT DEFAULT 0,
is_open BOOLEAN DEFAULT true,
schedule VARCHAR(200),
location VARCHAR(100)
);
-- 调查问卷表
CREATE TABLE surveys (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
course_id BIGINT,
title VARCHAR(200),
description TEXT,
start_time DATETIME,
end_time DATETIME,
is_anonymous BOOLEAN DEFAULT false,
status ENUM('DRAFT', 'PUBLISHED', 'CLOSED'),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
-- 调查问题表
CREATE TABLE survey_questions (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
survey_id BIGINT,
content TEXT,
type ENUM('SINGLE_CHOICE', 'MULTIPLE_CHOICE', 'TEXT', 'RATING', 'LIKERT_SCALE'),
order_num INT,
required BOOLEAN DEFAULT true,
options JSON, -- 存储选择题选项
FOREIGN KEY (survey_id) REFERENCES surveys(id)
);
五、关键业务流程
-
选课流程
学生登录 → 查看可选课程 → 选择课程 → 校验容量 → 生成选课记录 → 更新课程人数
-
调查流程
教师创建调查 → 设置调查时间 → 发布调查 →
学生填写调查 → 提交答案 → 系统统计结果 → 教师查看报告
六、特色功能实现
- 智能冲突检测
java
@Service
public class CourseConflictService {
public boolean hasScheduleConflict(Long studentId, Course newCourse) {
// 获取学生已选课程
List<Course> selectedCourses = courseService.getSelectedCourses(studentId);
// 检查时间冲突
return selectedCourses.stream()
.anyMatch(course -> isTimeOverlap(course.getSchedule(), newCourse.getSchedule()));
}
private boolean isTimeOverlap(String schedule1, String schedule2) {
// 解析上课时间格式,如 "周一 1-2节, 周三 3-4节"
// 判断是否有时间重叠
// ...
}
}
- 调查数据分析
java
@Service
public class SurveyAnalysisService {
// 生成调查统计报告
public SurveyReport generateReport(Long surveyId) {
SurveyReport report = new SurveyReport();
// 1. 参与率统计
report.setParticipationRate(calculateParticipationRate(surveyId));
// 2. 问题统计(选择题)
Map<Long, QuestionStatistics> questionStats =
calculateQuestionStatistics(surveyId);
// 3. 文本题关键词提取
List<TextAnalysis> textAnalysis = analyzeTextResponses(surveyId);
// 4. 生成可视化数据
report.setChartsData(generateChartsData(questionStats));
return report;
}
}
- 自动通知提醒
java
@Component
public class NotificationService {
@Scheduled(cron = "0 0 9 * * ?") // 每天9点执行
public void sendSurveyReminders() {
// 查找即将结束的调查
List<Survey> endingSurveys = surveyService.findSurveysEndingSoon();
endingSurveys.forEach(survey -> {
// 获取未填写的学生
List<User> uncompletedStudents =
findUncompletedStudents(survey.getId());
// 发送邮件或站内信提醒
uncompletedStudents.forEach(student ->
sendReminder(student, survey));
});
}
}
七、系统安全考虑
- 身份认证: JWT token认证
- 权限控制: 基于角色的访问控制
- 数据安全: 敏感信息加密存储
- 防重复提交: Token机制防止调查重复提交
- 防SQL注入: MyBatis参数化查询
八、部署方案
yaml
# docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: course_survey
redis:
image: redis:alpine
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf