ARTICLE DETAIL

资讯详情

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

JSP+Servlet成绩管理系统课设实战:权限设计、部署与避坑指南

JSP+Servlet成绩管理系统课设实战:权限设计、部署与避坑指南 简介一份基于 JSPServlet 实现的 Web 成绩管理系统项目资源面向 Java Web 课程设计、毕业设计及初学者进阶学习。系统按角色划分为学生、教师、管理员三大模块覆盖个人信息查询与修改、本人成绩查询、教师端成绩录入/修改/查看/分析以及管理员对学生、教师、班级、课程的增删改查和课程安排、用户管理、班级分配等完整业务场景。压缩包共 870 个文件以 Java 源码、JSP 页面、JavaScript、CSS 样式为主包含 93 个 Java 类、46 个 JSP 页面、212 个 JS 文件、174 个 CSS 文件并附 SQL 数据库脚本、图片素材与说明文档整体约 39.64MB目录结构清晰便于部署和二次开发。已有 173 人学习下载。借助该资源可快速掌握 JSPServletMySQL 的项目分层、权限控制与业务模块实现思路获得从建库、编码到页面展示的完整参考示例适合完成课程设计或提升 Java Web 开发能力。1. 这套 JSP Servlet 成绩管理系统课程设计直接拿去用如果你正在找一套能跑通、能答辩的 Web 成绩管理系统这套基于 JSP Servlet MySQL 的课设项目值得花半小时拆一遍。它把学生、教师、管理员三个角色的权限分得清清楚楚学生只能查自己的个人信息和成绩教师负责成绩的录入、修改与分析管理员则管着学生、教师、班级、课程这些基础数据的增删改查。换句话说它覆盖了 Java Web 课程设计里最典型的那条主线——Servlet 接收请求、调用业务逻辑、JSP 渲染页面、MySQL 存数据。无论是拿来应付期末课设还是想搞清楚一个完整 Web 项目从登录到 CRUD 的流转过程这套代码都够用。下面我从功能边界、表结构、部署流程和踩坑点四个角度把它拆开。2. 三个模块的权限边界学生、教师、管理员到底能干什么2.1 学生端查自己和改自己别给它多余权限学生模块的功能设计得很收敛就两件事个人信息查询与部分信息修改以及本人成绩的查询。这里的关键词是「本人」。也就是说学生登录之后系统必须根据 session 里存的学号去过滤数据而不是让学生自己传一个学号进来查。常见的实现方式是登录成功后把用户信息写入 session后续所有查询都从 session 取值。比如学生查询成绩时Servlet 里的逻辑大致是// StudentScoreServlet.java HttpSession session request.getSession(); String studentNo (String) session.getAttribute(studentNo); if (studentNo null) { response.sendRedirect(login.jsp); return; } String sql SELECT c.course_name, sc.score FROM score sc JOIN course c ON sc.course_id c.id WHERE sc.student_no ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, studentNo); ResultSet rs ps.executeQuery();这段代码的关键在两点一是先校验 session 里有没有登录标识没有就直接跳回登录页二是 SQL 里用?占位符传参而不是拼接字符串。很多课设项目在学生模块翻车就是因为让学生从前端页面传学号参数结果把 URL 里的studentNo一改就能查别人的成绩。这个坑在答辩时经常被老师点名属于安全边界问题。学生端还有一个「部分信息修改」的功能所谓「部分」一般是允许改手机号、邮箱、家庭住址这类联系方式但学号、姓名、班级不允许动。实现上就是 UPDATE 语句只更新允许的字段页面上的学号输入框设为 readonly。2.2 教师端录入、修改、查看、分析一条线教师模块比学生端重核心是成绩管理。它的功能点拆开看是四个动作录入、修改、查看、分析。录入和修改可以共用一个表单页面区别只在提交时是否携带成绩记录 ID。录入场景下教师先选择课程系统把选修这门课的学生列表拉出来然后逐条填成绩。这里有个实现细节值得注意录入通常按课程批量提交一个表单里有多行学生成绩Servlet 接收时用数组或者循环遍历// ScoreEntryServlet.java String courseId request.getParameter(courseId); String[] studentNos request.getParameterValues(studentNo); String[] scores request.getParameterValues(score); for (int i 0; i studentNos.length; i) { String studentNo studentNos[i]; String scoreValue scores[i]; if (scoreValue null || scoreValue.trim().isEmpty()) { continue; // 跳过没填成绩的学生 } // INSERT INTO score(course_id, student_no, score) VALUES(?, ?, ?) }这里用getParameterValues接数组是关键普通的getParameter只能拿到第一个值。另外要注意的是录入前最好先查一下这条记录是否已存在已存在的改成 UPDATE否则第二次录同一门课时会主键冲突。查看功能相对简单按课程或者按班级筛选成绩列表。分析功能在课设里一般做到统计层面就够比如计算某门课的平均分、最高分、最低分和及格率用 SQL 的 AVG、MAX、MIN 加条件统计就能实现不需要引入额外的图表库。2.3 管理员端基础数据的增删改查是重头戏管理员模块是这套系统里工作量最大的部分学生管理、教师管理、班级管理、课程管理四个 CRUD加上课程安排、系统用户管理、为学生分配班级。这四个 CRUD 的结构几乎一样都是典型的「列表页 新增表单 编辑表单 删除确认」四件套。Servlet 里用一个 action 参数区分操作类型是很多课设项目的写法// AdminStudentServlet.java String action request.getParameter(action); if (add.equals(action)) { // 新增学生 } else if (edit.equals(action)) { // 跳转编辑页并回显旧数据 } else if (update.equals(action)) { // 执行 UPDATE } else if (delete.equals(action)) { // 执行 DELETE }这种写法把多个操作塞进一个 Servlet优点是文件少、逻辑集中缺点是 action 一多方法就膨胀。答辩时如果老师问「为什么不用多个 Servlet」你可以说这是为了减少 web.xml 里的映射配置属于课程设计里权衡可维护性和代码量的常见做法。课程安排功能本质上是给班级关联课程实现上就是在班级表和课程表的关联表里插记录。为学生分配班级同理是在学生表上维护一个班级 ID 外键。管理员模块设计时要留意的点是删除学生或教师前必须检查他们名下是否已有成绩记录否则外键约束会直接报错这在第 5 章避坑部分会展开说。3. 后台表结构与数据流转从班级、课程到成绩的关联方式3.1 六张核心表的字段设计与外键关系这套系统后台的数据模型不复杂核心就六张表。我把字段设计和关联关系整理如下表名关键字段说明studentid, student_no, name, password, class_id, phone, emailstudent_no 唯一teacherid, teacher_no, name, password, phoneteacher_no 唯一adminid, admin_no, name, password后台登录账号classid, class_name, grade年级信息可以单独拆字段courseid, course_name, credit学分字段在课设里常被忽略scoreid, student_no, course_id, score联合唯一约束 student_no course_idstudent 表的 class_id 指向 class 表的主键score 表的 student_no 和 course_id 分别指向 student 表和 course 表。班级和课程之间如果有「课程安排」功能一般还要加一张 schedule 关联表或者直接在 course 表上挂一个 class_id 字段看你项目里是「一门课属于一个班」还是「一个班有多门课」。前者在 course 表加字段就行后者需要中间表。原项目描述里「课程的安排」和「为学生分配班级」是两个独立功能建议把课程安排做成选课关系也就是 student_course 中间表这样更灵活成绩表也能直接关联这条选课记录。建表 SQL 里最容易漏的是联合唯一约束。同一门课同一个学生只能有一条成绩记录这个约束在数据库层面必须卡住CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL, course_id INT NOT NULL, score DECIMAL(5,2), UNIQUE KEY uk_student_course (student_no, course_id), FOREIGN KEY (student_no) REFERENCES student(student_no), FOREIGN KEY (course_id) REFERENCES course(id) );这个UNIQUE KEY加上后就算代码里忘了判断成绩是否已存在数据库也会拒绝插入重复记录。课设项目里数据库层级的约束越严答辩时老师越挑不出毛病。3.2 成绩录入的两次查询先按课程筛学生再按学号定位成绩录入界面的数据流转值得单独讲因为它是前后端交互最频繁的页面。教师打开录入页面时第一步要选课程第二步要看到这门课对应的学生列表。这里涉及一次关联查询// 查询选了某门课的学生 String sql SELECT s.student_no, s.name FROM student s JOIN student_course sc ON s.student_no sc.student_no WHERE sc.course_id ?;如果是简化版系统没有选课中间表那就直接「按班级查学生」先选班级再选课程然后把该班级所有学生列出来。两种方案都能跑通区别在于前者更接近真实教务系统的逻辑后者代码量更少。我一般建议课设用后者因为答辩时逻辑更容易讲清楚班级下的所有学生都要学这门课录入页面一次性填完。成绩提交后的处理顺序是先判断成绩是否已存在存在则 UPDATE不存在则 INSERT。判断依据是 student_no 和 course_id 的组合。这一步可以用SELECT COUNT(*)查一下也可以依赖刚才说的唯一约束直接尝试 INSERT捕获到重复键异常再转 UPDATE。后一种写法更简洁但对异常处理要求高课设阶段用COUNT(*)判断可读性更好。4. 把项目跑起来从导入到部署的完整流程4.1 导入 Eclipse 之前的三个前置条件拿到源码包后第一件事不是打开 IDE而是确认环境。这套项目是 JSP Servlet 的经典组合需要 JDK 8、Tomcat 8.5 或 9.x、MySQL 5.7以及一个支持 Dynamic Web Project 的 IDEEclipse EE 或 IDEA 都可以。如果你用的是 IDEA导入时注意别选错项目类型。源码包如果自带.project和.classpath文件说明是 Eclipse 工程IDEA 里可以通过File - New - Project from Existing Sources导入选 Eclipse 格式如果只有 Java 源码和 JSP那就新建 Dynamic Web Project 后手动拷源码。这个步骤看着简单很多新手在这里卡住因为 IDEA 对 Eclipse 工程的兼容性不是百分之百导入后经常出现依赖丢失。前三件事按顺序做装好 JDK 并配好JAVA_HOME确认 Tomcat 能独立启动并访问localhost:8080MySQL 服务已启动且能连上。这三个前置条件满足后再谈导入项目。4.2 数据库初始化与连接池配置项目里一般会带 SQL 脚本名字可能是database.sql或init.sql。打开后先看里面有没有CREATE DATABASE语句没有的话手动建库mysql -u root -p # 输入密码后执行 CREATE DATABASE score_db DEFAULT CHARACTER SET utf8mb4; USE score_db; SOURCE /你的路径/init.sql;用utf8mb4而不是utf8是血泪教训。utf8 在 MySQL 里最多存 3 字节遇到 Emoji 这种 4 字节字符直接报错。虽然课设项目里不太可能存 Emoji但学生姓名里有生僻字时也有概率触发问题干脆建库时统一用utf8mb4。数据库连接配置看项目用的哪种方式。老课设项目多半是 JDBC 直连在 DBUtil 类里写死连接串// DBUtil.java private static final String URL jdbc:mysql://localhost:3306/score_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456;注意 URL 里的四个参数useUnicodetrue和characterEncodingutf8解决中文乱码useSSLfalse避免连接时 SSL 警告serverTimezoneAsia/Shanghai解决 MySQL 8 的时区报错。如果你的 MySQL 是 5.7serverTimezone可以不加但加了也不影响。如果你的数据库密码不是123456记得改 DBUtil 里的PASSWORD常量。4.3 部署到 Tomcat 并验证登录部署分两种姿势。Eclipse 里直接把项目 Add 到 Tomcat 的 Server 中启动后访问http://localhost:8080/项目名/。IDEA 里配置 Tomcat 的 Artifact 为war exploded然后 Run。这里有个常见坑项目的 context path。Eclipse 默认用项目名作为 context path比如项目叫StudentScoreSystem访问路径就是localhost:8080/StudentScoreSystem。如果项目里 JSP 页面的链接写的是绝对路径比如/login.jsp部署后刷新一下就没有 CSS 样式了因为路径里的项目名丢了。这个问题第 5 章会详细说这里先记住部署后访问首页先看地址栏里的路径结构。启动成功后用管理员账号登录进后台随便点几个菜单。如果页面能正常跳转、数据库里能查到数据说明项目整体跑通了。值得多测一步的是教师端的成绩录入这个功能涉及数组参数传递最容易因为版本或 JSP 表单写法不对而报空指针。表单里多个同名 input 控件name 属性必须完全一致这样 Servlet 才能用getParameterValues拿到数组。表单名重复是低级错误但确实是出现频率最高的错误之一。5. 避坑指南JSP Servlet 项目最常见的五个翻车点5.1 中文乱码从页面到数据库三层都不省心现象JSP 页面显示中文正常但提交中文到数据库后存进去的是乱码或者从数据库查出来在页面上显示成问号。原因三层编码不统一。浏览器提交时是 UTF-8Servlet 里 request 默认按 ISO-8859-1 解码数据库连接 URL 没加characterEncodingutf8JSP 页面本身没声明pageEncoding。解决三层逐一处理。Servlet 里在读取参数前加request.setCharacterEncoding(UTF-8); response.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8);JSP 页面头部声明% page contentTypetext/html;charsetUTF-8 languagejava pageEncodingUTF-8 %数据库连接 URL 带上characterEncodingutf8。这三处都改到位中文乱码基本绝迹。另外新建数据库时就用utf8mb4字符集否则即使代码全对表结构本身的字符集不对照样乱码。5.2 页面 404Servlet 映射访问不到现象登录后跳转成绩查询地址输对了Tomcat 返回 404。控制台没有报错。原因最常见的是 web.xml 里没有配置 Servlet 映射或者配置的 URL 模式和表单提交地址对不上。第二种常见情况是用了WebServlet注解但没写loadOnStartup导致路由冲突。解决检查 web.xml 中servlet-mapping的url-pattern是否与表单 action 完全一致。比如表单提交到score/listweb.xml 里写的却是ScoreListServletservlet servlet-nameScoreListServlet/servlet-name servlet-classcom.xxx.servlet.ScoreListServlet/servlet-class /servlet servlet-mapping servlet-nameScoreListServlet/servlet-name url-pattern/score/list/url-pattern /servlet-mapping注意url-pattern必须以/开头。还有一种情况是项目用了注解方式但 web.xml 版本是 3.0 以下注解不生效。这时候要么升级 web.xml 头部的version3.0要么把注解删掉改用 xml 映射。5.3 驱动找不到ClassNotFoundException 与连接失败现象启动项目后点登录页面报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者报Communications link failure。原因ClassNotFoundException是 mysql-connector-java.jar 没放进WEB-INF/lib目录。很多人只把 jar 加到 Build Path但部署时 Tomcat 加载的是 WebContent/WEB-INF/lib 下的 jar。Communications link failure则多半是 MySQL 服务没启动或者 3306 端口被防火墙挡了。解决把mysql-connector-java-版本.jar物理复制到WEB-INF/lib目录下然后Build Path - Add to Build Path。这一步做完后删掉 Tomcat 的缓存重新启动。MySQL 连接失败时先用telnet localhost 3306确认端口能通再用systemctl status mysqlLinux或服务管理器Windows确认 MySQL 进程活着。5.4 页面样式全丢静态资源路径被项目名坑了现象登录页能显示但 CSS、JS、图片全部加载不出来页面像脱了一层皮。原因JSP 页面里引用静态资源用了/css/style.css这种绝对路径部署后 context path 是/项目名浏览器请求的却是localhost:8080/css/style.css自然 404。解决JSP 里统一用request.getContextPath()拼路径link relstylesheet href${pageContext.request.contextPath}/css/style.css这个写法在JSP 页面里要养成习惯任何链接、表单 action、静态资源引用都用${pageContext.request.contextPath}前缀。项目部署名一改所有路径自动跟着变不会出现换了个 name 就全站裸奔的情况。热词里有人搜jsp 图片如何对坐标定位其实很多时候不是定位问题是图片本身就没加载出来先解决路径问题再看定位。5.5 删除班级提示外键约束失败现象管理员在班级管理里删除一个班级后台抛外键约束异常或者删完班级后学生列表里的班级 ID 变成悬空值。原因class 表被 student 表的 class_id 外键引用。直接 DELETE class 时MySQL 外键约束拒绝删除有子记录的主表数据。解决删除前先处理子表数据二选一。要么先把该班级下的学生迁移到其他班级要么禁止删除并提示「该班级下还有学生」。课设项目里推荐后者实现上就是删除前查一下String countSql SELECT COUNT(*) FROM student WHERE class_id ?; // 如果 count 0, 返回提示, 不执行删除顺带说一句删除课程也是一样的逻辑。课程如果已经被成绩表引用删的时候同样会被外键拦截。第 3 章建表时把外键约束建好这里删不掉的报错反而是保护机制说明约束生效了答辩时能拿这个当正面案例讲。6. 从课程设计到答辩验证功能与低成本改造6.1 答辩前必测的六条功能路径功能跑通不等于能答辩。答辩时老师会从三个角色各挑一条链路来走任何一条断掉都很尴尬。我建议按下面这张清单过一遍角色测试链路预期结果学生改个人手机号 → 查询成绩手机号更新成功成绩只显示本人教师选课 → 录入成绩 → 修改成绩 → 查看分析录入后列表有记录修改后分数变化管理员新增学生 → 分配班级 → 给该生选课学生出现在班级列表和成绩录入页管理员删除已有成绩的学生系统拦截或级联处理不报 500任意角色退出后直接访问内部页面 URL跳回登录页任意角色中文姓名/课程名录入与查询无乱码无问号最后两条尤其重要。未登录直接访问内部 URL 跳回登录页说明 session 校验起了作用这是安全性的一个基本得分点。中文乱码问题在第 5 章提过答辩前用中文数据走一遍全流程能提前暴露编码问题。6.2 三个低成本优化如果时间充裕加下面三个小改动能让项目在答辩时明显加分而且工作量都不大。第一个改动是登录失败提示。很多课设项目登录失败只跳回登录页什么提示都不给老师看着像 Bug。在 Servlet 里判断用户或密码错误时request 里放一条提示消息后转发回登录页request.setAttribute(msg, 账号或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response);登录页面上加span stylecolor:red${msg}/span。这一处改动大概五分钟但交互体验立刻不一样。第二个改动是成绩分析页面加一个简单的统计表。用一条 SQL 同时查出平均分、最高分、最低分、及格人数和总人数然后在页面用表格展示。这条 SQL 看着复杂但写起来很快SELECT course_id, AVG(score) AS avg_score, MAX(score) AS max_score, MIN(score) AS min_score, SUM(CASE WHEN score 60 THEN 1 ELSE 0 END) AS pass_count, COUNT(*) AS total_count FROM score WHERE course_id ? GROUP BY course_id;第三个改动是密码不存明文。课设项目里密码明文存储非常普遍但答辩时老师一句「密码为什么要明文存」会问住不少人。低成本的方案是用 JSP 页面提交前做一次 SHA-256 散列或者干脆在 Servlet 里对输入的密码先转成散列值再比对。注意散列后数据库中也要存散列值登录比对的是散列结果。这个改动唯一的坑是要保证注册、登录、修改密码三处都走同一种散列方法漏一处就登录不上了。把那以后我每次拿到课设项目源码都会强制走一遍「建库 → 跑通 → 换路径 → 试中文 → 试越权」这五步。前两步确认项目能跑后面三步才是答辩过不过的关键。特别是「试越权」这一步把学生账号登录后手改 URL 访问教师页面能扛住这一下的项目基本不用太担心。答辩前一天再按上面那张六条链路表过一遍把截图存好讲的时候至少不会慌。希望这套 JSP Servlet 成绩管理系统能帮你把课设顺利交付也把这些 Web 开发的基本功真正攒到自己手里。本文还有配套的精品资源点击获取
返回列表