资讯动态

JavaEE网上考试系统课程设计:Servlet+JSP+JDBC完整实现与二次开发指南

发布时间:2026/10/26 12:40:05 来源:尧图企业网站定制
简介这份资源是面向软件工程、计算机相关专业学生的JavaEE课程大作业完整方案聚焦网上考试系统的设计与实现适合需要完成期末项目、课程设计或自学JavaEE开发的学习者参考。压缩包共74个文件约6.75MB以16个Java源文件、16个JSP页面和16个class文件为核心配合CSS样式、GIF/JPG图片素材及jar依赖构成可运行的Web工程另附2份doc文档含设计报告与使用说明便于理解系统结构与部署流程。资源已有3476人学习下载经过较多同学验证。代码注释详细、难度适中导入后只需修改姓名、学号等个人信息即可直接使用报告部分可帮助梳理需求分析、数据库设计与功能模块说明使用说明则降低环境配置门槛适合作为课程作业提交或JavaEE入门实践的参考模板。1. 网上考试系统一份能直接跑通的 JavaEE 课程设计资源期末周前一周隔壁宿舍的 A 同学抱着笔记本过来说他选的 JavaEE 大作业是「网上考试系统」代码能编译但一登录就白屏报告也不知道从哪下笔。我打开压缩包翻了翻发现这套资源其实挺完整后端是标准的 JavaEE 三层结构前端是 JSP 加少量 JS数据库脚本、部署说明、设计报告一应俱全。它解决的不是「高并发在线考试平台」这种工业级需求而是课程设计场景下「能演示、能答辩、能改」的刚需——学生登录答题、教师组卷阅卷、后台管理题库三个角色闭环跑得通。适合谁正在做 JavaEE 课程设计、需要一份结构清晰可二次开发的参考实现的人也适合想复习 Servlet JSP JDBC 这套经典组合的初学者。下面按「它是什么 → 怎么跑起来 → 怎么改」的顺序拆。2. 技术栈与目录结构先看清这套 JavaEE 骨架长什么样2.1 技术选型为什么是 Servlet JSP JDBC 这套老组合这套项目的技术栈没有花活属于课程设计里最稳的一档后端 Servlet 负责请求分发和业务控制JSP 负责页面渲染JDBC 直连数据库做持久化前端用原生 JS 做表单校验和倒计时构建工具是 Maven容器是 Tomcat。没有 Spring 全家桶也没有前后端分离好处是依赖少、启动快、答辩时每一行代码都能讲清楚来龙去脉。我一般会跟人说选这套组合不是因为它先进而是因为它「透明」。Spring Boot 一个注解背后藏了多少自动配置课程设计答辩时老师一问就露怯而 Servlet 的doGet/doPost、web.xml的映射、JDBC 的Connection/PreparedStatement每一层都摆在明面上。对于要交报告、要讲设计思路的场景这种透明性比技术新颖度值钱得多。依赖清单大致是这几块javax.servlet-apiServlet 容器接口、jsp-apiJSP 编译支持、mysql-connector-java数据库驱动、jstlJSP 标签库用于页面循环和条件渲染。版本上不用追新Servlet 3.1 / 4.0 配 Tomcat 8 或 9 都能跑MySQL 驱动用 5.1.x 或 8.0.x 要和数据库版本对齐。这里有个血泪经验驱动版本和数据库版本不匹配是新手最常见的翻车点后面避坑章节会细说。2.2 目录结构一个标准 Maven Web 工程的分层把压缩包解开目录大致是这样不同版本可能略有出入但分层逻辑一致exam-system/ ├── pom.xml # Maven 依赖与打包配置 ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/exam/ │ │ │ ├── controller/ # Servlet 控制层 │ │ │ ├── service/ # 业务逻辑层 │ │ │ ├── dao/ # 数据访问层 │ │ │ ├── entity/ # 实体类User/Question/Paper/Score │ │ │ └── util/ # 数据库连接、工具类 │ │ ├── resources/ │ │ │ └── db.properties # 数据库连接配置 │ │ └── webapp/ │ │ ├── WEB-INF/ │ │ │ └── web.xml # Servlet 映射、欢迎页 │ │ ├── jsp/ # 各角色页面 │ │ ├── css/ js/ # 静态资源 │ │ └── index.jsp # 登录入口 │ └── test/ # 测试代码可能为空 ├── sql/ │ └── exam.sql # 建库建表 初始数据 └── 使用说明.md / 设计报告.docx这个结构的关键在于controller → service → dao → entity四层分明。控制层只做参数接收和页面跳转业务层处理组卷、判分这类逻辑DAO 层封装所有 SQL实体类对应数据库表。改功能时按层定位不会一锅粥。我特别建议先看entity包四五个实体类看完整个系统的数据模型就清楚了用户、题目、试卷、成绩外加一个题目类型枚举。2.3 数据库设计五张核心表撑起整个业务sql/exam.sql里通常包含建库语句和初始数据。核心表大致是这几张表名作用关键字段user用户学生/教师/管理员id, username, password, rolequestion题库id, type, content, options, answer, scorepaper试卷id, title, total_score, duration, create_bypaper_question试卷与题目关联paper_id, question_id, order_noscore成绩记录id, user_id, paper_id, score, submit_timequestion表的type字段区分单选、多选、判断options存选项常见做法是用 JSON 或分隔符拼接answer存标准答案。paper_question这张关联表是组卷的核心一张试卷有哪些题、什么顺序全靠它。score表记录谁在什么时候交了什么卷、得了多少分。这五张表的关系理清了后面看代码就是顺藤摸瓜。提示导入exam.sql前先确认字符集。老脚本常用utf8如果数据库默认是utf8mb4中文题干可能出现乱码建库时统一成utf8mb4更稳妥。3. 跑起来从导库到登录的完整启动链路3.1 环境准备与数据库导入启动这套系统的前置条件不多JDK 8或 11、Maven 3.6、Tomcat 8.5/9、MySQL 5.7/8.0。装好之后第一步是导库。用命令行或图形工具都行命令行更直观# 登录 MySQL按提示输入密码 mysql -u root -p # 创建数据库并指定字符集 CREATE DATABASE exam_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 退出后导入脚本路径按实际调整 mysql -u root -p exam_system sql/exam.sql导入完成后执行SHOW TABLES;确认五张表都在再SELECT * FROM user;看看初始账号。通常脚本里会预置一个管理员账号和几个测试学生账号密码可能是明文也可能是 MD5看脚本里的数据。这一步别跳过账号信息是后面登录的钥匙。3.2 改配置数据库连接那几行必须对上src/main/resources/db.properties是数据库连接的唯一入口内容大致长这样jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/exam_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.usernameroot jdbc.password你的密码四个参数逐个说清楚jdbc.driver在 MySQL 8 驱动下是com.mysql.cj.jdbc.DriverMySQL 5 驱动则是com.mysql.jdbc.Driver写错直接ClassNotFoundExceptionjdbc.url里的serverTimezone不加MySQL 8 会报时区错误useSSLfalse是本地开发省掉证书握手用户名密码换成你自己的。改完这四行连接层基本就通了。对应的工具类DBUtil一般长这样用静态块加载驱动、提供获取和关闭连接的方法public class DBUtil { private static String url; private static String username; private static String password; // 静态块在类加载时执行一次读取配置并注册驱动 static { try { Properties props new Properties(); props.load(DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)); Class.forName(props.getProperty(jdbc.driver)); url props.getProperty(jdbc.url); username props.getProperty(jdbc.username); password props.getProperty(jdbc.password); } catch (Exception e) { throw new ExceptionInInitializerError(数据库配置加载失败: e.getMessage()); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } public static void close(Connection conn, Statement stmt, ResultSet rs) { // 关闭顺序ResultSet → Statement → Connection逐个判空 try { if (rs ! null) rs.close(); } catch (SQLException ignored) {} try { if (stmt ! null) stmt.close(); } catch (SQLException ignored) {} try { if (conn ! null) conn.close(); } catch (SQLException ignored) {} } }逻辑说明静态块保证驱动只注册一次配置只读一次getConnection每次新建连接课程设计规模下够用不用连接池。参数说明url/username/password是静态字段被所有 DAO 共享。这里有个常见误用——把close写成只关 Connection 不关 ResultSet短时间看不出问题压测或反复操作后连接泄漏Tomcat 日志里会冒Too many connections。3.3 部署到 Tomcat 并验证登录配置改好后用 Maven 打包再丢进 Tomcat# 在项目根目录执行生成 target/exam-system.war mvn clean package # 把 war 复制到 Tomcat 的 webapps 目录路径按实际调整 cp target/exam-system.war $TOMCAT_HOME/webapps/ # 启动 Tomcat $TOMCAT_HOME/bin/startup.sh # Windows 用 startup.bat启动后访问http://localhost:8080/exam-system/应该看到登录页。用脚本里的管理员账号登录进后台看题库列表有没有数据再用学生账号登录看能不能进考试列表。两个角色都通了说明数据库、Servlet 映射、JSP 渲染整条链路没问题。如果白屏或 404先看 Tomcat 的logs/catalina.out再看浏览器控制台八成是web.xml映射路径和访问路径对不上或者 war 包名和 context path 不一致。注意IDEA 里直接配 Tomcat 跑也可以但要确认 Artifact 的 context path 和web.xml里的 servlet 映射一致否则页面里的相对路径跳转会 404。4. 核心模块拆解登录、组卷、答题判分三条主链路4.1 登录与权限拦截一个 Filter 管住所有角色登录流程是「表单提交 → Servlet 校验 → 写 Session → 跳角色首页」。校验逻辑在LoginServlet里核心是查用户、比对密码、把用户对象塞进 Sessionprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); User user userService.login(username, password); if (user null) { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(/jsp/login.jsp).forward(req, resp); return; } // 登录成功用户信息写入 Session后续页面据此判断角色 req.getSession().setAttribute(currentUser, user); // 按角色分流到不同首页 String target STUDENT.equals(user.getRole()) ? /jsp/student/home.jsp : /jsp/admin/home.jsp; resp.sendRedirect(req.getContextPath() target); }逻辑说明userService.login内部走 DAO 查库返回 null 表示账号或密码不对成功则把User对象放进 Session键名currentUser是全系统约定。参数说明username/password来自表单字段名JSP 里input nameusername必须和这里一致改字段名要两边同步。光有登录不够还得防越权。项目里通常有一个AuthFilter拦截/jsp/admin/*和/jsp/student/*检查 Session 里有没有currentUser、角色对不对public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); User user (User) req.getSession().getAttribute(currentUser); if (user null) { resp.sendRedirect(req.getContextPath() /jsp/login.jsp); return; } // 管理员路径只允许 ADMIN 角色访问 if (uri.contains(/admin/) !ADMIN.equals(user.getRole())) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } chain.doFilter(request, response); }这个 Filter 在web.xml里用filter-mapping配url-pattern为/jsp/*。改权限规则时只动这一个类不用满项目找判断。我一般会把角色判断抽成常量或枚举避免字符串硬编码写错大小写——admin和ADMIN不相等这种坑排查起来很费时间。4.2 组卷逻辑教师端怎么把题目拼成一张卷组卷是教师端的核心。流程是教师勾选题目 → 提交题目 ID 列表 → 后端写paper和paper_question两张表。Servlet 接收参数后调 ServiceService 里开事务保证两张表要么都成功要么都回滚public boolean createPaper(Paper paper, ListInteger questionIds) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 插入试卷主记录返回自增主键 int paperId paperDao.insert(conn, paper); // 2. 批量插入试卷-题目关联order_no 决定答题顺序 for (int i 0; i questionIds.size(); i) { paperQuestionDao.insert(conn, paperId, questionIds.get(i), i 1); } conn.commit(); return true; } catch (SQLException e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ignored) {} return false; } finally { DBUtil.close(conn, null, null); } }逻辑说明setAutoCommit(false)关掉自动提交两步插入都成功才commit任何一步抛异常就rollback。参数说明paper含标题、总分、时长questionIds是前端传来的题目 ID 列表顺序即答题顺序order_no从 1 开始。这里的关键是 DAO 方法要接收外部传入的Connection而不是自己新建——否则事务管不住两个 DAO 的连接。这是 JDBC 事务的经典写法也是很多课程设计里容易写错的地方每个 DAO 各开各的连接事务形同虚设。总分怎么算常见做法是在插入前遍历题目把每题score累加写进paper.total_score而不是让前端传。前端传的总分可以被篡改后端算才可靠。4.3 答题与自动判分客观题怎么对答案学生提交答卷时前端把「题目 ID → 所选答案」的映射传给后端。判分逻辑在ExamService.submit里逐题取标准答案比对累加得分最后写score表。public int gradeAndSave(int paperId, int userId, MapInteger, String answers) { ListQuestion questions questionDao.findByPaperId(paperId); int total 0; for (Question q : questions) { String userAnswer answers.get(q.getId()); if (userAnswer null) continue; // 未作答不得分 // 多选题答案排序后比较避免顺序不同误判 if (normalize(userAnswer).equals(normalize(q.getAnswer()))) { total q.getScore(); } } scoreDao.insert(userId, paperId, total, new Date()); return total; } // 去空格、统一大写、多选答案按字符排序 private String normalize(String ans) { char[] cs ans.replaceAll(\\s, ).toUpperCase().toCharArray(); Arrays.sort(cs); return new String(cs); }逻辑说明遍历试卷所有题目取学生答案和标准答案normalize做归一化后比较。参数说明answers的 key 是题目 IDvalue 是选项字母如A或ABD。多选题最容易翻车——学生选DBA、标准答案是ABD直接字符串比较就判错所以要先排序。这个细节报告里写进去答辩时是个加分点。判分只覆盖客观题。如果题库里有主观题简答、论述常见做法是标记为「待人工阅卷」教师端单独一个页面打分score表加个status字段区分已判/待判。这套资源里如果只有客观题那判分链路就是全自动的简单但完整。5. 避坑与排查启动和运行阶段最容易翻车的五件事5.1 中文乱码从请求到响应三处都要设现象题干、选项、用户名里的中文全变问号或方块。原因通常有三层数据库字符集不是utf8mb4、JDBC url 没带characterEncodingutf8、Servlet 里没设request.setCharacterEncoding(UTF-8)。解决建库时指定字符集url 补上编码参数并在 Filter 里统一setCharacterEncoding响应侧resp.setContentType(text/html;charsetUTF-8)。三处都对齐乱码基本绝迹。5.2 驱动版本不匹配ClassNotFound 与时间戳异常现象一启动报ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因是 pom 里引的是 MySQL 5 驱动配置里却写了 8 的类名或反过来。解决驱动版本和类名对齐5.x 用com.mysql.jdbc.Driver8.x 用com.mysql.cj.jdbc.Driver。现象二连库报时区错误The server time zone value ... is unrecognized。原因是 MySQL 8 驱动要求显式时区。解决url 加serverTimezoneAsia/Shanghai。这两个是新手最高频的翻车点改配置时一次到位。5.3 404 与白屏路径映射对不上现象访问首页 404或登录后跳转白屏。原因多半是 context path 不一致——war 包名是exam-system访问却用了/exam或者web.xml里 servlet 的url-pattern和表单action不匹配。解决先确认 Tomcatwebapps下的目录名访问路径以它为准再对照web.xml的servlet-mapping和 JSP 里的action三者路径要能串起来。白屏但无报错多半是 JSP 里 EL 表达式取不到 Session 属性检查键名是否和setAttribute一致。5.4 连接泄漏Too many connections 的连锁反应现象反复登录、答题几次后页面卡住Tomcat 日志出现Too many connections。原因是 DAO 里Connection没关或者close只关了部分资源。解决统一走DBUtil.closefinally块里调用检查每个 DAO 方法是否都有finally。课程设计规模下连接数不多但泄漏是累积的演示到一半崩掉很尴尬。我一般会在DBUtil里加个计数器打日志开发阶段看连接开闭是否配对。5.5 事务失效每个 DAO 各开各的连接现象组卷时试卷插进去了关联题目却没插进去数据半截。原因是 Service 开了事务但 DAO 内部自己getConnection事务管的是另一个连接。解决事务方法里把Connection作为参数传给 DAO所有操作共用同一个连接commit/rollback才有效。这个坑不看代码很难发现因为单步执行都「成功」只有异常回滚时才暴露。6. 二次开发从课程设计到能讲清楚的作品拿到这套代码最忌讳的是原样交上去。答辩老师看过的同类项目不少改都没改一眼就能看出来。我的建议是从三个方向做增量每个都不大但能体现你理解了架构。第一个方向是加题型。现有题库如果是单选、多选、判断可以加一个「填空」类型question.type加枚举值判分时对填空做去空格、忽略大小写的比较前端 JSP 加一个输入框分支。改动点集中在Question实体、判分 Service 和一个 JSP 片段四层结构的好处这时候就体现出来了——按层改不牵一发动全身。第二个方向是加考试时长控制。paper.duration字段如果只是展示没用上可以在学生进入考试时把「开始时间 时长」写进 Session前端 JS 做倒计时展示后端在提交时校验是否超时超时则按已答内容判分或直接作废。这里要注意前后端都要校验只靠前端倒计时可以被绕过。第三个方向是成绩统计。score表已经有数据加一个教师端页面按试卷维度算平均分、最高分、及格率用一条 SQL 聚合就能出结果SELECT p.title, COUNT(s.id) AS submit_count, AVG(s.score) AS avg_score, MAX(s.score) AS max_score, SUM(s.score 60) / COUNT(s.id) AS pass_rate FROM score s JOIN paper p ON s.paper_id p.id GROUP BY p.id, p.title;这条 SQL 直接喂给 JSP 循环渲染就是一张统计表报告里再配一段「为什么用聚合而非应用层计算」的说明说服力就有了。参数说明pass_rate依赖 MySQL 布尔转 0/1 的特性换数据库要改写。验证方法很简单每改一个功能先把三个角色的主流程各走一遍——管理员建题、教师组卷、学生答题看分。改完跑不通八成是新代码破坏了原有的事务边界或 Session 约定。我吃过一次亏加填空题时在 DAO 里新开了连接结果组卷事务回滚不彻底数据脏了半张表排查了一晚上才发现是连接没共用。从那以后我每次动 DAO 层都强制把「Connection 从哪来、到哪关」在纸上画一遍再写代码。希望这套拆解能帮你少走点弯路把这份课程设计改成自己讲得明白的作品。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑