1. 项目概述:SpringBoot+Vue+MySQL选课系统实战
这个学生网上选课系统采用目前主流的前后端分离架构,后端使用SpringBoot框架提供RESTful API接口,前端采用Vue.js构建用户界面,数据库选用MySQL进行数据存储。整套系统源码开箱即用,已经过完整测试可以直接运行,特别适合计算机相关专业学生作为课程设计或毕业设计项目参考。
我在实际开发教育类管理系统时发现,选课系统是最能体现典型业务场景的教学案例。它包含了用户权限管理、数据关联查询、事务处理等核心功能模块,同时业务逻辑清晰易懂。这个项目完整实现了学生选课、退课、课表查询等基础功能,教师端包含课程管理和成绩录入,管理员则负责系统用户管理和课程安排。
2. 技术栈深度解析
2.1 SpringBoot后端设计
后端采用SpringBoot 2.7.x版本构建,主要依赖包括:
- spring-boot-starter-web:提供Web MVC支持
- spring-boot-starter-data-jpa:简化数据库操作
- spring-boot-starter-security:处理权限认证
- lombok:减少样板代码
核心配置类说明:
java复制@SpringBootApplication
@EnableJpaAuditing
@EnableTransactionManagement
public class CourseSelectionApplication {
public static void main(String[] args) {
SpringApplication.run(CourseSelectionApplication.class, args);
}
}
数据库实体关系设计采用JPA注解方式,例如学生选课的多对多关系建模:
java复制@Entity
public class Student {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set<Course> selectedCourses = new HashSet<>();
}
2.2 Vue前端架构
前端使用Vue 3组合式API开发,主要技术特点:
- Vue Router处理页面路由
- Axios进行API请求
- Element Plus提供UI组件
- Pinia状态管理
典型API请求示例:
javascript复制import { defineStore } from 'pinia'
export const useCourseStore = defineStore('course', {
actions: {
async fetchAvailableCourses() {
return await axios.get('/api/courses/available')
},
async selectCourse(courseId) {
return await axios.post(`/api/student/select/${courseId}`)
}
}
})
2.3 MySQL数据库设计
数据库主要表结构设计:
sql复制CREATE TABLE `student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`student_no` varchar(20) NOT NULL,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_student_no` (`student_no`)
);
CREATE TABLE `course` (
`id` bigint NOT NULL AUTO_INCREMENT,
`course_code` varchar(20) NOT NULL,
`name` varchar(100) NOT NULL,
`credit` int NOT NULL,
`max_students` int NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_course_code` (`course_code`)
);
3. 核心功能实现细节
3.1 选课业务逻辑
选课服务层关键代码实现事务处理:
java复制@Service
@RequiredArgsConstructor
public class CourseSelectionService {
private final CourseRepository courseRepo;
private final StudentRepository studentRepo;
@Transactional
public void selectCourse(Long studentId, Long courseId) {
Course course = courseRepo.findById(courseId)
.orElseThrow(() -> new RuntimeException("课程不存在"));
if (course.getSelectedStudents().size() >= course.getMaxStudents()) {
throw new RuntimeException("课程人数已满");
}
Student student = studentRepo.findById(studentId)
.orElseThrow(() -> new RuntimeException("学生不存在"));
student.getSelectedCourses().add(course);
studentRepo.save(student);
}
}
3.2 权限控制方案
采用Spring Security + JWT实现权限控制:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/student/**").hasRole("STUDENT")
.antMatchers("/api/teacher/**").hasRole("TEACHER")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
return http.build();
}
}
4. 系统部署与运行
4.1 环境准备要求
- JDK 11+
- Node.js 16+
- MySQL 8.0+
- Maven 3.6+
4.2 数据库初始化
- 创建数据库:
sql复制CREATE DATABASE course_selection DEFAULT CHARACTER SET utf8mb4;
- 修改应用配置:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/course_selection
username: root
password: yourpassword
jpa:
hibernate:
ddl-auto: update
4.3 前端编译运行
bash复制# 安装依赖
npm install
# 开发模式运行
npm run dev
# 生产构建
npm run build
5. 常见问题解决方案
5.1 跨域问题处理
后端配置CORS支持:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
5.2 性能优化建议
- 课程列表分页查询:
java复制@GetMapping("/courses")
public Page<Course> getCourses(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return courseRepo.findAll(PageRequest.of(page, size));
}
- 添加Redis缓存:
java复制@Cacheable(value = "courses", key = "#id")
public Course getCourseById(Long id) {
return courseRepo.findById(id).orElse(null);
}
6. 项目扩展方向
- 添加选课冲突检测:
java复制public boolean hasTimeConflict(Course newCourse, Set<Course> existingCourses) {
return existingCourses.stream()
.anyMatch(c -> c.getSchedule().conflictsWith(newCourse.getSchedule()));
}
- 集成第三方登录:
java复制@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(
ClientRegistration.withRegistrationId("wechat")
.clientId("your-app-id")
.clientSecret("your-app-secret")
.scope("snsapi_login")
.authorizationUri("https://open.weixin.qq.com/connect/qrconnect")
.tokenUri("https://api.weixin.qq.com/sns/oauth2/access_token")
.userInfoUri("https://api.weixin.qq.com/sns/userinfo")
.userNameAttributeName("openid")
.clientName("WeChat")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
.build());
}
- 添加数据可视化看板:
javascript复制// 使用ECharts展示选课数据
import * as echarts from 'echarts'
const initChart = () => {
const chart = echarts.init(document.getElementById('chart'))
chart.setOption({
tooltip: {},
xAxis: { data: ['课程A', '课程B', '课程C'] },
yAxis: {},
series: [{ type: 'bar', data: [45, 30, 60] }]
})
}
