ARTICLE DETAIL

资讯详情

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

JavaWeb毕设实战:JSP+Servlet+JDBC学生成绩管理系统部署与权限详解

JavaWeb毕设实战:JSP+Servlet+JDBC学生成绩管理系统部署与权限详解 简介本资源是一套完整可用的JavaWeb学生成绩管理系统毕设项目面向计算机专业本科生、Java初学者及需要实战练手的开发者解决高校教务场景中学生、教师、管理员三类角色的成绩录入、查询、统计与考勤管理等核心需求。压缩包共3个文件1个说明文档、1个MySQL数据库脚本、1个含全部源码的ZIP总大小6.38MB结构清晰SQL脚本用于快速建库建表TXT文档提供部署指引与功能说明源码包涵盖JSP页面、Servlet逻辑、JDBC连接及完整目录结构开箱即用。已有7846人学习下载系统基于JDKEclipseTomcat开发环境采用JSPServletMySQL技术栈包含学生/教师/班级/课程/成绩/系统设置/考勤七大模块功能完备、界面简洁、调试通过可直接用于毕业设计答辩或课程实训。1. 这不是又一个“Hello World”式毕设它真能跑通、真有权限隔离、真能导出成绩报表——专为计算机专业本科生卡在答辩前两周的你准备你是不是也经历过导师甩来一句“找个JavaWeb项目改改”然后搜到一堆“学生成绩管理系统”点开全是截图模糊、源码缺包、数据库脚本报错1072、Tomcat启动后404跳转失败的“半成品”这个项目不是。它压缩包里带的是可直接导入Eclipse、配好web.xml和context.xml、连上MySQL 5.7就能登录三类角色学生/教师/管理员的真实运行体不是PPT里的功能列表。它用最朴素的JSPServletJDBC组合不玩Spring Boot自动装配的玄学不依赖Maven中央仓库抽风时的网络运气所有jar包全打在WEB-INF/lib下——这意味着你断网也能编译、打包、部署。它解决的不是“能不能写毕设”的问题而是“能不能在答辩前三天把系统跑起来、让导师现场输入几个学号查出成绩单、导出Excel不乱码”的真实交付压力。适合正在赶毕设 deadline 的本科生、想补全JavaWeb全流程实操链路的转行者以及需要快速验证JDBC事务边界或JSP表单校验逻辑的带教工程师。2. 从解压到首页五步走通部署链每一步都踩过坑才敢写进这行命令2.1 解压即得完整工程结构看清目录层级是避免后续404的第一道防线拿到StudentManagementSystem.zip后不要直接双击打开先用命令行确认解压路径是否干净unzip -l StudentManagementSystem.zip | head -20你会看到标准JavaWeb目录树student_management_system/ ├── WebContent/ │ ├── index.jsp │ ├── login.jsp │ ├── WEB-INF/ │ │ ├── web.xml ← 关键Servlet映射在此 │ │ ├── lib/ ← 所有jar包已内置mysql-connector-java-5.1.47.jar等 │ │ └── classes/ ← 编译后的.class文件含servlet和dao ├── src/ ← Java源码包结构com.student.dao / com.student.servlet ├── db_student_manager_web.sql ← 数据库建表初始数据含管理员账号admin/123456 └── project说明.txt提示WebContent是Eclipse默认的Web根目录不是src/main/webapp。若你用IDEA导入需手动指定Web Root为WebContent否则JSP路径解析会失效。2.2 数据库初始化执行SQL脚本前必须确认的三个硬性条件db_student_manager_web.sql不是“一键执行就完事”的脚本。它包含CREATE DATABASE IF NOT EXISTS student_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;但你的MySQL必须满足字符集必须是utf8mb4不是旧版utf8SHOW VARIABLES LIKE character_set%; -- 确保 character_set_server utf8mb4若不是修改MySQL配置文件my.cnf[mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci用户权限要覆盖student_manager库CREATE USER sm_userlocalhost IDENTIFIED BY sm_pass123; GRANT ALL PRIVILEGES ON student_manager.* TO sm_userlocalhost; FLUSH PRIVILEGES;执行时禁用外键检查脚本内已写但部分MySQL版本需手动加SET FOREIGN_KEY_CHECKS 0; SOURCE /path/to/db_student_manager_web.sql; SET FOREIGN_KEY_CHECKS 1;执行成功后用Navicat或命令行验证USE student_manager; SELECT COUNT(*) FROM user; -- 应返回3条admin/teacher/student SELECT * FROM course LIMIT 1; -- 查看课程表字段是否含中文不乱码2.3 Eclipse环境配置JDK、Tomcat、项目属性三者必须咬合这不是“新建Dynamic Web Project”就能套进去的工程。它基于JDK 1.8 Tomcat 8.5兼容9.0配置步骤如下JDK版本锁定右键项目 → Properties → Java Build Path → Libraries → Remove JRE System Library → Add Library → JRE System Library → Execution environment →JavaSE-1.8Tomcat Runtime绑定Window → Preferences → Server → Runtime Environments → Add → Apache Tomcat v8.5 → Browse指向你的Tomcat安装目录如/opt/tomcat85项目Facets强制对齐右键项目 → Properties → Project Facets → 勾选Dynamic Web Module: 3.1不是4.0Servlet 3.1对应Tomcat 8.5Java: 1.8JavaScript: 1.0→ Apply后点击“Further configuration available…” → Content directory填WebContent→ Generate web.xml deployment descriptor验证web.xml是否生效打开WebContent/WEB-INF/web.xml确认存在servlet servlet-nameLoginServlet/servlet-name servlet-classcom.student.servlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/login/url-pattern /servlet-mapping这意味着访问http://localhost:8080/student_management_system/login会触发LoginServlet而非404。2.4 启动与首屏验证绕过常见404的三个关键检查点启动Tomcat后别急着输URL。先做三件事检查控制台输出是否有INFO: Starting ProtocolHandler [http-nio-8080]若只有INFO: Initializing ProtocolHandler [http-nio-8080]没后续说明Context未加载——检查server.xml中Host节点是否包含Context docBasestudent_management_system path/student_management_system reloadabletrue/确认项目发布路径Eclipse右键项目 → Run As → Run on Server → 选择Tomcat → Finish后观察Console是否打印INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat85/webapps/student_management_system] INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat85/webapps/student_management_system] has finished in 2,345 ms首屏访问地址必须带上下文路径正确地址http://localhost:8080/student_management_system/注意末尾斜杠错误地址http://localhost:8080/会进Tomcat默认页或http://localhost:8080/student_management_system/index.jsp可能因web.xml欢迎文件配置失效访问成功后首页应显示“学生成绩管理系统”标题栏底部有“©2023 计算机学院毕设项目”字样——这是源码里index.jsp的硬编码证明静态资源已加载。3. 登录与角色流转三类账户权限如何通过Filter和Session实现硬隔离3.1 账户体系与密码存储明文密码不是漏洞而是教学场景的刻意设计项目中所有密码admin/123456、teacher/123456、student/123456均以明文存于user表password字段。这不是疏忽而是教学项目的关键设计降低学习门槛初学者无需纠缠BCrypt加密流程、盐值管理、密码比对逻辑便于调试你在LoginServlet.java中可直接System.out.println(DB pwd: dbPwd , input pwd: inputPwd);验证流程符合毕设评审要求高校毕设答辩更关注业务逻辑完整性而非安全深度注意若你需升级为生产级只需替换UserDao.login()方法中的密码比对逻辑// 原始明文比对 if (dbPwd.equals(inputPwd)) { ... } // 替换为BCrypt需引入bcprov-jdk15on-1.68.jar if (BCrypt.checkpw(inputPwd, dbPwd)) { ... }3.2 Filter拦截器实现角色路由为什么学生打不开教师页面系统用AuthFilter.java位于src/com/student/filter/实现核心权限控制。其doFilter()方法关键逻辑public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); // 如 /student_management_system/teacher/course_list.jsp // 1. 放行登录页、静态资源、验证码 if (uri.contains(login.jsp) || uri.contains(css/) || uri.contains(js/)) { chain.doFilter(request, response); return; } // 2. 检查Session中是否存在user对象 HttpSession session req.getSession(false); if (session null || session.getAttribute(user) null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } // 3. 角色路由根据URL路径前缀匹配权限 User user (User) session.getAttribute(user); if (uri.contains(/student/) !student.equals(user.getRole())) { resp.sendRedirect(req.getContextPath() /error.jsp?msg无权访问学生模块); return; } if (uri.contains(/teacher/) !teacher.equals(user.getRole())) { resp.sendRedirect(req.getContextPath() /error.jsp?msg无权访问教师模块); return; } if (uri.contains(/admin/) !admin.equals(user.getRole())) { resp.sendRedirect(req.getContextPath() /error.jsp?msg无权访问管理员模块); return; } chain.doFilter(request, response); }关键点uri.contains(/student/)是路径前缀匹配非正则——所以/student/info.jsp能过/teacher/student_info.jsp会被拦截error.jsp接收msg参数并显示红字提示这是比HTTP 403更友好的教学反馈3.3 Session生命周期管理为什么登出后还能点浏览器后退看到数据LogoutServlet.java中执行HttpSession session request.getSession(false); if (session ! null) { session.invalidate(); // 销毁Session对象 } response.sendRedirect(request.getContextPath() /login.jsp);但用户点击浏览器后退仍能看到上一页如成绩列表这是因为浏览器缓存了页面HTML后退时未向服务器发请求直接渲染本地缓存解决方案在每个JSP顶部添加防缓存头已在header.jsp中预置% response.setHeader(Cache-Control, no-cache, no-store, must-revalidate); // HTTP 1.1 response.setHeader(Pragma, no-cache); // HTTP 1.0 response.setDateHeader(Expires, 0); // Proxies %验证方法登录后打开开发者工具F12→ Network → 切换到成绩页 → 点登出 → 点后退 → 查看Network中该页状态码应为200 (from disk cache)但内容为空白因JSP中% if(session.getAttribute(user)null) response.sendRedirect(login.jsp); %重定向4. 成绩导入与统计Excel解析、事务回滚、百分比计算的实战细节4.1 Excel批量导入Apache POI 3.17如何处理空单元格和日期格式ScoreImportServlet.java使用POI读取.xls文件不支持.xlsx这是教学简化。关键代码段HSSFWorkbook workbook new HSSFWorkbook(fileInputStream); HSSFSheet sheet workbook.getSheetAt(0); for (int rowNum 1; rowNum sheet.getLastRowNum(); rowNum) { // 跳过标题行 HSSFRow row sheet.getRow(rowNum); if (row null) continue; // 跳过空行 String stuNo getCellStringValue(row.getCell(0)); // 学号列 String courseName getCellStringValue(row.getCell(1)); // 课程名 Double score getCellNumericValue(row.getCell(2)); // 成绩列数字类型 // 处理空单元格POI返回null需转为空字符串或0.0 if (stuNo null || stuNo.trim().isEmpty()) { errorMsg.append(第 (rowNum1) 行学号为空); continue; } if (score null) { errorMsg.append(第 (rowNum1) 行成绩为空); continue; } // 插入数据库... }getCellStringValue()和getCellNumericValue()是自定义工具方法处理POI的Cell.CELL_TYPE_STRING/CELL_TYPE_NUMERIC/CELL_TYPE_BLANK三种类型。特别注意Excel中日期单元格会被POI识别为CELL_TYPE_NUMERIC需用DateUtil.isCellDateFormatted(cell)判断并格式化。4.2 成绩统计模块JDBC事务如何保证“导入统计”原子性ScoreService.java中importAndCalculate()方法开启手动事务Connection conn null; PreparedStatement psInsert null; PreparedStatement psUpdate null; try { conn JDBCUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交 // 步骤1插入新成绩记录 psInsert conn.prepareStatement(INSERT INTO score(stu_no, course_id, score, exam_date) VALUES (?, ?, ?, ?)); for (Score score : scoreList) { psInsert.setString(1, score.getStuNo()); psInsert.setInt(2, score.getCourseId()); psInsert.setDouble(3, score.getScore()); psInsert.setDate(4, new java.sql.Date(score.getExamDate().getTime())); psInsert.addBatch(); } psInsert.executeBatch(); // 步骤2更新课程平均分、及格率 psUpdate conn.prepareStatement( UPDATE course SET avg_score (SELECT AVG(score) FROM score WHERE course_id ?), pass_rate (SELECT COUNT(*)*100.0/COUNT(score) FROM score WHERE course_id ? AND score 60) WHERE id ?); for (Score score : scoreList) { psUpdate.setInt(1, score.getCourseId()); psUpdate.setInt(2, score.getCourseId()); psUpdate.setInt(3, score.getCourseId()); psUpdate.addBatch(); } psUpdate.executeBatch(); conn.commit(); // 全部成功才提交 } catch (SQLException e) { if (conn ! null) conn.rollback(); // 任一环节失败则回滚 throw e; } finally { JDBCUtil.close(psInsert, psUpdate, conn); }血泪经验若忘记conn.setAutoCommit(false)插入成功但更新失败时成绩已入库却无法回滚——这就是为什么JDBCUtil.getConnection()方法里明确注释“此连接用于事务请勿在其他地方复用”。4.3 百分比计算陷阱MySQL的COUNT(*)与COUNT(score)差异在course表中pass_rate字段定义为DECIMAL(5,2)但SQL中SELECT COUNT(*)*100.0/COUNT(score) FROM score WHERE course_id ? AND score 60这里COUNT(score)只统计非NULL成绩而COUNT(*)统计所有行。若某课程有10条记录其中2条score为NULL未录入则COUNT(*) 10COUNT(score) 8COUNT(*)*100.0/COUNT(score) 125.00错误及格率不可能超100%正确写法已在db_student_manager_web.sql中修正SELECT COUNT(CASE WHEN score 60 THEN 1 END)*100.0/COUNT(*) FROM score WHERE course_id ?这样分子分母都基于同一COUNT(*)基数且CASE确保只计及格人数。5. 避坑指南那些让你在凌晨三点对着Tomcat日志抓狂的5个真实问题5.1 现象登录后跳转到/student_management_system/teacher/teacher_list.jsp页面空白且Console无报错原因teacher_list.jsp中% page contentTypetext/html;charsetUTF-8%缺失导致JSP编译时默认ISO-8859-1中文字段显示为??进而c:forEach遍历request.getAttribute(teacherList)时因编码异常中断渲染解决在所有JSP顶部强制声明% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%并在web.xml中全局配置filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping5.2 现象导入Excel时抛出java.lang.NoClassDefFoundError: org/apache/poi/hssf/usermodel/HSSFWorkbook原因WEB-INF/lib下POI jar包版本不匹配项目用3.17你误放了5.2.4或缺少commons-collections4-4.4.jarPOI 3.17依赖解决核对lib目录文件清单poi-3.17.jar poi-scratchpad-3.17.jar commons-collections4-4.4.jar commons-codec-1.10.jar删除所有poi-*.jar除3.17外重新下载 POI 3.175.3 现象管理员修改教师密码后该教师下次登录报java.sql.SQLException: Column password cannot be null原因TeacherDao.updatePassword()中SQL语句写成String sql UPDATE teacher SET password? WHERE id?; // 但teacher表中password字段定义为NOT NULL而前端传入空字符串JDBC将转为NULL解决在DAO层增加空值校验if (newPassword null || newPassword.trim().isEmpty()) { throw new IllegalArgumentException(密码不能为空); } // 或在SQL中用COALESCE String sql UPDATE teacher SET passwordCOALESCE(?, password) WHERE id?;5.4 现象考勤统计页attendance_report.jsp中图表不显示Console报ReferenceError: echarts is not defined原因echarts.min.js被放在WebContent/js/但JSP中引用路径写成script srcjs/echarts.min.js/script而当前页面URL为/student_management_system/admin/attendance_report.jsp相对路径解析为/student_management_system/admin/js/echarts.min.js404解决统一用绝对路径script src${pageContext.request.contextPath}/js/echarts.min.js/script${pageContext.request.contextPath}会动态输出/student_management_system确保路径正确。5.5 现象Tomcat启动后CPU飙升100%jstack发现大量org.apache.tomcat.util.net.NioEndpoint$Poller.run()线程阻塞原因JDBCUtil.getConnection()中数据库连接池未配置最大连接数MySQL默认max_connections151当并发请求超限连接等待队列溢出导致线程死锁解决在JDBCUtil.java中硬编码连接池参数教学简化版private static final int MAX_CONNECTIONS 20; private static final int TIMEOUT_SECONDS 30; // 并在getConnection()中添加超时检测 if (connectionCount.get() MAX_CONNECTIONS) { throw new SQLException(数据库连接池已满请稍后重试); }6. 毕设答辩加分技巧三招让导师眼前一亮的定制化改造6.1 成绩分析页嵌入动态折线图用ECharts 4.9.0绘制班级成绩趋势原系统student/score_analysis.jsp仅用HTML表格展示数据。要让它“活”起来只需三步引入ECharts CDN避免本地JS路径问题在head中添加script srchttps://cdn.jsdelivr.net/npm/echarts4.9.0/dist/echarts.min.js/script构造JSON数据接口新增ScoreAnalysisServlet.javaprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String classId request.getParameter(class_id); ListScoreTrend trends ScoreService.getScoreTrendByClass(classId); response.setContentType(application/json;charsetUTF-8); response.getWriter().write(new Gson().toJson(trends)); }ScoreTrend类包含term学期、avgScore平均分、passRate及格率字段。前端渲染图表在score_analysis.jsp底部div idchart stylewidth: 800px;height:400px;/div script var chart echarts.init(document.getElementById(chart)); $.get(${pageContext.request.contextPath}/scoreAnalysis?class_id${classId}, function(data){ var option { title: { text: 2023级软件工程1班成绩趋势 }, tooltip: { trigger: axis }, xAxis: { data: data.map(d d.term) }, yAxis: {}, series: [ { name: 平均分, type: line, data: data.map(d d.avgScore) }, { name: 及格率, type: line, data: data.map(d d.passRate) } ] }; chart.setOption(option); }); /script效果答辩时点击班级下拉框实时刷新折线图——导师会立刻意识到你掌握了前后端数据交互而非只会CRUD。6.2 导出Excel增加样式用Apache POI设置表头背景色和边框ExportScoreServlet.java原生导出无格式。增强版代码HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(成绩表); HSSFCellStyle headerStyle workbook.createCellStyle(); headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); headerStyle.setBorderBottom(BorderStyle.THIN); headerStyle.setBorderLeft(BorderStyle.THIN); headerStyle.setBorderRight(BorderStyle.THIN); headerStyle.setBorderTop(BorderStyle.THIN); HSSFRow headerRow sheet.createRow(0); String[] headers {学号, 姓名, 课程, 成绩, 考试日期}; for (int i 0; i headers.length; i) { HSSFCell cell headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } // 自动列宽 for (int i 0; i headers.length; i) { sheet.autoSizeColumn(i); }价值点毕设文档中可截图对比“原始导出”vs“美化导出”证明你具备用户体验意识——这比单纯实现功能更能体现工程素养。6.3 权限细化到按钮级用JSTL标签库控制操作按钮显隐原系统角色权限只到页面级。要体现“细粒度控制”在teacher/course_list.jsp中% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % c:if test${user.role admin} button onclicklocation.hrefadmin/add_course.jsp添加课程/button /c:if c:if test${user.role teacher user.courseId course.id} button onclickeditScore(${score.id})修改成绩/button /c:if关键逻辑user.courseId是教师实体中关联的授课课程ID确保教师只能修改自己所教课程的成绩——这比“教师角色能访问所有课程页”更真实。从那以后我每次做毕设演示都会在答辩前强制走一遍这三步用Chrome隐身模式登录三类账号验证权限隔离无漏洞导入一份含100条记录的Excel检查事务回滚是否生效故意制造一条重复学号打开开发者工具Network确认所有AJAX请求返回200且响应体含预期JSON。这三步做完心里才有底——不是因为代码完美而是因为所有可能翻车的点我都亲手碾过一遍。希望帮到你。本文还有配套的精品资源点击获取
返回列表