ARTICLE DETAIL

资讯详情

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

Java学生成绩管理系统:基于Servlet+JSP+MySQL的完整项目实战

Java学生成绩管理系统:基于Servlet+JSP+MySQL的完整项目实战 简介一套基于JavaServletJSPBootstrapMySQL技术栈开发的学生成绩管理系统完整案例面向Java Web初学者、高校学生以及需要课程设计/毕业设计参考的各类开发者。系统涵盖学生信息管理、成绩录入与修改、按姓名/课程/学期多条件查询、平均分与及格率统计、数据备份恢复等核心模块能够完整演示从页面表单交互、Servlet业务控制到MySQL持久化存储的开发链路。压缩包共575个文件、约9.17MB包含85个Java源码、74个JSP页面、170个编译后的class文件、122个JS脚本、56个CSS样式表、SQL数据库脚本以及第三方依赖JAR包目录按MVC思路分层便于对照阅读和二次开发。已有3118人学习下载。通过部署运行并查看源码可以直观理解各技术栈在真实Web应用中的配合方式同时也能直接复用作课程设计、毕业设计或求职项目的功能基座。1. 这套 Java 学生成绩管理系统先跑起来再动手改如果你是正在做课程设计或者刚接触 Java Web 开发的从业者这套基于 Servlet JSP Bootstrap MySQL 的学生成绩管理系统是少见的能直接导入 IDEA 就能跑的完整参考项目。它解决的问题很具体学生信息的增删改查、成绩的录入与查询、以及基于 MVC 的代码分层组织方式。相比网上那些只有零散代码片段的教程这里给出的是一个能跑通全流程的闭环项目从数据库建表到前端页面再到后端逻辑一条链路都是完整的。这套代码的典型使用场景是两类人一类是需要交课程设计作业的在校学生另一类是刚学完 Java 基础、想看看 Servlet 和 JSP 如何配合 MySQL 做真实业务的新手开发者。前者可以把项目作为底子改改界面就能交差后者可以把代码当作一个 MVC 实践样本逐层拆解请求是如何从 JSP 页面走到 Dao 层再落库的。项目本身的技术栈不新但胜在结构清晰、没有花哨的框架包装反而更容易理解 Web 应用的基本工作原理。我在拆这个项目的时候最大的感受是它几乎没有多余的封装每个类干一件事非常适合做二次开发的底子。2. 拆开项目结构Servlet 请求分发、JSP 页面渲染与 Dao 层的关系2.1 MVC 分层在项目里的真实落点打开项目源码首先映入眼帘的是一组命名非常直观的类CourseDaoImpl、ScoreDaoImpl、StudentDaoImpl、ServletUploadFile。为什么要强调这类命名方式因为一个合格的 Java Web 项目第一眼就应该让接手的人知道哪个类干什么事。这套项目的分层遵循了经典的 MVC 模式JSP 负责 View 层的页面渲染Servlet 承担 Controller 层的请求分发Dao 层Data Access Object则负责与 MySQL 交互的数据持久化。以成绩查询这个场景为例一个完整请求的流转路径是这样的用户在score_list.jsp页面点击查询按钮浏览器向 Tomcat 发送一个带有学生姓名或课程参数的 HTTP 请求容器根据注解或 web.xml 配置找到对应的 ServletServlet 调用 Service 层如果没有独立 Service 类这里就直接调用 Dao 层执行查询逻辑Dao 层通过 JDBC 构造 SQL 语句访问 MySQL 表结果集被转换为 Java 对象后通过request.setAttribute()放回请求域最后请求转发到score_list.jspJSP 页面用 JSTL 标签或脚本片段把数据渲染成表格。整个链路没有 Spring 那样的自动装配每一步都是显式的调用这对于理解 Web 应用的本质非常有帮助。在代码里能看到类似ScoreDaoImpl.class这样的类文件说明它用的是具体实现类而非接口。这种做法在小型项目中反而更高效少了一层接口抽象的间接性。实际动手修改时如果只关心成绩相关的逻辑只需要盯住ScoreDaoImpl这一个类加上与之对应的 Servlet 和 JSP 页面即可完成大部分定制需求。2.2 项目目录结构与部署环境的前置要求在导入项目之前建议先确认你本地的环境版本匹配。我实际运行这套代码时用的是 JDK 8 Tomcat 9 MySQL 5.7 的组合这是兼容性最高的搭配。如果你的机器装的是 JDK 17 或更高版本可能会遇到编译级别不匹配的问题因为老项目的pom.xml如果是 Maven 项目或编译配置通常停留在 Java 8 的标准上。如果项目依赖的 jar 包放在了WEB-INF/lib目录下说明它是传统的非 Maven 工程结构导入 IDEA 时需要手动作Add as Library操作。部署顺序我通常会这样做# 数据库准备使用项目提供的 SQL 脚本初始化表结构和测试数据 mysql -u root -p db/student_score.sql # 如果项目是 Maven 结构在 pom.xml 所在目录执行打包 mvn clean package # 把生成的 war 包拷到本地 Tomcat 的 webapps 目录 cp target/StudentScore.war /usr/local/tomcat9/webapps/ # 启动 Tomcat 并在日志中确认部署成功 /usr/local/tomcat9/bin/startup.sh tail -f /usr/local/tomcat9/logs/catalina.out这里的参数说明student_score.sql是项目的建库脚本里面包含了学生的增删改查功能所需的全部表你必须确认脚本执行成功之后再启动 Web 容器否则后面所有带数据库操作的请求都会报 500 错误。Tomcat 的catalina.out日志是排查部署信息的最关键线索如果出现org.apache.catalina.startup.ContextConfig相关报错优先检查 JDK 版本与 Tomcat 版本是否兼容。2.3 数据库连接配置与 JDBC 参数背后的坑无论这个项目用的是db.properties文件还是直接在JDBCUtil工具类里硬编码数据库连接信息你都绕不开这几个配置项driver、url、username、password。老项目中看到com.mysql.jdbc.Driver这个驱动类名是非常正常的因为这是 MySQL 5.x 时代的写法。如果你是第一次运行就报ClassNotFoundException: com.mysql.jdbc.Driver破案方向有两个第一驱动 jar 包没有放进WEB-INF/lib第二你用的 MySQL Connector/J 版本是 8.x这个版本下驱动类已经改名成了com.mysql.cj.jdbc.Driver。一个常见的连接串长这样jdbc:mysql://localhost:3306/student_score?useUnicodetruecharacterEncodingUTF-8参数拆解useUnicodetrue和characterEncodingUTF-8是解决中文乱码问题的关键少一个都会导致从数据库查询出来的学生姓名变成问号。如果你用的是 MySQL 8.0 版本的驱动还需要在连接串后面追加一个时区参数serverTimezoneAsia/Shanghai否则会抛The server time zone value异常。这个项目既然选的是 MySQL你在改连接配置时记住一条原则让 JDBC 驱动版本和数据库服务端版本尽量保持一致的代际不要拿 MySQL 8.0 的驱动去连 5.7 的库虽然能连上但 SSL 连接警告和时区问题会浪费你不少时间。3. 把项目变成可改的底子四步完成导入到运行的完整闭环3.1 数据库初始化先看脚本再建库这是整个项目能否跑通的第一道关卡。项目提供的 SQL 脚本是以.sql结尾的文件通常在db或sql目录下。打开脚本文件后建议我建议你先快速浏览一遍建表语句重点确认三张核心表的存在student学生表、course课程表、score成绩表。如果项目中还有admin或user表那是给登录功能用的有则说明系统包含登录鉴权逻辑没有也完全不影响成绩管理的核心流程。执行脚本的常见做法有两种一是用命令行工具 mysql二是用可视化工具如 Navicat。我习惯用命令行因为可以直接看到是否报错mysql -u root -p输入密码后进入 MySQL 交互环境source /path/to/student_score.sql;如果脚本里已经包含了CREATE DATABASE语句你就不需要手动建库脚本里只有CREATE TABLE而没有建库语句那就必须自己先创建库再USE选择该库。这是一个非常容易忽略的细节脚本执行完后发现表全部建在默认的test库里连数据库连接配置里的库名都对不上后面整个模块都会因为Table doesnt exist直接 500。3.2 导入 IDEA 并解决依赖缺失问题拿到项目源码后用 IntelliJ IDEA 打开时不要急着点运行按钮而是先检查项目的构建方式。如果是 Maven 工程在pom.xml文件上右键选择Add as Maven Project等待依赖下载完成即可。如果项目只有WEB-INF/lib下的 jar 包而没有pom.xml则需要手动导入依赖打开Project Structure快捷键CtrlAltShiftS选择Libraries把 lib 目录下所有 jar 包全选添加进来。这里还有个隐藏的坑需要点出来老项目的 jar 包可能混着不同版本的依赖。比如说servlet-api.jar这个包那是 Tomcat 已经自带的如果你把WEB-INF/lib下的这个包也放进Libraries会导致运行时冲突报错信息往往晦涩难懂。我的处理习惯是凡是 Tomcat 本身提供的 jarservlet-api、jsp-api都从项目的 lib 里剔除只保留数据库驱动和 JSTL 相关的包。做完这一步再启动 Tomcat整个部署过程才会顺畅。3.3 配置 Tomcat 的 Artifact 与访问路径在 IDEA 中点击右上角的运行配置选择Tomcat Server - Local然后在Deployment选项卡下点击加号选择Artifact。如果你的项目是 war exploded 模式即解压后的目录部署时会直接把 Web 根目录作为资源根路径这样修改 JSP 文件后无需重启 Tomcat刷新浏览器就能看到效果这正是开发阶段效率最高的配置方式。访问路径由Application context决定我在实际操作中会把它从默认的/项目名_war_exploded改成简洁的/score这样首页访问地址就是http://localhost:8080/score/。如果你不想改这个配置直接用默认路径访问也一样能跑但 URL 长了之后复制给别人演示时很不方便。改完这个配置后确认Server选项卡里的端口号没有被占用常见的 8080 被占用问题经常出在之前装过其他 Web 服务的情况。4. Bootstrap 页面改造的注意点在 JSP 里引用静态资源的方式最容易被忽略4.1 相对路径陷阱为什么 CSS 样式会突然消失这套项目用了 Bootstrap 作为前端框架页面里的表格和按钮看起来是那么回事儿。但如果你在浏览器里打开 JSP 页面发现所有样式全部失效页面变成纯文本的 HTML 堆积八成是静态资源的引用路径出了问题。产生这个问题的根源是在 JSP 页面中link标签里的href属性如果写的是相对路径css/bootstrap.min.css当请求地址从/score/index.jsp变为/score/student/list.jsp时浏览器解析出来的实际路径就变成了/score/student/css/bootstrap.min.css而文件根本不在那里。解决这个问题正确写法必须把路径改成从上下文根路径开始的绝对路径。具体有两种常用方式第一种是直接在 JSP 页面顶部获取上下文路径然后拼接% String path request.getContextPath(); % link href%path%/css/bootstrap.min.css relstylesheet第二种写法是利用 JSTL 的c:set标签简化操作。在改这个项目的前端页面时你要养成一个肌肉记忆凡是引用 JS、CSS、图片等静态资源的路径都必须用${pageContext.request.contextPath}作为前缀而不是图上画个相对路径就交差。我在给一个课程设计学生改这套代码时他花了半小时没解决样式失效的问题最后就是因为在student_add.jsp这个二层级目录的页面里写了相对的../css/bootstrap.min.css虽然当前能打开但转发到其他目录层级时就彻底崩了。4.2 成绩录入表单的交互逻辑与参数接收边界这个系统里成绩录入功能score_add.jsp是前后端交互比较典型的页面。前端需要一个下拉选择框让用户选择学生一个下拉选择课程一个文本框填写分数提交按钮汇聚表单数据交给 Servlet 处理。在 JSP 中使用 Bootstrap 的form-control类可以让这些控件在视觉上保持一致但要注意的是你在设置成绩录入的数值校验时必须依赖前端表单的required属性与 JS 校验加上后端 Servlet 里的二次校验两道关卡缺一道都容易出现脏数据入库。这里有个边界情况需要破一下所谓成绩它的取值范围应该限定在 0 到 100 之间。Bootstrap 在表单控件上可以搭配typenumber配合min和max属性在浏览器端做一层拦截但前端的校验无论多严密都不能替代后端 Servlet 中对取值的解析校验。如果在后端只用Integer.parseInt(request.getParameter(score))就完事没有判空和范围判断一旦传入一个非数字字符NumberFormatException会让整个页面直接 500。加一个小习惯把成绩参数的解析封装成一个独立方法返回布尔值或默认值这样既能复用又能兜底。4.3 修改 Bootstrap 默认样式而不是重写样式表覆盖顺序的玄学直接改 Bootstrap 源码里的变量或类名是最差的做法因为一旦项目里 Bootstrap 升级或更换文件你的修改全部丢失。正确做法是在 Bootstrap 的样式表引用之后再引入一个自定义的custom.css。CSS 样式覆盖取决于引入顺序后引入的相同优先级规则会覆盖先引入的同名规则所以custom.css必须放在 Bootstrap 的link之后才会生效。举个例子你想把表格表头的背景色从默认的灰色改成浅蓝不必重写整个table样式只需在custom.css中这样写.table thead th { background-color: #e3f2fd; color: #1a237e; }注意选择器的优先级.table thead th这样的写法比 Bootstrap 默认的.table th更具体在优先级上天然胜出不需要!important就能覆盖。如果你在改样式时发现覆盖不生效优先检查是不是选择器的优先级不够而不是盲目加!important。这种方式让你在保留 Bootstrap 框架的基础上把项目外观改成自己想要的配色方案对课程设计而言这通常是提分项。5. 避坑手册运行这套成绩管理系统最常见的 6 个报错与排查过程5.1 HTTP 500java.lang.NullPointerException在 ScoreDaoImpl 的第 43 行现象点击成绩查询按钮后页面上半部分正常渲染下半部分直接抛异常堆栈明确指出ScoreDaoImpl第 43 行为空。原因分析这一行在调用ResultSet.getString(course_name)时传入的列名与实际的数据库字段名不匹配。项目中的 SQL 语句如果使用了别名比如SELECT s.name AS student_name那么你只能通过getString(student_name)取数据如果表格里实际的列名就是student_name而你用的是原始的名字那结果集里根本没有这一列返回的就是空值。解决打开 MySQL 的查询日志或直接在 Navicat 里执行该 SQL 语句查看实际返回的列名确保getXxx(列名)与结果集的列标签一致。这是老项目最容易出现的字段名不一致问题因为表结构可能有微调但代码里的字符串没有同步更新。5.2 HTTP 404访问/score/student/list时提示资源不存在现象首页能访问点击学生管理菜单后浏览器地址栏变化了但页面显示 404。原因分析Servlet 的注解映射路径与前端 JSP 里表单或链接的action路径不一致。常见原因是项目里既有通过web.xml配置的servlet-mapping又有注解WebServlet两者冲突导致实际生效的 URL 不是你预期的那条。诊断方法打开 Tomcat 的日志文件确认容器启动时注册了哪些 Servlet或者在 IDEA 的Run控制台里看映射信息。解决统一使用注解方式配置删除web.xml中对应的 Servlet 声明前端所有跳转路径都要带上${pageContext.request.contextPath}作为前缀避免从二级页面发起请求时路径拼错。5.3 中文乱码学生姓名显示成问号现象数据库表里明明存的是中文查询列表页上显示的内容全是???。原因分析这一般不是数据库表的问题而是 JDBC 连接字符串里缺少编码参数或者 JSP 页面没有声明响应编码。解决步骤先在数据库连接串上加上useUnicodetruecharacterEncodingUTF-8然后在处理请求的 Servlet 中加request.setCharacterEncoding(UTF-8)最后确认 JSP 页面第一行有% page contentTypetext/html;charsetUTF-8 languagejava %。三层设置缺一不可漏掉任何一个环节都可能有编码转换异常被吞掉。我的排查习惯是先检查 JSP 页面头部的page指令再检查 Servlet 里有没有设置请求编码最后才去动连接串按从外到内的顺序逐一排除。5.4 连接超时Communications link failure报错现象点击登录按钮后页面卡很久然后报数据库连接失败。原因分析这个报错几乎都是因为 MySQL 服务端没有启动或者连接串里的端口号写错。如果是本机部署的默认配置端口是 3306如果你在安装 MySQL 的时候选过自定义端口那连接串里也要对应修改。还有一种隐蔽情况是MySQL 服务虽然启动了但对登录用户的 host 权限有限制默认创建的root只允许从 localhost 登录如果你的代码是通过局域网 IP 访问数据库就要确认账号权限覆盖了对应来源。解决先在本机命令行执行mysql -u root -p确认能正常连接再检查项目配置中的 IP、端口、库名三者完全对齐。5.5 文件上传功能无效点上传按钮页面刷新但没有反应现象ServletUploadFile这个类的存在说明系统应该有文件上传功能比如导入学生照片但实际点击上传没有任何反馈。原因分析老项目里的表单必须显式声明enctypemultipart/form-data才能触发文件上传逻辑如果 JSP 页面的form标签里只写了methodpost那 Servlet 里用getParameter()获取字段值是可以的但文件部分根本不会被解析。解决确认表单里加了enctypemultipart/form-data同时 Servlet 侧需要处理 Part 对象来接收文件流。如果当前项目用的是老的commons-fileupload组件处理逻辑会不同需要检查WEB-INF/lib下有没有commons-io.jar和commons-fileupload.jar这两个包。5.6 Tomcat 部署后页面样式错乱但代码检查没有发现问题现象JSP 引用 Bootstrap 的路径写法完全正确本地打开 HTML 文件也是正常的但部署到 Tomcat 后样式完全失效。原因分析存在浏览器缓存问题。浏览器为了加速加载把没有更新过的静态资源CSS、JS缓存到了本地虽然服务器上的文件已更新但浏览器还在用旧缓存。这属于开发阶段最常见的“玄学”问题实际上和代码没有关系。解决在静态资源的引用路径后加上版本参数强制刷新例如/css/bootstrap.min.css?v20240601这样浏览器会把老缓存当成新资源重新下载。从那以后我每次对这个项目做前端改动都会顺手改掉路径里的v参数从源头上避免样式失效的翻车现场。6. 验收与改造技巧把成绩查询做成真正的多条件组合过滤这套系统的基础功能如果已经能跑通你真正要做的其实是把它改造成一个像样的毕设作品或练习项目。有一个性价比最高的改造点把成绩查询模块从单项条件查询改成多条件组合查询。实现思路不复杂核心在 Dao 层拼接动态 SQL。先在前端表单里固定三个查询条件学生姓名、课程名称、分数区间。JSP 页面的表单是这样的结构form action${pageContext.request.contextPath}/score/query methodget input typetext namestudentName classform-control placeholder学生姓名 select namecourseId classform-control option value全部课程/option option value1Java程序设计/option option value2数据库原理/option /select input typenumber nameminScore classform-control placeholder最低分 min0 input typenumber namemaxScore classform-control placeholder最高分 max100 button typesubmit classbtn btn-primary查询/button /form对应的 Servlet 接收参数后传给 Dao 层动态拼接 SQLpublic ListScoreVO queryByCondition(String studentName, Integer courseId, Double minScore, Double maxScore) { StringBuilder sql new StringBuilder(SELECT * FROM score WHERE 11 ); ListObject params new ArrayList(); if (studentName ! null !studentName.trim().isEmpty()) { sql.append(AND student_name LIKE ? ); params.add(% studentName %); } if (courseId ! null) { sql.append(AND course_id ? ); params.add(courseId); } if (minScore ! null) { sql.append(AND score ? ); params.add(minScore); } if (maxScore ! null) { sql.append(AND score ? ); params.add(maxScore); } // 使用 PreparedStatement 按顺序填充参数 }这样写法的精妙之处在于WHERE 11这个恒真条件它只是为了后续拼接AND时不用判断是否是第一条代码看起来更省事。在参数传入判断上studentName要做空字符串判断而minScore和maxScore则要做空值判断。由于这些值是从 HTTP 请求中传输过来的request.getParameter()返回的都是字符串Servlet 层做类型转换时要小心NumberFormatException最好加一层 try-catch。改造完成后你要做的不只是点一遍页面看效果还要做一轮模拟边缘测试只输入学生姓名查询、只选课程查询、不填任何条件直接点查询此时应该数据全量返回。多条件组合过滤是对这套系统原本单条件查询能力的有力补充从功能完整度到代码结构都值得你自己动手敲一遍而不是复制粘贴。这套代码里还有一个可以在验收时提分的小细节把 Dao 层原来分散的Connection创建逻辑收拢到一个JdbcUtils工具类里每次获取连接的代码从原来的重复三行变为调用一个静态方法代码行数瞬间减少逻辑也清晰很多。我在后来接手其他老项目时都会先做这一步重构再谈新功能。希望这个项目能帮你在课程设计或练手路上省下一些琢磨环境的时间把精力放在真正该花心思的功能打磨上。希望帮到你。本文还有配套的精品资源点击获取
返回列表