这个基于SpringBoot+Vue的学生成绩管理系统是我在指导毕业设计过程中总结出的一个典型教学案例。作为一个在高校和企业都有过开发经验的工程师,我深知成绩管理是教学管理中最基础也最繁琐的工作之一。传统的手工记录或单机版管理软件已经无法满足现代教学管理的需求,特别是在疫情后线上线下混合教学成为常态的背景下。
系统采用前后端分离架构,后端使用SpringBoot提供RESTful API接口,前端用Vue.js构建响应式界面,数据库选用MySQL 8.0。这种技术组合既保证了系统的稳定性和扩展性,又降低了学习曲线,特别适合作为计算机专业学生的毕业设计项目。
选择SpringBoot作为后端框架主要基于以下考虑:
实际开发中,我特别推荐使用SpringBoot 2.7.x版本,这个版本既稳定又兼容性强。对于学生成绩管理系统这种CRUD操作较多的应用,建议采用MyBatis-Plus作为ORM框架,它能极大简化单表操作代码。
Vue.js作为渐进式框架的优势在这个项目中体现得淋漓尽致:
特别提醒初学者:Vue 3.x虽然功能更强大,但考虑到生态兼容性,建议毕业设计项目先用Vue 2.6+版本。等熟悉了核心概念后再尝试Composition API等新特性。
MySQL 8.0相比5.7版本在性能和功能上都有显著提升:
数据库设计时需要注意:
系统采用经典的三层架构:
架构图中特别加入了Swagger用于API文档生成,这在团队协作开发时非常有用。前后端开发人员可以并行工作,只需约定好接口规范。
用户管理模块
成绩管理模块
统计分析模块
系统管理模块
成绩查询接口实现示例:
java复制@RestController
@RequestMapping("/api/score")
public class ScoreController {
@Autowired
private ScoreService scoreService;
@GetMapping
public Result list(
@RequestParam(required = false) String studentId,
@RequestParam(required = false) String courseId,
@RequestParam(required = false) String semester,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
Map<String, Object> params = new HashMap<>();
params.put("studentId", studentId);
params.put("courseId", courseId);
params.put("semester", semester);
PageUtils pageUtils = scoreService.queryPage(params, page, size);
return Result.ok().put("data", pageUtils);
}
}
这段代码展示了SpringBoot中如何实现一个带分页和多条件查询的RESTful接口。特别注意:
成绩录入组件关键部分:
vue复制<template>
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="学号" prop="studentId">
<el-input v-model="form.studentId"></el-input>
</el-form-item>
<el-form-item label="课程" prop="courseId">
<el-select v-model="form.courseId">
<el-option
v-for="course in courseList"
:key="course.id"
:label="course.name"
:value="course.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="成绩" prop="score">
<el-input-number
v-model="form.score"
:min="0"
:max="100"
:precision="1">
</el-input-number>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
studentId: '',
courseId: '',
score: null
},
rules: {
studentId: [{ required: true, message: '请输入学号' }],
courseId: [{ required: true, message: '请选择课程' }],
score: [{ required: true, message: '请输入成绩' }]
},
courseList: []
}
},
methods: {
submitForm() {
this.$refs.formRef.validate(valid => {
if (valid) {
this.$axios.post('/api/score', this.form)
.then(response => {
this.$message.success('成绩录入成功')
})
}
})
}
}
}
</script>
这个组件展示了Vue中表单处理的最佳实践:
学生表(student)
sql复制CREATE TABLE `student` (
`id` varchar(20) NOT NULL COMMENT '学号',
`name` varchar(50) NOT NULL COMMENT '姓名',
`gender` char(1) DEFAULT NULL COMMENT '性别',
`birthday` date DEFAULT NULL COMMENT '出生日期',
`class_id` varchar(20) DEFAULT NULL COMMENT '班级ID',
PRIMARY KEY (`id`),
KEY `idx_class` (`class_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
课程表(course)
sql复制CREATE TABLE `course` (
`id` varchar(20) NOT NULL COMMENT '课程编号',
`name` varchar(100) NOT NULL COMMENT '课程名称',
`credit` decimal(3,1) DEFAULT NULL COMMENT '学分',
`hours` int DEFAULT NULL COMMENT '学时',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
成绩表(score)
sql复制CREATE TABLE `score` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`student_id` varchar(20) NOT NULL COMMENT '学号',
`course_id` varchar(20) NOT NULL COMMENT '课程编号',
`semester` varchar(20) NOT NULL COMMENT '学期',
`score` decimal(5,2) DEFAULT NULL COMMENT '成绩',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_student_course` (`student_id`,`course_id`,`semester`),
KEY `idx_course` (`course_id`),
KEY `idx_semester` (`semester`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
索引策略:
事务处理:
java复制@Transactional
public void batchImport(List<Score> scores) {
for (Score score : scores) {
scoreDao.insert(score);
}
}
批量操作一定要放在事务中,确保数据一致性。
缓存设计:
后端环境:
前端环境:
数据库环境:
推荐使用Docker容器化部署:
后端Dockerfile:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/score-system.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
前端Dockerfile:
dockerfile复制FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
使用docker-compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- ./mysql/data:/var/lib/mysql
ports:
- "3306:3306"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
前后端分离开发时最常见的跨域问题解决方案:
后端配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
前端代理配置(vue.config.js):
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
}
后端优化:
前端优化:
数据库优化:
SQL注入防护:
XSS防护: