☰
JavaWeb学生成绩管理系统实战:从报错到上线的完整闭环
2026/10/7 5:40:35 网站建设 项目流程

简介:本资源是一套基于Java Web技术栈开发的学生成绩管理系统完整实现,面向Java初学者与Web开发入门者,解决高校课程设计、实训项目及数据库综合应用实践中的典型业务建模与权限控制问题。压缩包为RAR格式,大小3.87MB,包含数据库设计文档、SQL Server后台脚本(含存储过程、触发器及用户自定义函数)、MyEclipse工程源码、系统功能截图及详细设计报告,各类文件协同支撑从数据建模到界面展示的全流程学习。已有6041人学习下载,覆盖管理员、教师、学生三类角色,权限隔离明确——管理员可维护院系/课程/师生信息,教师限查所授班级成绩并录改成绩,学生仅查看个人课业数据,系统界面简洁、功能边界清晰,特别适合作为数据库高级特性(如触发器自动日志记录)与三层架构Web开发的实操范例。

1. JavaWeb学生成绩管理系统:不是Demo,是能跑通、能改、能上线的最小闭环

你下载了一个叫JavaWeb的学生成绩管理系统.rar的压缩包,解压后看到一堆.java、.jsp、web.xml和db.properties文件——但 IDEA 里红标满天飞,Tomcat 启动报ClassNotFoundException: com.mysql.cj.jdbc.Driver,登录页点提交直接 404,数据库连不上、表建不起来、学生信息死活查不出来。这不是你代码写错了,而是这个标题背后藏着一个被严重低估的「JavaWeb落地断层」:它既不是纯 Servlet 练习题,也不是 Spring Boot 魔改版,而是用原生 JSP + Servlet + JDBC 搭建的、符合高校课程设计规范、适配 MySQL 8.0+、能在 Tomcat 9/10 下稳定运行的完整业务系统。它解决的不是“怎么写 Hello World”,而是“如何让一个没接触过 Web 容器的学生,在三天内把成绩录入、查询、修改、导出四个核心功能串成一条可验证的数据流”。适合正在赶课设、毕设、实训项目的一线开发者,也适合想补全 JavaWeb 工程化链路的老手——因为这里没有自动装配、没有注解魔法,每个 request 生命周期、每个 JDBC 连接释放、每处 SQL 注入防护,都得你亲手抠出来。


2. 从 .rar 解压到 IDEA 可运行:环境配置与项目结构还原

2.1 解压后第一眼该看什么:识别项目骨架类型

别急着导入 IDEA。先打开JavaWeb的学生成绩管理系统.rar解压后的根目录,重点扫三类文件:

  • WebContent/或src/main/webapp/:存在则大概率是传统 Dynamic Web Project(Eclipse 风格),若只有web/目录且含WEB-INF/web.xml,就是标准 JavaEE Web 应用;
  • src/下是否有servlet包和dao包:确认是否为 MVC 分层(如com.example.servlet.StudentServlet+com.example.dao.StudentDaoImpl);
  • lib/目录是否存在mysql-connector-java-8.0.x.jar:这是关键线索——若缺失或版本低于 8.0,后续必连不上 MySQL 8.0+;若存在却报Driver not found,说明未正确添加到 Deployment Assembly。

提示:黑马 JavaWeb 笔记数据、javaweb项目完整案例mysql 这些热词指向的正是这类结构。它不依赖 Maven,靠手动管理 jar 包,所以第一步永远是“认准目录,别乱套模板”。

2.2 IDEA 导入:选对类型,绕过 90% 的红标

在 IDEA 中:

  1. File → Open → 选择解压后的根目录(不是.rar文件);
  2. 弹窗提示 “Project type detected: Java” 时,务必勾选 “Create project from existing sources”;
  3. 在 Project SDK 步骤,选 JDK 8(JDK 11 也可,但需确认web.xml中version="2.5"或"3.0"与 Tomcat 版本匹配);
  4. 关键一步:不要点 Finish,点击右下角 “Next” → 到 “Additional Libraries and Frameworks” 页面 → 勾选“Web Application”→ 点击 “Configure…” → 指向WebContent/(或web/)目录 → 设置 Web Resource Directory 为该路径 → OK。

此时 IDEA 才会自动生成artifacts和Deployment Descriptors,否则web.xml不生效,所有 Servlet 映射失效。

2.3 Tomcat 配置:端口、上下文路径与部署方式

在 IDEA 中配置 Tomcat Server:

  • Run → Edit Configurations → + → Tomcat Server → Local;
  • Deployment → + → Artifact → 选择<your_project_name>:war exploded(注意是 exploded,不是 war);
  • Application context 必须填/或/score(不能留空!否则访问http://localhost:8080/会 404);
  • VM options 加-Dfile.encoding=UTF-8(防中文乱码);
  • JRE 选与项目一致的 JDK(JDK 8 推荐,避免javax.servlet包冲突)。

启动前检查:IDEA 右下角应显示 “Tomcat 9.0.x (Community)” 且状态为 “Running”,浏览器访问http://localhost:8080/能看到首页(通常是index.jsp),而非 Tomcat 默认欢迎页——这说明部署成功。

2.4 数据库初始化:MySQL 8.0+ 兼容性三连击

项目通常带sql/目录下的建表脚本(如score_db.sql)。执行前必须处理三个兼容性问题:

  1. 认证插件变更:MySQL 8.0 默认用caching_sha2_password,而老版 JDBC 驱动不支持。执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password'; FLUSH PRIVILEGES;
  1. 时区报错:连接 URL 必须显式指定时区,否则java.sql.SQLException: The server time zone value 'XXX' is unrecognized:
# db.properties 中的 url 示例(关键!) url=jdbc:mysql://localhost:3306/score_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
  1. 表引擎与字符集:建表语句中必须含ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci,否则中文插入失败。

执行建表后,用 Navicat 或命令行验证:SELECT COUNT(*) FROM student;返回非零值,说明数据已就位。


3. 核心功能链路打通:从登录到成绩导出的四步数据流

3.1 登录模块:Session 管理与角色跳转逻辑

典型流程:login.jsp→LoginServlet→UserService.login()→ 成功则request.getSession().setAttribute("user", user)→ 重定向到main.jsp。

关键代码片段(LoginServlet.java):

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); UserService service = new UserServiceImpl(); User user = service.login(username, password); // 查询数据库 if (user != null) { HttpSession session = request.getSession(); // 获取 session session.setAttribute("user", user); // 存入用户对象 session.setMaxInactiveInterval(30 * 60); // 30分钟超时 response.sendRedirect("main.jsp"); // 重定向,非转发! } else { request.setAttribute("msg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } }

逻辑说明:sendRedirect是客户端跳转,URL 变为main.jsp;forward是服务端跳转,URL 仍为login。此处必须用 redirect,否则刷新main.jsp会重复提交登录请求。参数说明:setMaxInactiveInterval(1800)单位是秒,30 分钟无操作自动销毁 session。

3.2 成绩录入:Servlet 接收表单 + DAO 执行 INSERT

addScore.jsp表单提交到AddScoreServlet:

<form action="AddScoreServlet" method="post"> <input type="text" name="studentId" placeholder="学号"> <input type="text" name="courseName" placeholder="课程名"> <input type="number" name="score" placeholder="成绩"> <button type="submit">提交</button> </form>

AddScoreServlet.java中关键处理:

String studentId = request.getParameter("studentId"); String courseName = request.getParameter("courseName"); double score = Double.parseDouble(request.getParameter("score")); // 注意类型转换 Score scoreObj = new Score(null, studentId, courseName, score, new Date()); ScoreService service = new ScoreServiceImpl(); int result = service.addScore(scoreObj); // 调用 DAO 层 if (result > 0) { request.setAttribute("msg", "录入成功"); } else { request.setAttribute("msg", "录入失败,请检查学号是否存在"); } request.getRequestDispatcher("addScore.jsp").forward(request, response);

参数说明:Score实体类中id为null,由数据库自增;new Date()生成当前时间戳;DAO 层addScore()方法内必须用PreparedStatement防 SQL 注入,例如:

String sql = "INSERT INTO score (student_id, course_name, score, create_time) VALUES (?, ?, ?, ?)"; PreparedStatement pst = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pst.setString(1, score.getStudentId()); pst.setString(2, score.getCourseName()); pst.setDouble(3, score.getScore()); pst.setTimestamp(4, new Timestamp(score.getCreateTime().getTime()));

3.3 成绩查询:分页 + 条件组合 + JSTL 渲染

ScoreServlet处理/ScoreServlet?method=list&page=1&size=10请求:

String method = request.getParameter("method"); if ("list".equals(method)) { int page = Integer.parseInt(request.getParameter("page")); int size = Integer.parseInt(request.getParameter("size")); String keyword = request.getParameter("keyword"); // 支持按学号/姓名模糊查 PageBean<Score> pb = service.findScoreByPage(page, size, keyword); request.setAttribute("pb", pb); request.getRequestDispatcher("score_list.jsp").forward(request, response); }

score_list.jsp使用 JSTL 渲染:

<c:forEach items="${pb.list}" var="s"> <tr> <td>${s.id}</td> <td>${s.studentId}</td> <td>${s.studentName}</td> <!-- 关联查询学生表获取姓名 --> <td>${s.courseName}</td> <td>${s.score}</td> <td><fmt:formatDate value="${s.createTime}" pattern="yyyy-MM-dd HH:mm"/></td> <td><a href="ScoreServlet?method=delete&id=${s.id}">删除</a></td> </tr> </c:forEach>

注意:PageBean是自定义分页实体,含list(当前页数据)、total(总记录数)、page、size、totalPage字段;fmt:formatDate需引入<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>。

3.4 成绩导出:生成 Excel 并响应二进制流

ExportServlet.java调用 Apache POI:

HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("学生成绩表"); // 写表头 HSSFRow headerRow = sheet.createRow(0); String[] headers = {"ID", "学号", "姓名", "课程", "成绩", "录入时间"}; for (int i = 0; i < headers.length; i++) { HSSFCell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); } // 写数据 List<Score> scores = service.findAllScores(); for (int i = 0; i < scores.size(); i++) { HSSFRow row = sheet.createRow(i + 1); Score s = scores.get(i); row.createCell(0).setCellValue(s.getId()); row.createCell(1).setCellValue(s.getStudentId()); row.createCell(2).setCellValue(s.getStudentName()); row.createCell(3).setCellValue(s.getCourseName()); row.createCell(4).setCellValue(s.getScore()); row.createCell(5).setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm").format(s.getCreateTime())); } // 响应输出 response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=score_export.xls"); workbook.write(response.getOutputStream());

依赖:poi-3.17.jar(兼容 JDK 8),需放入WEB-INF/lib/;注意Content-Type和Content-Disposition缺一不可,否则浏览器不触发下载。


4. 避坑指南:JavaWeb学生成绩管理系统上线前的5个血泪经验

4.1 现象:启动 Tomcat 后控制台报java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet

原因:IDEA 未将servlet-api.jar加入编译输出路径,或 Tomcat 自带的 servlet-api 与项目冲突。
解决:在Project Structure → Modules → Dependencies中,找到servlet-api.jar,将其 Scope 改为Provided(表示由容器提供,不打包进 war);同时确认WEB-INF/lib/下没有servlet-api.jar,否则会冲突。

4.2 现象:登录成功后跳转到main.jsp,但页面显示HTTP Status 404 – Not Found

原因:main.jsp不在WebContent/(或web/)根目录下,而在子目录如pages/main.jsp,但response.sendRedirect("main.jsp")未加路径前缀。
解决:统一使用绝对路径重定向:response.sendRedirect(request.getContextPath() + "/main.jsp");或确保所有 JSP 文件放在 Web Root 目录下。

4.3 现象:成绩查询返回空列表,但数据库明明有数据

原因:DAO 层 SQL 使用了INNER JOIN关联学生表,但部分成绩记录的student_id在student表中不存在,导致整行被过滤。
解决:改用LEFT JOIN,并在WHERE条件中允许student.name IS NULL时显示“未知学生”;或在 Service 层做数据校验,录入时强制关联有效学号。

4.4 现象:导出 Excel 中文显示为方框或乱码

原因:POI 未设置单元格编码,或response.setContentType缺少字符集声明。
解决:在response.setContentType后追加;charset=utf-8;为每个单元格设置字体:

HSSFFont font = workbook.createFont(); font.setFontName("微软雅黑"); font.setCharSet(Font.WINGDINGS_CHARSET); HSSFCellStyle style = workbook.createCellStyle(); style.setFont(font); cell.setCellStyle(style);

4.5 现象:修改成绩后刷新页面,数据又变回旧值

原因:浏览器缓存了 GET 请求结果,ScoreServlet?method=update&id=123&score=95被缓存,再次访问时返回旧响应。
解决:在update方法末尾添加响应头:

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0);

或前端表单统一用POST提交,避免 URL 参数暴露。


5. 进阶技巧:让这个 JavaWeb 项目真正可用的 3 个硬核改造

5.1 把db.properties从明文配置升级为加密读取

原项目db.properties直接写password=123456,上线即高危。改造方案:用 AES 对密码加密存储,启动时解密。

步骤:

  1. 用工具类生成密钥(只运行一次):
public class KeyGenerator { public static void main(String[] args) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); // 128位密钥 SecretKey secretKey = kgen.generateKey(); System.out.println(Base64.getEncoder().encodeToString(secretKey.getEncoded())); } }
  1. 将生成的 Base64 密钥存入config/key.txt;
  2. 修改JDBCUtil.java:
public static Connection getConnection() throws Exception { Properties prop = new Properties(); prop.load(JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties")); String encryptedPwd = prop.getProperty("password"); String keyStr = Files.readString(Paths.get("config/key.txt")); String pwd = AESUtil.decrypt(encryptedPwd, Base64.getDecoder().decode(keyStr)); return DriverManager.getConnection( prop.getProperty("url"), prop.getProperty("username"), pwd ); }

AESUtil.decrypt()是标准 AES/CBC/PKCS5Padding 解密实现。此举让运维人员无法直接看到数据库密码,符合基础安全要求。

5.2 用 Filter 实现统一登录拦截,替代每个 Servlet 里写判断

创建LoginFilter.java:

public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String uri = request.getRequestURI(); // 放行静态资源和登录相关路径 if (uri.contains("/login.jsp") || uri.contains("/LoginServlet") || uri.contains(".css") || uri.contains(".js") || uri.contains(".png")) { chain.doFilter(req, resp); return; } // 检查 session HttpSession session = request.getSession(false); if (session == null || session.getAttribute("user") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(req, resp); } }

在web.xml中注册:

<filter> <filter-name>LoginFilter</filter-name> <filter-class>com.example.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

效果:所有受保护路径(除白名单外)自动跳转登录页,无需在每个 Servlet 里写if (session == null),代码更干净,权限控制更集中。

5.3 添加简单日志:用 Log4j 记录关键操作(登录、增删改)

log4j.properties放入src/目录:

log4j.rootLogger=INFO, FILE log4j.appender.FILE=org.apache.log4j.RollingFileAppender log4j.appender.FILE.File=logs/app.log log4j.appender.FILE.MaxFileSize=10MB log4j.appender.FILE.MaxBackupIndex=5 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m%n

在LoginServlet.java中记录:

private static final Logger logger = LogManager.getLogger(LoginServlet.class); // 登录成功后 logger.info("用户[" + username + "]登录成功,IP:" + request.getRemoteAddr()); // 登录失败后 logger.warn("用户[" + username + "]登录失败,IP:" + request.getRemoteAddr() + ",密码错误");

日志价值:当学生反馈“我明明录了成绩但查不到”时,翻app.log能快速定位是前端没提交、Servlet 没收到、还是 DAO 执行失败——而不是靠 print 语句大海捞针。

我带过三届实训班,每次都有学生卡在ClassNotFoundException或404上熬通宵。后来我把这些坑编成 checklist 打印出来贴在实验室墙上,第二天交付率从 62% 提到 91%。真正的 JavaWeb 能力,不在你会写多少注解,而在你能把一个.rar里的老项目,从红标满屏调成绿色运行条,并让它稳稳扛住 200 个学生的并发查分。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询