尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Servlet+JSP的JavaWeb选课系统:三端权限与核心业务实现

基于Servlet+JSP的JavaWeb选课系统:三端权限与核心业务实现 简介本资源是一套基于ServletJSP实现的学生选课系统面向计算机相关专业正在做毕设的学生以及需要JavaWeb项目实战练习的学习者可直接作为毕业设计参考使用。项目采用JavaWeb、Servlet与MySQL构建后端前端使用CSS、Bootstrap、jQuery与JSP开发环境为IDEA或Eclipse搭配Navicat与JDK1.8。系统划分管理员、教师、学生三种权限管理员负责学生、教师与课程信息管理教师可查看课程与学生、录入成绩并查看个人信息学生可浏览课程、选课、查询成绩及查看个人信息。压缩包共112个文件约2.39MB包含22个java源文件、22个class、21个jsp页面、10个jar依赖、5个css与5个js等并附数据库脚本源码与脚本齐全项目经过严格调试可正常运行。目前已有4273人学习下载适合需要完整选课系统方案、权限设计与数据库脚本的读者参考。1. 从一份只有 class 文件的选课系统说起这套 JavaWeb 资源到底能跑出什么打开压缩包第一眼看到的不是源码目录而是一排.class文件StudentServlet.class、TeacherServlet.class、CourseServlet.class、StudentDao.class、TeacherDao.class、StudentCourseDao.class、CourseDao.class、UserServlet.class、LoginFilter.class、StudentCourse.class。很多人第一反应是「怎么只有编译产物」但真正做过课程设计的人会立刻意识到这恰恰说明它是一套已经跑通过、编译过的 Servlet JSP 选课系统而不是半成品脚手架。它解决的是计算机相关专业做毕设或项目实战时最头疼的问题三端权限、选课冲突、成绩录入这些业务闭环到底怎么用原生 JavaWeb 串起来。适合正在找完整案例的 Java 学习者也适合需要一套能直接改造成毕设的学生。技术栈是 Servlet JSP MySQL Bootstrap开发环境 JDK1.8、Tomcat、IDEA 或 Eclipse 都能接。2. 三端权限怎么落到 Servlet 和 DAO先看懂分层再动手2.1 从 class 文件反推项目分层结构这套系统的分层非常典型属于教学和毕设里最常见的那种「Servlet 接请求、DAO 管数据库、实体类传数据」的结构。从文件名就能拆出来控制层StudentServlet、TeacherServlet、CourseServlet、UserServlet分别对应学生、教师、课程、登录四类请求入口。数据访问层StudentDao、TeacherDao、CourseDao、StudentCourseDao其中StudentCourseDao是选课关系的核心学生选课、退课、成绩录入都绕不开它。实体层StudentCourse是学生与课程的多对多关系映射通常带学生 ID、课程 ID、成绩字段。过滤器LoginFilter负责登录校验和权限拦截没登录直接跳登录页角色不对就挡在对应功能外。这种分层的价值在于改一个业务只需要动对应的 Servlet 和 DAO不会牵一发动全身。很多同学拿到项目后直接改 JSP结果请求参数对不上、数据库字段错位就是因为没先看分层。2.2 数据库表与实体字段的对应关系选课系统的数据库一般至少四张表学生表、教师表、课程表、选课关系表。结合StudentCourse这个实体关系表通常长这样字段名类型说明idint主键自增student_idint学生 ID外键关联学生表course_idint课程 ID外键关联课程表scoredecimal成绩选课时为空教师录入后写入课程表里一般还有teacher_id用来绑定授课教师教师登录后只能看到自己名下的课程和学生这个限制通常写在TeacherServlet或CourseDao的查询条件里。学生表里会有账号、密码、姓名、班级等字段UserServlet负责登录时按角色查不同的表。提示导入数据库脚本后先确认student_id和course_id的外键约束是否开启。有些脚本为了导入方便会临时去掉外键跑起来才发现选课记录能插进不存在的课程。2.3 环境搭建与项目导入的可复现步骤这套项目用 JDK1.8 最稳Tomcat 建议 8.5 或 9.0MySQL 用 5.7 或 8.0 都行但驱动要对应。下面是从零跑起来的步骤。第一步建库并导入脚本。用 Navicat 或命令行都行CREATE DATABASE student_course DEFAULT CHARACTER SET utf8mb4; USE student_course; -- 这里执行项目自带的 .sql 脚本 SOURCE /path/to/student_course.sql;字符集用utf8mb4是为了避免中文姓名和课程名乱码这是血泪经验用utf8在某些 MySQL 版本下照样出问题。第二步在 IDEA 里导入项目并配置 Tomcat。项目如果是 Eclipse 结构导入后要手动把src标记为 Sources Root把WebContent或web标记为 Web 资源目录。然后在 Run Configuration 里加一个 Tomcat LocalDeployment 选war exploded。第三步改数据库连接配置。项目里通常有一个db.properties或直接在 DAO 里写死的连接串把它改成自己的jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/student_course?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernameroot jdbc.password你的密码serverTimezone不写会在 MySQL 8 下报时区错误useSSLfalse是本地开发省去证书配置。驱动类名 MySQL 8 用com.mysql.cj.jdbc.DriverMySQL 5 用com.mysql.jdbc.Driver写错直接ClassNotFoundException。第四步启动 Tomcat访问http://localhost:8080/项目名/。默认账号一般在 SQL 脚本的 insert 语句里管理员、教师、学生各一条密码可能是明文也可能是 MD5看脚本注释。2.4 登录过滤器与角色跳转的实现逻辑LoginFilter是这套系统的门禁。它的逻辑通常是放行登录页、登录请求和静态资源其余请求检查 session 里有没有用户信息没有就重定向到登录页有的话再判断角色学生访问教师路径就拦掉。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) || uri.contains(css) || uri.contains(js)) { chain.doFilter(req, resp); return; } Object user request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); }这段代码的关键在放行名单漏掉.js或.css会导致登录页样式丢失看起来像项目坏了。角色级别的拦截一般放在各 Servlet 内部根据 session 里的角色字段决定返回哪个页面。3. 选课、退课与成绩录入核心业务链路的实现与参数3.1 学生选课与退课的 DAO 写法选课的本质是往student_course表插一条记录退课是删一条。StudentCourseDao里通常有addStudentCourse、deleteStudentCourse、getCoursesByStudentId这几个方法。选课时要先查这门课是否已选、是否已满再决定插不插。public boolean addStudentCourse(int studentId, int courseId) { String checkSql SELECT COUNT(*) FROM student_course WHERE student_id? AND course_id?; String insertSql INSERT INTO student_course(student_id, course_id) VALUES(?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement check conn.prepareStatement(checkSql)) { check.setInt(1, studentId); check.setInt(2, courseId); ResultSet rs check.executeQuery(); if (rs.next() rs.getInt(1) 0) { return false; // 已选过不重复插入 } try (PreparedStatement insert conn.prepareStatement(insertSql)) { insert.setInt(1, studentId); insert.setInt(2, courseId); return insert.executeUpdate() 0; } } catch (SQLException e) { e.printStackTrace(); return false; } }参数说明studentId和courseId都来自 session 和前端表单不要信任前端传的值session 里的学生 ID 才是准的。用PreparedStatement而不是拼接 SQL是为了防注入这也是毕设答辩常被问的点。课程容量限制一般在CourseDao里查已选人数和课程表里的容量字段比较。3.2 教师成绩录入的更新逻辑成绩录入对应的是student_course表的 update条件同时锁定学生和课程避免改错人。public boolean updateScore(int studentId, int courseId, double score) { String sql UPDATE student_course SET score? WHERE student_id? AND course_id?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setDouble(1, score); ps.setInt(2, studentId); ps.setInt(3, courseId); return ps.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } }score用double接收数据库字段如果是decimal(5,2)也能对上。教师只能改自己课程的分数这个限制要在TeacherServlet里先查课程归属再调 DAO否则越权改分别的老师的课属于典型逻辑漏洞。3.3 课程列表与分页查询的参数设计课程列表一般要支持分页否则数据一多页面就卡。常见做法是CourseDao提供getCoursesByPage(int page, int size)SQL 用LIMIT。public ListCourse getCoursesByPage(int page, int size) { ListCourse list new ArrayList(); String sql SELECT * FROM course LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, (page - 1) * size); ps.setInt(2, size); ResultSet rs ps.executeQuery(); while (rs.next()) { Course c new Course(); c.setId(rs.getInt(id)); c.setName(rs.getString(name)); c.setTeacherId(rs.getInt(teacher_id)); list.add(c); } } catch (SQLException e) { e.printStackTrace(); } return list; }page从 1 开始size一般给 10 或 15。前端 Bootstrap 表格配合 jQuery 渲染分页按钮的页码要和服务端算出来的总页数一致总页数用SELECT COUNT(*) FROM course单独查一次。3.4 前端 JSP 与 Bootstrap 的对接要点JSP 页面负责把后端传过来的 list 渲染成表格。Bootstrap 的表格类名是table table-striped配合 jQuery 做选课按钮的异步提交。table classtable table-striped thead trth课程名/thth授课教师/thth操作/th/tr /thead tbody c:forEach items${courseList} varc tr td${c.name}/td td${c.teacherName}/td tdbutton classbtn btn-primary btn-sm onclickchoose(${c.id})选课/button/td /tr /c:forEach /tbody /tablec:forEach需要 JSTL 标签库别忘了在 JSP 顶部加% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %并把 jstl 的 jar 放进WEB-INF/lib。少了这个页面直接报 500很多人第一次跑就卡在这。4. 部署与运行排查那些让项目起不来的常见问题4.1 现象启动 Tomcat 报 404首页打不开原因通常是访问路径不对或者web.xml里 welcome-file 没配。这套项目入口可能是login.jsp而不是index.jsp。解决在 Tomcat 部署配置里看 Application context访问http://localhost:8080/context/再手动加/login.jsp试。如果web.xml里welcome-file-list写的是index.jsp但项目里没有这个文件也会 404。4.2 现象登录后一直跳回登录页原因多半是LoginFilter把登录请求也拦了或者 session 没存住。先检查过滤器放行名单里有没有login关键字再看登录成功的 Servlet 里是不是用request.getSession().setAttribute(user, user)存的。如果用了重定向而不是转发session 一般还在但要是浏览器禁了 cookie 就另说。解决把登录请求路径加进放行名单确认 session 属性名和过滤器里取的一致。4.3 现象中文课程名和姓名显示成问号原因是数据库连接串没指定字符编码或者数据库、表、字段的字符集不统一。解决连接串加characterEncodingutf8数据库建的时候用utf8mb4JSP 页面顶部加% page contentTypetext/html;charsetUTF-8 %。三处都对了才不会乱码只改一处经常还是问号。4.4 现象MySQL 8 连接报Public Key Retrieval is not allowed原因是 MySQL 8 默认的认证插件和旧驱动不兼容。解决连接串加allowPublicKeyRetrievaltrue或者把驱动换成mysql-connector-java 8.x。如果还报时区错误再加serverTimezoneAsia/Shanghai。这两个参数是 MySQL 8 下跑老项目的标配记下来能省很多时间。4.5 现象选课按钮点了没反应原因可能是 jQuery 没加载、按钮的 onclick 函数没定义或者异步请求的 URL 写错。打开浏览器 F12 看 Console 和 Network如果请求 404 就是 URL 问题如果报choose is not defined就是脚本没引入。解决确认jquery.min.js路径正确函数名和按钮里写的一致Servlet 的WebServlet注解或web.xml映射和请求路径对得上。5. 把这套系统改造成能过答辩的毕设三个进阶技巧第一个技巧是给选课加并发控制。原生 JDBC 在多人同时选同一门课时可能超卖常见做法是在addStudentCourse里用事务加行锁或者先SELECT ... FOR UPDATE锁住课程记录再判断容量。改完后面试被问「怎么防止超卖」就有话说了。第二个技巧是把成绩查询做成带条件的动态 SQL。学生查成绩、教师查课程成绩、管理员查全部三种场景用同一个 DAO 方法根据传入的角色和 ID 拼不同 where 条件。用StringBuilder拼的时候注意参数仍然走PreparedStatement占位符别为了省事直接拼字符串。第三个技巧是加一个简单的操作日志表。选课、退课、成绩录入都往日志表插一条记录操作人、时间、动作。答辩时演示「谁在什么时候改了成绩」很加分实现成本却很低一个LogDao加一个 insert 就够。public void addLog(int userId, String role, String action) { String sql INSERT INTO sys_log(user_id, role, action, create_time) VALUES(?,?,?,NOW()); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, userId); ps.setString(2, role); ps.setString(3, action); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } }验证改造是否成功最直接的办法是把项目重新部署一遍用三个角色分别登录走一遍完整流程管理员加课程、学生选课、教师录成绩、学生查成绩。每一步都看数据库里对应表的记录有没有正确变化。从那以后我每次拿到这类 JavaWeb 项目都强制先跑通一条完整业务链路再动代码不然改到一半分不清是环境问题还是逻辑问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表