ARTICLE DETAIL

资讯详情

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

JavaWeb学生成绩管理系统实战:从报错到上线的完整闭环

JavaWeb学生成绩管理系统实战:从报错到上线的完整闭环 简介本资源是一套基于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 ProjectEclipse 风格若只有web/目录且含WEB-INF/web.xml就是标准 JavaEE Web 应用src/下是否有servlet包和dao包确认是否为 MVC 分层如com.example.servlet.StudentServletcom.example.dao.StudentDaoImpllib/目录是否存在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 中File → Open → 选择解压后的根目录不是.rar文件弹窗提示 “Project type detected: Java” 时务必勾选 “Create project from existing sources”在 Project SDK 步骤选 JDK 8JDK 11 也可但需确认web.xml中version2.5或3.0与 Tomcat 版本匹配关键一步不要点 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 ServerRun → Edit Configurations → → Tomcat Server → LocalDeployment → → Artifact → 选择your_project_name:war exploded注意是 exploded不是 warApplication context 必须填/或/score不能留空否则访问http://localhost:8080/会 404VM options 加-Dfile.encodingUTF-8防中文乱码JRE 选与项目一致的 JDKJDK 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。执行前必须处理三个兼容性问题认证插件变更MySQL 8.0 默认用caching_sha2_password而老版 JDBC 驱动不支持。执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;时区报错连接 URL 必须显式指定时区否则java.sql.SQLException: The server time zone value XXX is unrecognized# db.properties 中的 url 示例关键 urljdbc:mysql://localhost:3306/score_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8表引擎与字符集建表语句中必须含ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci否则中文插入失败。执行建表后用 Navicat 或命令行验证SELECT COUNT(*) FROM student;返回非零值说明数据已就位。3. 核心功能链路打通从登录到成绩导出的四步数据流3.1 登录模块Session 管理与角色跳转逻辑典型流程login.jsp→LoginServlet→UserService.login()→ 成功则request.getSession().setAttribute(user, user)→ 重定向到main.jsp。关键代码片段LoginServlet.javaprotected 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.jspforward是服务端跳转URL 仍为login。此处必须用 redirect否则刷新main.jsp会重复提交登录请求。参数说明setMaxInactiveInterval(1800)单位是秒30 分钟无操作自动销毁 session。3.2 成绩录入Servlet 接收表单 DAO 执行 INSERTaddScore.jsp表单提交到AddScoreServletform actionAddScoreServlet methodpost input typetext namestudentId placeholder学号 input typetext namecourseName placeholder课程名 input typenumber namescore placeholder成绩 button typesubmit提交/button /formAddScoreServlet.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?methodlistpage1size10请求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); // 支持按学号/姓名模糊查 PageBeanScore 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} vars tr td${s.id}/td td${s.studentId}/td td${s.studentName}/td !-- 关联查询学生表获取姓名 -- td${s.courseName}/td td${s.score}/td tdfmt:formatDate value${s.createTime} patternyyyy-MM-dd HH:mm//td tda hrefScoreServlet?methoddeleteid${s.id}删除/a/td /tr /c:forEach注意PageBean是自定义分页实体含list当前页数据、total总记录数、page、size、totalPage字段fmt:formatDate需引入% taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt %。3.4 成绩导出生成 Excel 并响应二进制流ExportServlet.java调用 Apache POIHSSFWorkbook 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]); } // 写数据 ListScore 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;filenamescore_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后追加;charsetutf-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?methodupdateid123score95被缓存再次访问时返回旧响应。解决在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直接写password123456上线即高危。改造方案用 AES 对密码加密存储启动时解密。步骤用工具类生成密钥只运行一次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())); } }将生成的 Base64 密钥存入config/key.txt修改JDBCUtil.javapublic 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.javapublic 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-nameLoginFilter/filter-name filter-classcom.example.filter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/*/url-pattern /filter-mapping效果所有受保护路径除白名单外自动跳转登录页无需在每个 Servlet 里写if (session null)代码更干净权限控制更集中。5.3 添加简单日志用 Log4j 记录关键操作登录、增删改log4j.properties放入src/目录log4j.rootLoggerINFO, FILE log4j.appender.FILEorg.apache.log4j.RollingFileAppender log4j.appender.FILE.Filelogs/app.log log4j.appender.FILE.MaxFileSize10MB log4j.appender.FILE.MaxBackupIndex5 log4j.appender.FILE.layoutorg.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 个学生的并发查分。希望帮到你。本文还有配套的精品资源点击获取
返回列表