ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java+Servlet+JSP+MySQL成绩管理系统课设源码拆解与实战改造

Java+Servlet+JSP+MySQL成绩管理系统课设源码拆解与实战改造 简介这是一套面向高校计算机相关专业学生的Java Web课程设计资源采用ServletJSPMySQL技术栈实现学生成绩管理系统适合作为期末大作业、课程设计或Java Web入门练手项目。压缩包共188个文件约11.29MB包含24个java源文件、42个jsp页面、72个class编译文件、12个xml配置、9个jar依赖及6个sql脚本另附项目报告docx文档源码经本地编译可运行评审分达98分难度适中。系统涵盖登录验证、管理员管理、学生信息维护、成绩录入与查询等核心模块分层结构清晰便于理解MVC设计思想与数据库交互流程。已有223人学习下载读者可据此快速搭建可运行环境参考Dao与Servlet实现思路并借助报告文档完成课程设计文档撰写与答辩准备。1. 从一份 98 分课设说起这套 JSP 成绩管理系统到底能帮你省多少事如果你正在为期末大作业或者课程设计发愁大概率已经翻过不少学生成绩管理系统的源码包。我这次拆的这套是 Java Servlet JSP MySQL 的组合评审分 98源码在本地编译过、能直接跑起来。它解决的核心问题很明确给你一套结构完整、分层清晰、带报告的三层架构 Web 项目让你不用从零搭架子把精力放在改需求、调界面、写文档上。这套东西适合谁一是赶课设 deadline 的在校生二是想拿一个真实 Servlet/JSP 项目练手 Java Web 基础的初学者三是需要一份能讲清楚分层的参考实现来对照自己代码的人。它不适合谁想学 Spring Boot、MyBatis 这类现代框架的人这套是原生 Servlet JDBC 的写法技术栈偏传统但恰恰因为传统反而能让你看清 request、response、session、DAO 这些底层东西是怎么串起来的。我拿到包的第一反应是看目录结构GradeDao.class、AdministratorDao.class、LoginServlet.class、StudentDao.class这些编译产物说明它已经过了编译这一关不是那种丢给你一堆.java让你自己配环境的半成品。下面我按能跑起来 → 看懂结构 → 改得动 → 不踩坑的顺序把这份资源拆开讲。2. 环境搭建与数据库初始化让项目在你机器上真正跑起来很多人下载完源码第一件事就是往 IDE 里一丢然后点运行结果报一堆错。这套项目要跑起来顺序很重要先装 JDK 和 Tomcat再建数据库最后导项目。顺序错了你会花大量时间在排查一些本来不该出现的问题上。2.1 JDK、Tomcat 与 MySQL 的版本选择这套项目用的是原生 Servlet JSP没有 Maven 依赖管理所以版本兼容性得自己盯。我的建议是 JDK 81.8Tomcat 8.5 或 9.0MySQL 5.7 或 8.0 都行。为什么不用 JDK 17因为老项目的 Servlet API 和 Tomcat 版本对高版本 JDK 支持不稳容易出现Unsupported class file major version这类玄学报错。MySQL 8.0 要注意一个坑驱动类从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver连接 URL 也要加时区和 SSL 参数。如果你用的是 5.7那就按老写法来。这一步选错后面连接数据库必翻车。组件推荐版本备注JDK1.8避免高版本兼容问题Tomcat8.5 / 9.0与 Servlet 3.x 匹配MySQL5.7 / 8.08.0 需改驱动类和 URLIDEEclipse / IDEA需支持 Dynamic Web Project2.2 建库建表先跑 SQL 再导项目数据库没建好就导项目启动时 DAO 层一连接就抛异常。常见做法是先找到资源里的.sql文件一般在sql或db目录用 Navicat 或命令行执行。下面是我整理的核心建表语句字段名和项目里的实体类对应-- 创建数据库字符集用 utf8mb4 避免中文乱码 CREATE DATABASE grade_manage DEFAULT CHARACTER SET utf8mb4; USE grade_manage; -- 管理员表 CREATE TABLE administrator ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL ); -- 学生表 CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, sno VARCHAR(20) NOT NULL, -- 学号 name VARCHAR(50) NOT NULL, gender VARCHAR(4), class_name VARCHAR(50) ); -- 成绩表外键关联学生 CREATE TABLE grade ( id INT PRIMARY KEY AUTO_INCREMENT, sno VARCHAR(20) NOT NULL, course VARCHAR(50) NOT NULL, score DECIMAL(5,2), FOREIGN KEY (sno) REFERENCES student(sno) );逻辑说明grade表用sno而不是student.id做外键是因为项目里的 DAO 查询大多按学号来关联这样查成绩时不用多一次 join。参数上score用DECIMAL(5,2)而不是FLOAT避免浮点精度问题导致成绩显示成 89.99999。字符集一定用utf8mb4否则学生姓名里的生僻字会变问号。提示执行 SQL 前先确认 MySQL 服务已启动端口 3306 没被占用。8.0 版本如果报Public Key Retrieval is not allowed在连接 URL 后面加allowPublicKeyRetrievaltrue。2.3 导入项目与修改数据库连接配置建完库接下来把项目导入 IDE。Eclipse 用Import → Existing Projects into WorkspaceIDEA 用Open选项目根目录。导入后第一件事不是运行是找到数据库配置文件。这套项目通常把连接信息写在db.properties或者直接硬编码在 DAO 的getConnection()里。// 常见写法在 DAO 基类里获取连接 public class BaseDao { private static final String URL jdbc:mysql://localhost:3306/grade_manage?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai; private static final String USER root; private static final String PWD 你的密码; public static Connection getConn() throws Exception { Class.forName(com.mysql.cj.jdbc.Driver); // 8.0 用 cj5.7 去掉 cj return DriverManager.getConnection(URL, USER, PWD); } }逻辑说明useUnicodetruecharacterEncodingutf8保证中文不乱码serverTimezoneAsia/Shanghai是 8.0 必须加的否则报时区错误。Class.forName加载驱动8.0 用com.mysql.cj.jdbc.Driver5.7 用com.mysql.jdbc.Driver写错直接ClassNotFoundException。改完配置把 MySQL 驱动 jar 放进WEB-INF/lib然后配置 Tomcat 运行。启动后访问http://localhost:8080/项目名/login.jsp能看到登录页就说明环境通了。这一步跑通后面才有得聊。3. 三层架构拆解Servlet、DAO、JSP 各管什么环境跑通只是第一步真正要用这套源码得看懂它的分层逻辑。这套项目是典型的 Model2 模式Servlet 当控制器DAO 管数据JSP 做展示。搞不清这三层谁调谁你改一个功能就会牵一发动全身。3.1 LoginServlet 的请求处理链路登录是理解整个流程最好的入口。用户在login.jsp填账号密码表单提交到LoginServletServlet 调AdministratorDao查库查到就写 session 跳转主页查不到就回登录页带错误信息。// LoginServlet 核心逻辑 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); AdministratorDao dao new AdministratorDao(); Administrator admin dao.login(username, password); // 查库 if (admin ! null) { req.getSession().setAttribute(admin, admin); // 写 session resp.sendRedirect(index.jsp); // 跳主页 } else { req.setAttribute(msg, 账号或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); } }逻辑说明getParameter拿表单值dao.login返回实体对象非空说明验证通过。sendRedirect是重定向地址栏会变forward是转发地址栏不变。登录失败用forward是为了把msg带到页面上显示。这里有个细节session 里存的是整个Administrator对象不是只存用户名方便后续页面取管理员信息。参数上要注意req.getParameter拿到的永远是字符串如果表单里有数字字段得用Integer.parseInt转且要处理NumberFormatException否则用户乱填就 500。3.2 DAO 层的增删改查与 JDBC 封装GradeDao、StudentDao、AdministratorDao这三个 DAO 是数据操作的核心。它们内部都是PreparedStatementResultSet的老套路没有 ORM 框架。看一个成绩查询的典型实现// GradeDao 按学号查成绩 public ListGrade getGradesBySno(String sno) { ListGrade list new ArrayList(); String sql SELECT * FROM grade WHERE sno ?; try (Connection conn BaseDao.getConn(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, sno); // 参数化防注入 ResultSet rs ps.executeQuery(); while (rs.next()) { Grade g new Grade(); g.setCourse(rs.getString(course)); g.setScore(rs.getDouble(score)); list.add(g); } } catch (Exception e) { e.printStackTrace(); } return list; }逻辑说明用PreparedStatement而不是Statement拼接字符串是为了防 SQL 注入这是血泪经验拼接写法一旦被输入 OR 11就全表泄露。try-with-resources自动关连接避免连接泄漏导致 Tomcat 跑一会儿就卡死。参数ps.setString(1, sno)的 1 是占位符序号从 1 开始不是 0这个新手常写错。ResultSet遍历时字段名要和数据库列名一致大小写不敏感但拼错就抛SQLException。如果查询结果为空list是空集合不是 null调用方不用做 null 判断这是好习惯。3.3 JSP 页面如何渲染数据与 session 校验JSP 层负责把 DAO 查出来的数据展示成表格。这套项目的 JSP 里混用了 JSTL 和脚本片段% %老项目常见。看一个成绩列表的渲染% page contentTypetext/html;charsetUTF-8 % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % // session 校验没登录踢回登录页 if (session.getAttribute(admin) null) { response.sendRedirect(login.jsp); return; } % table trth课程/thth成绩/th/tr c:forEach items${gradeList} varg tr td${g.course}/td td${g.score}/td /tr /c:forEach /table逻辑说明顶部 session 校验是每个需要登录的页面都要加的否则用户直接输 URL 就能绕过登录。c:forEach遍历后端request里放的gradeList${g.course}是 EL 表达式等价于g.getCourse()。注意 JSP 顶部contentType要设charsetUTF-8否则中文乱码。这里有个容易忽略的点如果 Servlet 里用forward到 JSPrequest域的数据能拿到如果用sendRedirectrequest数据就丢了得靠 session 或 URL 传参。改功能时搞混这两个数据就显示不出来。4. 功能改造实战从能跑到能用的几个关键改动源码能跑不等于满足你的课设要求。评审老师看的是你有没有自己的东西。这一章讲几个高频改造点改完既能让项目更像你的又不会把原有结构搞崩。4.1 新增字段给学生表加入学年份课设常见要求是加字段。假设要给student表加enroll_year改动链路是数据库加列 → 实体类加属性 → DAO 的增删改 SQL 加字段 → JSP 表单加输入框 → 列表页加显示列。少改一处就报错。ALTER TABLE student ADD COLUMN enroll_year INT DEFAULT 2024;// Student 实体类加属性和 getter/setter private int enrollYear; public int getEnrollYear() { return enrollYear; } public void setEnrollYear(int y) { this.enrollYear y; }// StudentDao 插入语句同步加字段 String sql INSERT INTO student(sno,name,gender,class_name,enroll_year) VALUES(?,?,?,?,?); ps.setString(1, s.getSno()); ps.setString(2, s.getName()); ps.setString(3, s.getGender()); ps.setString(4, s.getClassName()); ps.setInt(5, s.getEnrollYear()); // 新增逻辑说明实体类属性名用驼峰enrollYear数据库列名用下划线enroll_year这是 Java 惯例。ps.setInt对应 INT 列如果传 null 要用setNull。JSP 表单里加input nameenrollYearServlet 里Integer.parseInt(req.getParameter(enrollYear))接收。整条链路任何一环漏了要么插入失败要么页面显示 null。4.2 分页查询成绩列表数据多了怎么处理数据一多全量查询页面就卡。加分页是课设加分项。核心是LIMIT加两个参数起始偏移量和每页条数。// 分页查询page 从 1 开始 public ListGrade getGradesByPage(int page, int pageSize) { ListGrade list new ArrayList(); int offset (page - 1) * pageSize; // 关键偏移量计算 String sql SELECT * FROM grade LIMIT ?, ?; try (Connection conn BaseDao.getConn(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, offset); ps.setInt(2, pageSize); ResultSet rs ps.executeQuery(); while (rs.next()) { Grade g new Grade(); g.setSno(rs.getString(sno)); g.setCourse(rs.getString(course)); g.setScore(rs.getDouble(score)); list.add(g); } } catch (Exception e) { e.printStackTrace(); } return list; }逻辑说明offset (page-1) * pageSize是分页公式第 1 页 offset 为 0第 2 页 offset 为 pageSize。LIMIT ?, ?第一个问号是偏移量第二个是条数顺序别写反。总页数要另写一个SELECT COUNT(*)查询用Math.ceil(total / (double)pageSize)算。参数上pageSize一般设 10 或 15太大分页没意义太小翻页太频繁。注意MySQL 的LIMIT偏移量在数据量大时性能会下降因为要扫描前 offset 行。课设数据量小无所谓但面试被问到要能说出这个边界。4.3 中文乱码POST 和 GET 两套处理方案中文乱码是这套项目最容易翻车的地方而且 POST 和 GET 处理方式不一样。POST 请求在 Servlet 里读参数前设req.setCharacterEncoding(UTF-8)GET 请求改 Tomcat 的server.xml加URIEncodingUTF-8。// POST 乱码必须在 getParameter 之前调用 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); // 这一行必须在最前面 resp.setContentType(text/html;charsetUTF-8); String name req.getParameter(name); // 此时拿到的才是正确中文 }逻辑说明setCharacterEncoding只对 POST 请求体有效且必须在第一次getParameter之前调用调晚了无效。GET 请求的参数在 URL 里编码由 Tomcat 决定8.0 以上默认 UTF-8老版本要在server.xml的 Connector 标签加URIEncodingUTF-8。响应端setContentType设了浏览器才知道用什么编码解析。数据库连接 URL 里的characterEncodingutf8也要加三层都对齐 UTF-8乱码才彻底消失。只改一层问题会从页面转移到数据库再转回来排查起来很折磨。5. 避坑与排查这套源码最容易翻车的五个地方前面讲的是怎么用这一章讲怎么不翻车。以下五条都是我在拆这类原生 Servlet 项目时反复遇到的每条按现象、原因、解决来说。5.1 启动报 ClassNotFoundException: com.mysql.jdbc.Driver现象Tomcat 一启动或一登录就抛这个异常堆栈指向BaseDao。原因MySQL 驱动 jar 没放进WEB-INF/lib或者用了 8.0 的库却写 5.7 的驱动类名。解决确认WEB-INF/lib下有mysql-connector-java-x.x.x.jar且Class.forName里的类名和版本匹配。8.0 用com.mysql.cj.jdbc.Driver5.7 用com.mysql.jdbc.Driver。放完 jar 记得在 IDE 里刷新项目并重新部署。5.2 页面报 404但 Tomcat 启动没报错现象访问login.jsp显示 404Tomcat 日志正常。原因项目访问路径不对或者web.xml里 Servlet 映射配错或者 JSP 放在了WEB-INF下直接访问不到。解决先确认访问 URL 是http://localhost:8080/项目名/login.jsp项目名是部署时的 context path。JSP 如果放在WEB-INF下必须通过 Servlet 转发访问不能直接输 URL。检查web.xml的url-pattern和servlet-name是否对应。5.3 登录成功但跳转后 session 丢失现象登录后跳主页主页又跳回登录页像没登录一样。原因session 没写进去或者跳转用了sendRedirect导致跨域丢 cookie或者浏览器禁了 cookie。解决确认req.getSession().setAttribute(admin, admin)执行了。sendRedirect在同域下 session 不会丢但如果项目名或端口变了会。检查主页 JSP 的 session 校验取的 key 和登录时存的 key 是否一致admin和administrator这种拼写不一致最常见。5.4 成绩显示为 0.0 或 null现象列表页成绩列全是 0.0 或空白。原因ResultSet取的列名和数据库不一致或者实体类 setter 没被调用或者DECIMAL用getInt取。解决核对rs.getString(score)里的列名和建表语句一致。DECIMAL类型用getDouble或getBigDecimal用getInt会截断。实体类 setter 名要和属性对应setScore对应scoreIDEA 自动生成的一般没问题手写容易错。5.5 修改后不生效还是旧页面现象改了 JSP 或 Java 代码重新运行还是老样子。原因Tomcat 缓存了编译后的 class 和 JSP或者 IDE 没重新编译。解决在 IDE 里Clean项目再重新部署或者删掉 Tomcat 的work目录。改 Java 代码必须重启 Tomcat改 JSP 一般热加载但有时也需重启。养成改完先 Clean 的习惯能省很多我明明改了的困惑。6. 报告撰写与答辩加分把源码变成能讲清楚的作品课设不只是交代码报告和答辩占分往往不低。这套资源自带报告但直接交容易撞车得改成自己的话。我的做法是报告结构照搬但每个模块用自己的语言重写一遍重点写为什么这么设计而不是我做了什么。报告里最容易被问的是数据库设计。把 E-R 图、表结构、字段类型和约束讲清楚尤其是外键和索引。比如grade表的sno外键要能说出为什么用学号关联而不是主键 id——因为业务查询按学号走减少一次 join。这种细节一讲老师就知道你真懂了。答辩演示有个技巧提前准备好三条数据链路登录 → 查成绩 → 改成绩每条都能从页面点到数据库再回来。演示时故意输错密码展示错误处理故意查不存在的学号展示空结果处理这些边界比正常流程更能体现你考虑周全。代码层面把System.out.println换成日志或者删掉把硬编码的数据库密码抽到配置文件把重复的 JDBC 代码抽成工具类。这几个小改动花不了多少时间但答辩时老师翻代码看到印象分直接上去。从那以后我每次拿到这类课设源码都强制自己先跑通再改一处再讲一遍跑不通不改改完必讲。这套流程走下来代码才真正变成自己的。希望帮到你。本文还有配套的精品资源点击获取
返回列表