JavaWeb学生成绩管理系统:源码部署到增删改查改造实战

📅 发布时间:2026/10/4 1:21:36
JavaWeb学生成绩管理系统:源码部署到增删改查改造实战
简介一套面向JavaWeb初学者的学生成绩管理系统完整源码与数据库资源适合在校生、毕业设计及自学开发者使用。系统围绕成绩管理场景实现用户登录、学生信息维护、课程管理、成绩录入、查询与统计等模块代码采用MVC分层涉及Servlet、JSP和JDBC技术数据库包含学生表、课程表、成绩表并通过外键关联可帮助读者打通从表设计到页面交互的完整链路这种实现思路对初学者尤其友好。包内共353个文件含24个jsp页面、53个java源码、53个class文件、24个jar依赖、40个css样式及110张png图片等资源包大小约8.98MB文件类型较全方便按目录对照学习。已有1740人学习下载。从这套资源中可直接部署运行查看效果也可结合源码与数据库脚本梳理增删改查、会话管理和权限校验等典型写法适合课程设计参考和JavaWeb入门进阶。1. 拿到 javaweb学生成绩管理系统源码数据库.rar 之后先别急着点 index.jsp拿到一个javaweb学生成绩管理系统源码数据库.rar最常见的开场是解压、双击 index.jsp然后看着浏览器里的 404 发呆。我帮人调这类课程设计源码的次数不算少真正打不开的原因往往不是代码坏了而是环境没对齐JDK 版本、Tomcat 版本、MySQL 的驱动和字符集每一处都是坑。这个项目的价值其实不在“跑起来”本身而在于它把学生、课程、成绩、账号这几类数据组织成一套完整的增删改查闭环是 JavaWeb 三层架构和数据库设计最典型的小样本。这篇文章我按自己接手源码的顺序来讲先看懂表结构再在 IDEA 里把项目跑通最后改造成带着个人风格的课程设计。适合正在选 JavaWeb 选题、或者拿到源码想快速消化的人。2. 表和权限设计先看懂数据库结构再谈跑起来2.1 五个核心表是怎么把成绩管理串起来的我不急着看代码第一件事是打开.sql文件搜索CREATE TABLE数一数有几个表。这类学生成绩管理系统表多则七八张少则四五张但核心永远跑不出这五张学生表、课程表、成绩表、用户表外加一张班级或教师表。只要把这几张表的关系理清整个系统的增删改查就都能顺出来。学生表里最重要的字段是学号通常设唯一索引课程表里是课程编号同样唯一。成绩表则是连接前两者的关系表它不直接存学生姓名、课程名称只存student_id、course_id、分数和考试时间。这么做不是绕弯子是为了避免同一门课程名称改了、学生转班之后成绩数据跟着变脏。数据库课里讲的“第三范式”在这个项目里就是最基本的落点。用户表要单独建不要图省事把角色字段塞进学生表里。一个学生是一个自然人一个账号是登录凭证两者理论上应该分开。简单项目里用户表至少要有用户名、密码、角色admin、teacher、student三个字段再用一个ref_id指向学生表或教师表的主键。这样学生登录后能查出自己的基本信息教师登录后能定位到他所教的课程而不是把权限和业务数据揉在一起。2.2 建库 SQL 脚本字段类型和约束一次说清拿到源码后我习惯先按下面这套脚本把结构重建一遍不是为了丢开原库而是为了确认每张表的作用。这套脚本覆盖了学生、课程、成绩、用户四类核心数据字段类型和约束都是课程设计里最稳的写法CREATE DATABASE IF NOT EXISTS score_manage DEFAULT CHARACTER SET utf8mb4; USE score_manage; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(50) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT 1 COMMENT 1男 0女, class_name VARCHAR(50) COMMENT 班级, phone VARCHAR(20) COMMENT 联系电话, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE course ( id INT PRIMARY KEY AUTO_INCREMENT, course_no VARCHAR(20) NOT NULL UNIQUE COMMENT 课程编号, course_name VARCHAR(100) NOT NULL COMMENT 课程名称, credit DECIMAL(3,1) DEFAULT 2.0 COMMENT 学分, semester VARCHAR(30) COMMENT 开课学期 ); CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, course_id INT NOT NULL, score DECIMAL(5,1) COMMENT 成绩 0~100, exam_time VARCHAR(30) COMMENT 考试时间或学期, UNIQUE KEY uk_stu_course (student_id, course_id), CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student(id), CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course(id) ); CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL COMMENT 建议存加密后的密码, user_type VARCHAR(20) NOT NULL COMMENT admin/teacher/student, real_name VARCHAR(50), ref_id INT COMMENT 关联 student 或 teacher 的主键 );这里有几个参数值得留意。score表上的联合唯一键uk_stu_course是防止同一条成绩被重复插入的关键教师端录入成绩的标准动作应该是“先查再插”已存在则UPDATE不存在才INSERT这个约束就是兜底。DECIMAL(5,1)表示总位数 5 位、小数 1 位能存 0.0 到 999.9日常成绩有 0.5 分用整数存再处理会很别扭用 DOUBLE 又容易出浮点误差DECIMAL 是折中方案。外键约束在课程设计源码里并不统一很多老项目为了删数据省事直接省略外键。带外键的坏处是删除课程时如果已有成绩记录会被数据库拦截好处是逼着你在代码里先处理子表数据学习阶段我更推荐保留。.sql文件如果本来没有外键导入后也别慌代码里一般会在插入成绩前先校验学生和课程是否存在逻辑等价只是约束放到了 Java 层。2.3 用例图背后的三种角色和业务链路学生成绩管理系统的用例图画出来通常很清晰管理员维护学生、课程、账号教师负责录入和修改成绩学生只能查询自己的成绩。三张用例图对应三条数据流落到 DAO 层就是标准的增删改查。管理者登录后要新增学生先是INSERT INTO student同时INSERT INTO user生成登录账号创建课程则是往 course 表写一条记录。教师录成绩是业务核心。点击保存后Servlet 层先按学号和课程号查成绩表是否存在记录不存在就新增存在就执行UPDATE score SET score? WHERE student_id? AND course_id?。这个动作就是最典型的“增删改查”综合用例比单纯背 SQL 有说服力。学生查成绩则是三表 JOIN把 student、course、score 连起来按学号过滤再按学期排序。源码的目录结构通常也是按这个链路组织的dao包下每个实体一个类servlet包接收请求并转发util包里放数据库连接工具类。看到这样的分层基本能判断这个项目是 JSPServletJDBC 的经典写法不是 Spring Boot 那种前后端分离架构。明确了这一点接下来配置环境才有方向。3. 本地跑通最小步骤数据库导入、IDEA 配置和连接参数3.1 命令行导入 SQL 文件两种方式看清库名导入数据库是源码落地第一关。先用压缩包里的.sql文件确认里面有没有CREATE DATABASE语句这决定了命令怎么写。如果文件开头已经建库并USE直接在命令行执行mysql -uroot -p D:/db/score_manage.sql如果.sql文件只有建表和插入语句没有建库动作那就先手动建库再导入mysql -uroot -p mysql CREATE DATABASE score_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql USE score_manage; mysql SOURCE D:/db/score_manage.sql; mysql SHOW TABLES;SOURCE后面的路径尽量不要带中文和空格否则某些 Windows 终端会解析失败。导入完成后SHOW TABLES是必须做的验证看到 student、course、score 这些表名才算成功。如果表名一个都没有别急着怀疑代码先回头检查库名是否和连接串里写的一致这类问题十有八九是导错了库。提示如果.sql文件里有存储过程或触发器命令行导入通常没问题但用 Navicat 或 DataGrip 的“运行 SQL 文件”功能时遇到DELIMITER语句可能分段执行报错。遇到这种情况换成命令行SOURCE方式更稳。3.2 IDEA 运行 JavaWeb 项目配置Tomcat、Artifact 和 WebRoot老式 JavaWeb 项目没有 Maven 坐标依赖全在WEB-INF/lib目录下IDEA 里配置时最容易漏掉这一步。先打开 Project Structure找到 Artifacts确认项目打包产物里包含了WEB-INF/lib下的所有 jar 包。没有的话右键添加入库目录这一步不做启动时必然报ClassNotFoundException而且报的是驱动类或 Servlet 类让人误以为是代码问题。Run Configuration 里选 Tomcat Server 的 Local 类型。Server 页绑定本机 Tomcat 安装目录Deployment 页添加 Artifact这里我建议选war exploded而不是war。exploded 模式直接把编译后的目录作为部署目录Tomcat 不需要重新解压 war改完 JSP 刷新浏览器就能看到效果调试体验好很多。下方 Application context 填/score这个值要和浏览器访问路径一致否则后面打开页面总是 404。很多课程设计源码的 Web 目录不叫webapp而叫WebRootIDEA 默认不会把 WebRoot 识别为站点根目录。需要在 Project Structure 的 Facets 里找到 Web把 Web Resource Directory 指向 WebRoot并确认它的相对路径是/。这一步漏掉的话即使 Tomcat 启动成功你访问的也是空上下文页面全白。3.3 db.properties 连接参数三个必须对齐的配置项源码里的数据库连接信息通常集中在一个db.properties或JDBCUtil.java中找到它改成你自己的参数。最常见的内容是下面这种driverClasscom.mysql.jdbc.Driver jdbcUrljdbc:mysql://localhost:3306/score_manage?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue usernameroot password123456驱动类名要和 jar 包版本匹配com.mysql.jdbc.Driver是 5.x 驱动用的MySQL 8 的驱动必须写成com.mysql.cj.jdbc.Driver。如果你用的是 MySQL 8 但代码里还是老驱动类名启动时直接报ClassNotFoundException。URL 里的serverTimezoneAsia/Shanghai也不能省MySQL 8 驱动连接时若没指定时区会抛The server time zone value is unrecognized。字符集这条要一起看建库用的是utf8mb4连接串用characterEncodingutf8代码里如果还有request.setCharacterEncoding(UTF-8)三者一致才不会有乱码。改完db.properties必须重启 Tomcat因为这个文件通常在连接池初始化时被读取刷新页面不会生效。连接参数对不对最快的验证方式是写一个三行 Java 类先测连接而不是直接启动整个 Web 项目。配置项常见写法注意点driverClasscom.mysql.cj.jdbc.DriverMySQL 8 必须用 cj 包路径jdbcUrljdbc:mysql://localhost:3306/score_manage库名、时区、字符集都要对齐username/passwordroot/自行设置本地练习可先用 root联调后务必改弱口令4. 常见问题与排查数据库、依赖、编码三个重灾区4.1 驱动类找不到与 MySQL 8 认证插件报错现象一Tomcat 启动后访问页面报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。原因很简单要么mysql-connector-java的 jar 包根本没放进WEB-INF/lib要么驱动 jar 是 8.x 版本代码里还写着 5.x 的驱动类名。解决方式是先检查 Artifacts 里有没有这个 jar再看代码里驱动类名和 jar 版本是否匹配。现象二连接时报Unable to load authentication plugin caching_sha2_password这是 MySQL 8 的老账。MySQL 8 默认用户的密码加密方式是caching_sha2_password老版本的驱动不认这个插件。解决方式二选一把驱动 jar 换成 8.x 版本或者把用户密码改回旧式加密方式SQL 写法是ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;。我建议直接换新驱动因为改动最小而且不用动数据库安全策略。4.2 Tomcat 10 的包名翻车javax 还是 jakarta如果启动时看到NoClassDefFoundError: javax/servlet/http/HttpServlet而你的 Tomcat 是 10 或更高版本问题就出在命名空间上。Tomcat 10 起把 Servlet API 从javax.servlet迁移到了jakarta.servlet这套课程设计源码是照着老规范写的import 全是javax.*在新 Tomcat 里自然找不到类。解决方式最稳的是换成 Tomcat 8.5 或 9.0这是老项目的舒适区兼容性最好。非要用 Tomcat 10就得把所有import javax.servlet.*全局替换成jakarta.servlet.*但 JSP 的内置对象、web.xml头版本也可能跟着出问题新手容易改到一半进退两难。我见过不少人在这一步反复折腾最后换回 Tomcat 9 十分钟就跑通了环境版本不要追新追兼容。4.3 中文乱码连接串、JSP 和 server.xml 要一起调页面里的中文变成一串问号这恐怕是这个项目里出现频率最高的玄学问题。它不是一个地方导致的而是三个地方必须同时统一数据库表字符集、JDBC 连接串、页面响应编码。建库用utf8mb4连接串带characterEncodingutf8每个 JSP 页面上方的pageEncoding设为UTF-8这三步做到位八成乱码已经消失。剩下的两成在 Tomcat 配置。GET 请求的参数编码由server.xml里的 Connector 决定通常要显式加上URIEncodingUTF-8POST 请求则在代码里通过request.setCharacterEncoding(UTF-8)控制。更省事的做法是在web.xml里配置一个 CharacterEncodingFilter把请求和响应都强制成 UTF-8比在每个 Servlet 里手工设置要可靠得多。乱码问题排查时先看数据库里直接查询中文是否正常再逐层往上查黑匣子式的猜是浪费时间。4.4 端口占用与访问路径 404部署名和上下文对不上Tomcat 启动直接失败控制台报Port 8080 required by Tomcat ... is already in use这是端口被占用。Windows 下用netstat -ano | findstr 8080找出占用进程的 PID再用taskkill /F /PID 进程号结束它。不想动别人的进程也可以在 Server 配置里把 Tomcat 端口改成 8081但注意连接串里的端口是 MySQL 的和 Tomcat 端口没关系别改错地方。另一种 404 更隐蔽Tomcat 明明启动成功浏览器访问却始终找不到页面。这通常是 Application context 和实际访问路径不一致造成的。IDEA 里配置的 context 是/score你就得访问http://localhost:8080/score/login.jsp少一层路径都不行。先看控制台里 Tomcat 输出的部署日志它会明确告诉你应用挂载在哪个路径下照着那个路径访问基本一次就能定位。5. 进阶改造从跑通源码到做出自己的管理系统5.1 先做减法把 JDBC 样板代码换成 JdbcTemplate老项目的 DAO 层最磨人的是 PreparedStatement 那十几行固定模板拿连接、预编译、绑参数、执行、关资源。改动成本不高但收益明显用 Spring 的 JdbcTemplate 可以把代码压缩一半以上。传统 lib 方式需要往WEB-INF/lib加 spring-jdbc、spring-tx 几个 jarMaven 项目则直接加坐标。// 改造前手工管理连接和 PreparedStatement PreparedStatement ps conn.prepareStatement( insert into score(student_id, course_id, score, exam_time) values(?,?,?,?)); ps.setInt(1, studentId); ps.setInt(2, courseId); ps.setBigDecimal(3, score); ps.setString(4, term); ps.executeUpdate(); // 改造后一行完成事务和资源释放交给框架 jdbcTemplate.update( insert into score(student_id, course_id, score, exam_time) values(?,?,?,?), studentId, courseId, score, term);用BeanPropertyRowMapper时有个隐藏坑score 表里的student_id无法自动映射到实体的studentId属性因为下划线转驼峰是 MyBatis 的约定Spring 的默认 RowMapper 不做这个转换。要么给查询列起别名AS studentId要么手写 RowMapper。这个细节我踩过别看它小改错位置能让你怀疑人生。5.2 再加功能成绩导出 Excel 的三个必要动作课程设计答辩时评委最喜欢问“你这系统能不能导成绩单”。用 POI 做 Excel 导出套路固定先引入 poi-ooxml 依赖再创建 XSSFWorkbook 和 Sheet把查询结果逐行填入单元格最后通过 HttpServletResponse 把文件写回浏览器。三个必要动作缺一不可Content-Type 要设成application/vnd.openxmlformats-officedocument.spreadsheetml.sheet响应头要设置Content-Disposition附上文件名文件名的中文要做 URL 编码否则浏览器下载时中文乱码。分数列用setCellValue(double)不要用字符串否则 Excel 里无法求和。不想引入大依赖退一步用 CSV 也可以。CSV 本质是文本文件但中文容易乱码需要在文件开头写一个 UTF-8 BOM。POI 的坑更多在于内存数据量大时用 SXSSFWorkbook 流式写入别用 XSSFWorkbook 硬扛几千行。5.3 验证方法角色切换、数据备份和用例回归改代码之前先把数据库备份好这是我这几年雷打不动的习惯。一行命令搞定mysqldump -uroot -p score_manage score_manage_backup.sql备份不只是防手滑更是让你敢放手改代码的后悔药。改完之后验证流程固定三步开两个浏览器一个教师账号、一个学生账号教师录一条成绩切换到学生端确认能查到管理员尝试删除一个有成绩记录的课程确认外键拦截或代码提示生效再用学生账号确认页面上看不到录入和修改按钮。权限验证不是看代码里写了什么而是以两个角色实际点一遍为准。这个项目本身的价值不在跑通而在拆开重组的过程。我习惯先备份、再跑通、最后动刀每改一个功能就回归一遍相关用例。把别人的源码改成自己的系统比从零写一遍更能看清 Servlet 生命周期和数据库设计的关系。希望帮到你。本文还有配套的精品资源点击获取