
简介面向高校计算机专业毕业设计场景一份基于Java的学生成绩管理系统完整毕业设计包适合需要完成课设或快速搭建Web应用项目的学生。资源包含Java源代码、SQL数据库脚本、部署文档与部署视频覆盖成绩录入、查询、统计与分析等核心模块并体现MVC设计模式、JDBC数据库连接、Servlet与JSP开发等关键知识点可辅助理解从编码到部署的全流程。包体共9个文件以mp4操作演示与部署录屏为主配合sql脚本、doc文档及两个txt说明整体约122.79MB。其中4个视频分别展示系统功能演示、项目部署运行、代码结构讲解及中文乱码问题处理对实操落地较有参考价值。当前已有662人学习下载资源目录分工明确便于按源码、文档、SQL、视频分模块查阅。通过对照源码与视频读者可掌握Java Web项目开发、数据库表设计、服务器部署及常见运行问题排查思路省去从零摸索的时间是一份可直接用于答辩参考和二次开发的实用资料。1. 这套基于 Java 的学生成绩管理系统先搞清楚它解决什么“学生成绩管理系统”在毕业设计里是典型的“看着简单、做起来全是事”的题目代码量不大但涉及数据库、前后端、部署三条链路。这套基于 Java 的毕业设计资源把源代码、数据库脚本、部署文档和部署视频打成一个 zip核心目标只有一个让你在有限工期里拿到一个能启动、能演示、能答辩的系统。它适合三类人要交毕设的应届生、想拿现成工程改业务逻辑的课程设计者、以及想快速验证想法但不想从零搭环境的开发者。值不值得用不取决于代码多新而取决于你能不能把一个“学生增删改查”讲成完整的数据闭环。下面按我实际做过这类项目的顺序把技术选型、核心代码、部署链路和最容易翻车的点拆给你。2. 先把地基打好技术选型与成绩管理系统的数据库设计2.1 为什么这套 Java 毕设最常见的组合是 Spring Boot MyBatis MySQL你在网上下载的 Java 学生成绩管理系统源码十有八九是 Spring Boot MyBatis MySQL 的组合这不是巧合。Spring Boot 内嵌 Tomcat不用再单独装一个 Tomcat 去部署 war 包配置集中在application.yml比传统 SSM 的多个 XML 配置好维护得多启动就是一个main方法演示现场不容易出幺蛾子。对毕设答辩来说老师问“项目怎么跑起来的”你能很清楚地讲出“Spring Boot 启动内嵌容器自动装配数据源”这在原理层面站得住脚。持久层选 MyBatis 而不是 JPA核心理由是 SQL 可控。成绩系统最常被问到的就是“按课程统计平均分”“按分数段查人数”这类带聚合的查询把这些 SQL 写在 Mapper XML 里逻辑直白面试时也好展开。如果你图省事用 MyBatis-Plus它确实能根据实体类自动生成建表语句也能少写大量单表 CRUD但我的建议是毕设里不要过度依赖这种代码生成因为答辩老师一旦追问“这张表的关联关系怎么设计的”你答不上来亮点反而变成减分项。MySQL 版本没有严格要求5.7 和 8.0 都行。但要注意 8.0 的默认认证插件是caching_sha2_password如果你手里的驱动是 5.x 的老版本启动时会有“Communications link failure”一类的问题这个坑我放到后面避坑章节详细说。总之这套组合覆盖面广、资料多、部署资料好找是最稳妥的路线。2.2 五张核心表的设计用户、学生、教师、课程与成绩的关系很多新手一上来就给成绩表里直接塞“课程名”“学生姓名”这种冗余字段这是典型的反范式设计。正确做法是把学生、教师、课程拆成独立表成绩表只存外键 ID。以我常用的设计为例核心是sys_user登录账号、student学生、teacher教师、course课程、score成绩五张表其中score是学生和课程的多对多关联表。完整的建库建表脚本如下CREATE DATABASE IF NOT EXISTS student_score DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE student_score; CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT 密码存MD5或BCrypt, role VARCHAR(20) NOT NULL COMMENT admin/teacher/student, real_name VARCHAR(50) DEFAULT NULL COMMENT 姓名冗余自业务表 ) ENGINEInnoDB COMMENT 系统用户表; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(50) NOT NULL, gender VARCHAR(10) DEFAULT 男, class_name VARCHAR(50) COMMENT 班级如计算机2101, major VARCHAR(50) COMMENT 专业, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB COMMENT 学生表; CREATE TABLE teacher ( id INT PRIMARY KEY AUTO_INCREMENT, teacher_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, name VARCHAR(50) NOT NULL, title VARCHAR(30) COMMENT 职称如副教授 ) ENGINEInnoDB COMMENT 教师表; CREATE TABLE course ( id INT PRIMARY KEY AUTO_INCREMENT, course_no VARCHAR(20) NOT NULL UNIQUE COMMENT 课程编号, course_name VARCHAR(100) NOT NULL, credit DECIMAL(3,1) DEFAULT 2.0 COMMENT 学分, teacher_id INT COMMENT 授课教师ID, CONSTRAINT fk_course_teacher FOREIGN KEY (teacher_id) REFERENCES teacher(id) ) ENGINEInnoDB COMMENT 课程表; CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, score DECIMAL(5,2) COMMENT 成绩如85.50, semester VARCHAR(20) COMMENT 学期如2024-2025-1, exam_date DATE, CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student(id), CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course(id), UNIQUE KEY uk_student_course (student_id, course_id) ) ENGINEInnoDB COMMENT 成绩表;这段脚本里有几个设计点需要说明答辩时也经常被问到。sys_user承担登录认证role区分管理员、教师、学生三种身份角色权限如果不复杂不用单独建角色表一个字段足够。score表中没有直接写课程名而是用course_id关联这样课程改名后历史成绩不受影响。UNIQUE KEY uk_student_course保证同一个学生同一门课程只能有一条成绩记录这是业务上必须的约束。初始化数据方面我建议至少插入一个管理员账号和几条演示数据这样系统第一次启动就不会是空页面。管理员密码用 MD5 存储是毕设里的常见做法123456的 MD5 值是e10adc3949ba59abbe56e057f20f883e登录校验时对输入密码做同样的 MD5 再比对即可。如果你用 BCrypt那就不需要关心固定值但引入的依赖会多一些。2.3 初始化脚本的正确姿势先导数据还是先启动程序不少第一次接触这类系统的同学拿到 SQL 文件后不知道该先导数据库还是先启动程序。正确顺序是先创建数据库和表再启动 Spring Boot 项目。因为项目启动时 MyBatis 会检查 Mapper XML 里的 SQL 对应表是否存在表不存在会导致启动报错。导入命令很简单mysql -uroot -p init.sql执行后可以用SHOW TABLES;确认五张表都在。这里顺便说一句Mysql 数据库常用命令里SHOW CREATE TABLE score;比DESC score;信息更全能直接看到外键约束和索引定义排查表结构问题时优先用前者。如果你需要修改表结构比如给student表加一个email字段ALTER TABLE student ADD COLUMN email VARCHAR(100) DEFAULT NULL;注意这种“改表结构”的操作改完以后实体类和 Mapper 里的字段要同步更新否则程序运行时会报找不到列这个我在避坑章节再展开。3. 核心代码落地从登录到成绩增删改查的最小可运行版本3.1 工程骨架与依赖先让项目在你电脑上启动拿到源码后第一件事不是读业务代码而是让项目完整启动起来。我一般先把工程结构扫一遍确认是不是标准的 Maven 结构src/main/java/com/example/score/ ├── controller/ # 接口层UserController, StudentController, ScoreController ├── service/ # 业务层接口 impl ├── mapper/ # MyBatis Mapper接口 ├── entity/ # 实体类Student, Course, Score, SysUser └── config/ # 登录拦截器、CORS配置等 src/main/resources/ ├── mapper/ # Mapper XML文件 ├── application.yml # 数据源配置 └── init.sql # 建库建表脚本核心依赖就三样Spring Boot Web、MyBatis Starter、MySQL 驱动。pom.xml关键部分如下parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency /dependenciesSpring Boot 2.7.x 是当前兼容性最稳的版本线搭配 JDK 8 不会出现模块化系统报错。MyBatis Starter 选 2.3.x 完全够用。MySQL 驱动在 Spring Boot 2.7 里用mysql-connector-j这个新坐标旧坐标mysql-connector-java也能被管理但新项目建议用新坐标。数据源配置集中在application.ymlserver: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/student_score?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 你自己的密码 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.score.entityurl里的参数不是随便加的。characterEncodingutf8解决中文乱码serverTimezoneAsia/Shanghai解决 MySQL 8 的时区报错allowPublicKeyRetrievaltrue解决 MySQL 8 认证时需要公钥的警告useSSLfalse关掉 SSL 警告。没有这些参数项目在 JDK 8 MySQL 8 的环境下很容易启动失败。3.2 登录接口与权限过滤器的实现用户登录是成绩管理系统的第一道门通常用 Session 保存登录状态配合一个拦截器拦截未登录请求。先看登录接口RestController RequestMapping(/api/user) public class UserController { Resource private SysUserService sysUserService; PostMapping(/login) public Result login(RequestBody SysUser loginUser, HttpSession session) { SysUser user sysUserService.login(loginUser.getUsername(), loginUser.getPassword()); if (user null) { return Result.error(用户名或密码错误); } session.setAttribute(loginUser, user); return Result.success(user); } }这里login方法只做两件事调用 Service 查用户成功就写入 Session。密码比较逻辑在 Service 层做典型实现是对传入密码做 MD5再和库里的值比对避免在 Controller 里塞业务代码。Result是一个统一返回对象包含code、msg、data三个字段后续所有接口都复用。拦截器的作用是保护需要登录的接口。以学生管理为例未登录用户不能访问public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); SysUser user (SysUser) session.getAttribute(loginUser); if (user null) { response.setStatus(401); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\msg\:\未登录\}); return false; } return true; } }注册拦截器时要指定路径规则常见做法是/api/**全部拦截登录和退出接口放行。还有一点容易漏如果前端用了前后端分离的跨域请求还需要在配置类里放开 CORS否则本地调试时浏览器会把请求拦截掉。3.3 成绩 CRUD从查询到录入的完整代码成绩管理是这个项目的业务核心覆盖增删改查四类操作。先定义实体类字段和数据库表一一对应public class Score { private Integer id; private Integer studentId; private Integer courseId; private BigDecimal score; private String semester; private Date examDate; // getter/setter 略 }Mapper 接口不做复杂事情声明五个方法即可public interface ScoreMapper { ListScore selectByCondition(ScoreQuery query); Score selectById(Integer id); int insert(Score score); int update(Score score); int deleteById(Integer id); }对应的 XML 映射文件mapper namespacecom.example.score.mapper.ScoreMapper sql idbaseColumns id, student_id, course_id, score, semester, exam_date /sql select idselectByCondition resultTypecom.example.score.entity.Score SELECT include refidbaseColumns/ FROM score where if teststudentId ! null AND student_id #{studentId} /if if testcourseId ! null AND course_id #{courseId} /if if testminScore ! null AND score gt; #{minScore} /if if testmaxScore ! null AND score lt; #{maxScore} /if /where ORDER BY id DESC /select insert idinsert parameterTypecom.example.score.entity.Score INSERT INTO score(student_id, course_id, score, semester, exam_date) VALUES(#{studentId}, #{courseId}, #{score}, #{semester}, #{examDate}) /insert update idupdate parameterTypecom.example.score.entity.Score UPDATE score SET score #{score}, semester #{semester}, exam_date #{examDate} WHERE id #{id} /update delete iddeleteById parameterTypeint DELETE FROM score WHERE id #{id} /delete /mapper这段 XML 里有几个细节要说明。where标签会自动处理动态条件第一个条件前面的AND会被去掉这是 MyBatis 的经典用法比手工拼接字符串安全得多。score gt; #{minScore}里的gt;是 XML 转义的大于号不能直接写。#{studentId}是预编译占位符能防止 SQL 注入这是毕设答辩时值得主动讲的点。写库操作要加上事务注解否则半途出错会留下脏数据Service public class ScoreServiceImpl implements ScoreService { Resource private ScoreMapper scoreMapper; Override Transactional(rollbackFor Exception.class) public int saveScore(Score score) { if (score.getId() null) { return scoreMapper.insert(score); } return scoreMapper.update(score); } }Transactional的意思是方法内所有数据库操作同生共死任何一个抛异常整组操作回滚。成绩录入这个场景如果涉及“插入成绩 更新学生总评”事务就非常必要。Controller 层的写法和其他模块类似注意成绩查询要支持按学号、课程、分数段过滤这正好对应热搜里常见的“数据库增删改查”基本功。一个更复杂一点的统计查询放到了最后一章那个可以作为答辩时的加分项。4. 部署链路从本地 IDE 到打包上线的完整参数清单4.1 本地跑通的最小参数配置很多同学下载源码后卡在第一步项目 import 进来了但运行按钮是灰的或者启动几秒就报错。最常见的原因是 JDK 和 Maven 版本对不上。启动前先执行两个命令确认环境java -version mvn -vJDK 版本要 1.8 或 11Maven 3.6 以上。如果你用的是 IDEA打开项目后要确认 Project Structure 里 Project SDK 选到了本机 JDK不要默认选一个不存在的 SDK。Maven 的 settings.xml 里建议配置阿里云镜像不然第一次拉依赖会非常慢这个不算玄学是网络环境的实际问题。配置文件里的数据库密码和端口要改成你自己的。改完以后直接运行启动类Application看到日志里有Tomcat started on port(s): 8080就说明系统已经起来了。浏览器访问http://localhost:8080能打开登录页本地链路就算通了。4.2 打包成可交付的 jar命令与绕过测试的时机本地跑通以后下一步是把项目打包成可独立运行的 jar。这一步在部署文档里通常只有一句命令但它对新手来说很容易翻车。我常用的命令是mvn clean package -DskipTestsclean会删除上次构建的target目录-DskipTests跳过测试用例执行。这里说明一下跳过测试不代表不编译测试代码只是不运行如果你的工程里没有写测试类加不加这个参数没区别。如果确实有测试类且依赖外部数据库启动测试时会连不上库导致打包失败所以-DskipTests在本地临时交付时是安全的做法。打包完成后target目录下会生成一个xxx-0.0.1-SNAPSHOT.jar。运行它只需要 JDK不需要 Mavenjava -jar target/score-system-0.0.1-SNAPSHOT.jar如果你发现端口被占用启动时指定新端口java -jar target/score-system-0.0.1-SNAPSHOT.jar --server.port8081命令行参数优先级高于配置文件这个技巧在演示现场设备环境不可控时非常有用。4.3 部署到 Linux 服务器后台运行与日志排查如果把系统部署到云服务器用java -jar前台运行是不够的因为 SSH 窗口一关进程就没了。常见的做法是配合nohup命令让进程在后台持久运行nohup java -jar score-system-0.0.1-SNAPSHOT.jar \ --spring.datasource.urljdbc:mysql://localhost:3306/student_score?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue \ --spring.datasource.usernameroot \ --spring.datasource.password你的密码 \ app.log 21 这段命令里nohup让进程忽略挂断信号 app.log 21把标准输出和错误输出都写到app.log最后的是放到后台执行。服务器上 MySQL 的连接地址如果是本机写localhost就行如果是云数据库要改成云数据库的内网或公网地址。启动后一定要看一眼日志确认不是假启动tail -f app.log看到Started Application才算成功。很多线上事故都是“进程在服务没起来”这时的日志排查比前端界面可靠得多。如果服务器有安全组或 iptables 规则记得把 8080 端口放行否则外部访问不通。部署文档和部署视频在这个环节的作用是查漏补缺而不是让你照着抄。我的习惯是先把视频里涉及环境变量的段落看到位比如“PATH 里有没有 JDK”再直接操作比一步步暂停播放效率高。部署视频更适合处理“文档没说清、但我这一步卡住了”的局部问题。5. 常见问题与避坑让毕设现场翻车的 5 个真实场景5.1 启动就报 Communications link failure现象项目启动后控制台出现Communications link failure或Access denied for user rootlocalhost应用直接退出。第一次遇到的人很容易怀疑人生因为代码还没跑起来就死在数据源上。原因要么是数据库连接参数不对要么是 MySQL 8 的认证插件和老驱动的兼容性问题。Communications link failure通常是端口填错、MySQL 没启动、或者 URL 里主机地址不对Access denied则是用户名或密码错误。MySQL 8 默认认证插件是caching_sha2_password如果驱动是 5.x握手协议不一致也会连不上。解决先用命令行确认 MySQL 能连mysql -uroot -p能进去说明数据库本身没问题问题就在连接参数。然后检查application.yml里的 URL、用户名、密码是否和本机一致。如果是 MySQL 8 老驱动要么把驱动升级到mysql-connector-j8.x要么在 MySQL 里执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;5.2 页面和数据库里全是问号现象系统能跑但登录后页面上的中文全是?数据库里插入的学生姓名也是???。这个在本地开发时最容易遇到因为很多人安装 MySQL 时会按默认选项来字符集不是utf8mb4。原因建库时没有指定字符集MySQL 默认用了latin1中文存不进去。另一条原因是 JDBC URL 里缺少characterEncodingutf8客户端和服务器之间的字符集协商不对。解决先看数据库字符集SHOW CREATE DATABASE student_score;如果显示不是utf8mb4执行修改结构ALTER DATABASE student_score CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;同时把表也转换ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;改完后再检查 JDBC URL 是否带characterEncodingutf8。这两处都对了中文乱码问题基本绝迹。5.3 Invalid bound statement (not found)现象项目启动正常但访问/api/score/list时报Invalid bound statement (not found): com.example.score.mapper.ScoreMapper.selectByCondition。原因这是 MyBatis 的老熟人问题。Mapper 接口方法名和 XML 里的id对不上或者 XML 的namespace写错或者 XML 文件压根没有被打进target/classes。解决先检查 Mapper 接口的方法名和 XML 里的select标签的id是否一致这是 90% 的原因。再检查 XML 文件头部的namespace是否写的是接口全限定名。如果上面都对执行一次mvn clean把旧的 target 清掉再重新启动因为有时 XML 没有同步到编译目录clean 后就会强制刷新。5.4 用数据库工具改了表结构后程序一直报列不存在现象用 Navicat 或命令行给student表加了一个字段重启程序后调用相关接口反而报Unknown column email in field list或映射失败。不少人会以为是 MyBatis 的“玄学”缓存问题。原因数据库改了表但实体类和 Mapper SQL 没有同步。比如你在数据库层加了email列实体类里没有email字段MyBatis 的 resultMap 不会自动映射新列查询时如果SELECT *拿到多余列并不会报错但反向操作如 insert 语句没写这个字段就会出现字段缺失或参数不对的问题。解决数据库修改和代码修改必须捆绑进行。给表加列同时给实体类加对应属性、给 Mapper XML 的 insert/update 语句加字段。这也是为什么我建议毕设里所有表结构变更先改 SQL 脚本再统一执行不要直接在上线的库里动手。改完以后重启应用不重启的话运行中的连接池拿到的元数据可能还是旧状态。5.5 打包没问题java -jar 启动后立刻退出或端口冲突现象mvn package执行成功但java -jar启动一两秒就退出或者直接提示Port 8080 was already in use。前者在 IDEA 里看可能不明显在服务器上很直接。原因端口冲突常见于本机多个演示项目同时跑启动后立刻退出则要去看日志十有八九是数据源配置不对或者 JDK 版本和编译版本不一致。比如代码用 JDK 8 编译服务器用 JDK 17 运行会抛UnsupportedClassVersionError。解决先处理端口问题最方便的是换端口启动java -jar score-system.jar --server.port8081端口占用也可以查是被谁占的Windows 下netstat -ano | findstr 8080然后决定是否释放。版本问题用java -version确认服务器 JDK 版本尽量和本机保持一致。6. 交差前必做的两件小事数据核对与统计接口加分6.1 用一条 SQL 找出脏数据系统跑通后强烈建议做一次数据一致性验证。你可以在 Navicat 或命令行里执行这条 SQL找出“成绩表里引用了不存在学生”的脏数据SELECT s.id, s.student_id FROM score s LEFT JOIN student stu ON s.student_id stu.id WHERE stu.id IS NULL;如果结果为空说明成绩和学生的关联是干净的如果查出数据说明删除学生时没有同步删除成绩或者外键约束没建成功。这个检查是答辩演示前的一颗定心丸我在交付这类系统时必做。6.2 再顺手加一个统计接口当答辩亮点系统功能完整但不一定要有新意加一个轻量统计功能就能让答辩内容厚一点。比如按课程统计平均分、最高分和选课人数SELECT c.course_name, AVG(s.score) AS avg_score, MAX(s.score) AS max_score, COUNT(s.id) AS student_count FROM score s JOIN course c ON s.course_id c.id GROUP BY c.course_name;在 Service 层加对应方法Controller 里加一个/api/score/stat/course接口前端页面展示成一个简单表格。这个功能代码量不大但涉及表连接、聚合函数和分组恰好覆盖了数据库课程里最核心的知识点老师问起来你有得讲。我每次交这类带数据库的项目前都会把“新增学生→选课→录成绩→改成绩→删除学生”的完整链路自己走一遍再跑一遍上面的脏数据检查。这个习惯帮我挡掉过不少次演示现场翻车也让我在答辩时能理直气壮地说“这个系统数据是干净的”。希望帮到你。本文还有配套的精品资源点击获取