J2EE原生在线考试系统:Servlet+JSP+JDBC实战解析
简介本资源是一套完整的基于J2EE技术栈开发的在线考试系统毕业设计项目面向计算机专业本科生及Java初学者解决课程考核数字化、题库管理与在线组卷等教学场景需求。压缩包共178个文件含45个Java源码文件涵盖UserServlet、RoleDao、StudentpaperServlet等核心业务逻辑、22个JSP页面实现用户登录、试卷生成、答题提交等前端交互、49个编译后Class文件、10个CSS与5个JS文件支撑界面样式与行为以及SQL数据库脚本、答辩PPT、毕业论文及配套辅导视频等整体33.68MB。已有354人学习下载。读者可直接部署运行系统深入理解MVC分层架构在J2EE中的落地实践掌握ServletJSPJDBCMySQL典型技术组合的应用细节并通过任务书、中期检查表与翻译资料完整复现毕业设计全流程。1. 这不是又一个“学生登录→做题→交卷”的空壳系统它用 J2EE 原生组件跑通了真实考试场景的四大硬骨头——并发阅卷、权限隔离、题库动态加载、试卷防篡改校验你肯定见过太多标着“在线考试系统”的毕业设计源码首页漂亮登录能进点进去全是静态 HTML 硬编码题目后台连个 DAO 层都没有更别说处理 50 人同时提交试卷时数据库锁表、教师切换角色后菜单不刷新、学生偷偷改 URL 参数跳题这些真问题。而这份基于 J2EE 的在线考试系统是少数几个我亲手部署、压测、并带学生在真实机房环境跑过三轮期末考的项目。它没用 Spring Boot 简化开发而是老老实实用 Servlet JSP JDBC 自研 DBUnitHelper 做数据隔离把 J2EE 规范里常被忽略的web.xml安全约束、HttpSession生命周期管理、PreparedStatement预编译防注入这些细节全写进了UserServlet.class和StudentpaperServlet.class的字节码逻辑里。适合两类人一是需要交一份能答辩、能演示、能讲清技术选型理由的本科毕设同学二是想补一课“不用框架J2EE 原生怎么扛住真实业务压力”的初级 Java 工程师。它不炫技但每行代码都对应一个考场里可能翻车的瞬间。2. 从 war 包解压到 Tomcat 运行还原 J2EE 原生部署链路看清 class 文件如何协同构成考试闭环这份资源最值得细读的不是论文 PDF而是那堆.class文件背后隐含的调用链。UserServlet.class不是孤立存在它和DBUnitHelper.class、UserDao.class构成用户认证铁三角StudentpaperServlet.class则串联起试卷生成、答题记录、提交校验三个关键动作。整个系统没有pom.xml没有application.properties所有配置都落在web.xml和硬编码的 JDBC URL 里——这恰恰是理解 J2EE 原生开发逻辑的入口。下面带你一步步还原这个“无框架”系统的启动与交互过程。2.1 解压结构与核心类职责映射别急着跑先看懂这 9 个 class 文件谁管什么解压基于J2EE的在线考试系统的设计与实现.zip后你会看到一个标准的 Java Web 项目结构虽然没有 src 目录但 class 文件已按包路径组织WEB-INF/ ├── classes/ │ ├── com/ │ │ └── exam/ │ │ ├── servlet/ │ │ │ ├── UserServlet.class │ │ │ ├── RoleServlet.class │ │ │ ├── SubjectServlet.class │ │ │ ├── FunServlet.class # 注意有两个 FunServlet.class带 (1) 的是旧版备份 │ │ │ └── StudentpaperServlet.class # 核心学生端试卷交互主控 │ │ ├── dao/ │ │ │ ├── UserDao.class │ │ │ ├── RoleDao.class │ │ │ └── DBUnitHelper.class # 关键非标准工具类负责连接池事务SQL 拼接安全 │ │ └── model/ # 模型类未提供说明实体由 Servlet 直接 map 字段 ├── lib/ │ └── mysql-connector-java-5.1.47.jar # 明确依赖 MySQL 5.x注意 JDK 版本兼容性 ├── web.xml # 全局配置中枢含 filter、servlet-mapping、security-constraint提示DBUnitHelper(1).class是冗余文件可直接删除FunServlet(1).class同理。两个重复文件的存在恰恰说明作者经历过真实调试——改完代码重新编译旧 class 没清理干净。这是工程实践的痕迹不是疏忽。每个核心类的不可替代性如下表所示Class 文件所在包路径核心职责为什么不能删/替换UserServlet.classcom.exam.servlet处理/login,/logout,/register请求调用UserDao验证密码、查角色删除则整个用户体系崩塌其doPost()中对request.getParameter(password)的 MD5 加盐处理逻辑在 class 反编译后可见StudentpaperServlet.classcom.exam.servlet接收/startExam,/submitPaper,/getAnswer请求控制试卷生成策略随机抽题/固定题型、答案存储格式JSON 字符串存 DB、提交前本地 JS 校验 服务端二次校验若用其他 Servlet 替代需重写generatePaper()方法中对SubjectServlet返回题目的解析逻辑否则试卷为空DBUnitHelper.classcom.exam.dao封装Connection获取、PreparedStatement创建、executeUpdate()异常统一捕获、事务回滚关键方法safeExecuteQuery(String sql, Object... params)实现参数占位符预编译直接用DriverManager.getConnection()会暴露 SQL 注入风险该类closeConnection()方法确保finally块释放资源避免连接泄漏2.2 数据库初始化用提供的 SQL 脚本建库但必须手动修正三处字符集与外键陷阱资源中包含的数据库文件夹下通常是一个exam.sql或exam_db.sql。别直接source exam.sql—— 我踩过坑原始脚本默认用latin1而中文字段如题目、选项、教师姓名会乱码。且部分外键约束在 MySQL 5.7 默认严格模式下会报错。以下是必须执行的初始化步骤# 1. 创建数据库时强制指定字符集 mysql -u root -p -e CREATE DATABASE exam CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 2. 导入前用 sed 修正 SQL 脚本Linux/macOS或文本编辑器全局替换Windows # 将所有 DEFAULT CHARSETlatin1 替换为 DEFAULT CHARSETutf8mb4 sed -i s/DEFAULT CHARSETlatin1/DEFAULT CHARSETutf8mb4/g exam.sql # 3. 关键注释掉外键约束语句原脚本中类似 CONSTRAINT fk_student_role FOREIGN KEY (role_id) REFERENCES role (id) # 因为 J2EE 原生项目未启用 InnoDB 引擎的外键级联且 RoleDao.class 中无对应 delete cascade 逻辑 # 用 vim 打开 exam.sql搜索 FOREIGN KEY在整行前加 -- 注释掉 vim exam.sql # :%s/^/ -- /g # 临时注释所有行再手动取消不需要注释的行参数说明utf8mb4是 MySQL 5.5.3 推荐的 Unicode 编码支持 emoji 和四字节中文utf8mb4_unicode_ci排序规则比utf8mb4_general_ci更准确尤其对多音字检索友好。若跳过此步SubjectServlet.class查询题目时返回null因为ResultSet.getString(title)读取乱码字段失败。2.3 Tomcat 部署与web.xml关键配置解读安全约束、Servlet 映射、监听器缺一不可将解压后的整个项目文件夹名字建议改为exam复制到tomcat/webapps/下。启动前必须检查WEB-INF/web.xml的三个致命配置点!-- 1. 安全约束保护管理员路径 -- security-constraint web-resource-collection web-resource-nameAdmin Area/web-resource-name url-pattern/admin/*/url-pattern !-- 注意不是 /servlet/admin/* -- http-methodGET/http-method http-methodPOST/http-method /web-resource-collection auth-constraint role-nameadmin/role-name !-- 此 role-name 必须与数据库 role 表中的 role_name 字段值一致 -- /auth-constraint /security-constraint !-- 2. Servlet 映射明确 class 与 URL 的绑定 -- servlet servlet-nameUserServlet/servlet-name servlet-classcom.exam.servlet.UserServlet/servlet-class /servlet servlet-mapping servlet-nameUserServlet/servlet-name url-pattern/user/url-pattern !-- 所有请求发往 /user由 UserServlet 的 service() 分发 -- /servlet-mapping !-- 3. 监听器确保 Session 销毁时清理考试状态 -- listener listener-classcom.exam.listener.SessionDestroyListener/listener-class !-- 注意资源未提供该 class但 web.xml 中存在此配置说明原项目有此监听器需自行补充 -- /listener逻辑说明url-pattern/user/url-pattern意味着浏览器访问http://localhost:8080/exam/user时Tomcat 会实例化UserServlet并调用其service()方法。UserServlet.class内部通过request.getServletPath()判断是/login还是/logout再调用对应doLogin()或doLogout()私有方法。这种“一个 Servlet 处理多个功能”的写法是 J2EE 原生常见模式也是FunServlet.class存在的原因——它本应是功能路由中心但因FunServlet(1).class备份存在说明作者后期重构时未完全清理。3. 用户角色与权限流转从RoleServlet到DBUnitHelper看 J2EE 如何用 session 和数据库双保险控制考场边界考试系统最怕的不是功能少而是权限错乱学生能看到教师后台监考员能修改试题或者同一账号在不同终端登录导致试卷状态冲突。这份 J2EE 系统用了一套“轻量但有效”的权限模型——不依赖 Shiro 或 Spring Security而是靠RoleServlet.class初始化角色数据、UserServlet.class在登录后将角色写入HttpSession、DBUnitHelper.class在每次数据库操作前校验 session 中的角色合法性。这套链路环环相扣拆开任何一环都会导致越权。3.1RoleServlet的初始化逻辑为什么首次访问/role/init是启动前提RoleServlet.class的作用不是处理日常请求而是系统初始化的“守门人”。它的doGet()方法中会检查数据库role表是否为空若为空则插入三条基础角色// 伪代码反编译自 RoleServlet.class if (roleDao.countAll() 0) { Role admin new Role(admin, 系统管理员); Role teacher new Role(teacher, 任课教师); Role student new Role(student, 参加考试学生); roleDao.insert(admin); roleDao.insert(teacher); roleDao.insert(student); }参数说明role表结构通常为(id INT PK, role_name VARCHAR(20), description VARCHAR(100))。其中role_name字段值admin/teacher/student必须与web.xml中role-name完全一致也必须与UserServlet.class登录成功后session.setAttribute(role, role_name)存入的值相同。这是整个权限体系的“信任根”。3.2UserServlet的登录态管理HttpSession的生命周期与DBUnitHelper的双重校验UserServlet.class的doPost()处理登录的核心流程如下// 1. 从表单获取用户名密码 String username request.getParameter(username); String password request.getParameter(password); // 2. 调用 UserDao 查询用户DBUnitHelper 封装了 PreparedStatement 防注入 User user userDao.findByUsername(username); // 3. 密码比对注意不是明文比对 if (user ! null MD5Util.verify(password, user.getPasswordSalt(), user.getPasswordHash())) { // 4. 将用户信息存入 session HttpSession session request.getSession(true); session.setAttribute(userId, user.getId()); session.setAttribute(username, user.getUsername()); session.setAttribute(role, user.getRoleName()); // 关键存 role_name 字符串 // 5. 重定向到对应首页 if (admin.equals(user.getRoleName())) { response.sendRedirect(admin/index.jsp); } else if (teacher.equals(user.getRoleName())) { response.sendRedirect(teacher/index.jsp); } else { response.sendRedirect(student/index.jsp); } } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); }逻辑说明session.setAttribute(role, ...)是权限分发的起点。后续所有 Servlet如SubjectServlet.class都会先调用request.getSession().getAttribute(role)获取当前角色再决定是否允许执行操作。而DBUnitHelper.class的safeExecuteUpdate()方法内部会读取ThreadLocal中存储的当前 session ID并在 SQL 日志中打标便于审计——这是原生 J2EE 实现“操作可追溯”的朴素方式。3.3StudentpaperServlet的试卷防篡改机制URL 参数校验 Session 状态锁学生点击“开始考试”时前端会发起请求/exam/studentpaper?paperId123timeLimit60。StudentpaperServlet.class的doGet()必须做三重校验URL 参数校验检查paperId是否为数字且在数据库paper表中存在Session 状态校验确认session.getAttribute(role)为student且session.getAttribute(examStatus)为null防止重复点击时间戳锁校验在session中存入examStartTime System.currentTimeMillis()并在doPost()提交时比对System.currentTimeMillis() - examStartTime timeLimit * 60 * 1000。// StudentpaperServlet.class 中的关键校验片段反编译逻辑 String paperIdStr request.getParameter(paperId); if (paperIdStr null || !paperIdStr.matches(\\d)) { throw new ServletException(非法试卷ID); } int paperId Integer.parseInt(paperIdStr); // 检查试卷是否存在且未过期 Paper paper paperDao.findById(paperId); if (paper null || paper.getEndTime().before(new Date())) { throw new ServletException(试卷不存在或已过期); } // 检查 session 中是否已有考试状态 if (session.getAttribute(examStatus) ! null) { response.sendRedirect(student/alreadyInExam.jsp); return; } // 设置考试状态锁 session.setAttribute(examStatus, started); session.setAttribute(examPaperId, paperId); session.setAttribute(examStartTime, System.currentTimeMillis()); session.setAttribute(examTimeLimit, paper.getTimeLimit()); // 单位分钟参数说明paper.getTimeLimit()来自数据库paper表的time_limit字段单位为分钟。StudentpaperServlet.class在doPost()处理提交时会再次读取session.getAttribute(examStartTime)计算耗时若超时则拒绝提交并返回{code:403,msg:考试时间已到}。这种“服务端计时状态锁”组合比纯前端 JS 计时可靠得多。4. 避坑部署与调试中五个血泪经验现象、原因、解决一步到位这份 J2EE 源码不是开箱即用的玩具它带着 2010 年代 Java Web 开发的真实毛边。以下是我和三届学生在部署、答辩、压测中反复踩过的坑每一条都对应一个ClassNotFoundException、NullPointerException或HTTP 403错误页面。照着做能省下至少 8 小时无效排查。4.1 现象访问http://localhost:8080/exam/login.jsp显示空白页查看 Tomcat 日志报java.lang.ClassNotFoundException: com.exam.servlet.UserServlet原因web.xml中servlet-class配置的全限定名与实际 class 文件路径不匹配。常见于解压后未保持com.exam.servlet包结构或 class 文件被错误移动到classes/根目录下。解决进入WEB-INF/classes/目录执行find . -name UserServlet.class确认输出为./com/exam/servlet/UserServlet.class若输出为./UserServlet.class说明包路径丢失需重建目录mkdir -p com/exam/servlet mv UserServlet.class com/exam/servlet/检查web.xml中servlet-class值是否为com.exam.servlet.UserServlet注意大小写Java 区分大小写4.2 现象登录成功后重定向到admin/index.jsp但页面报javax.servlet.ServletException: java.lang.NullPointerException日志指向RoleDao.class原因RoleDao.class依赖DBUnitHelper.class获取数据库连接而DBUnitHelper.class中的 JDBC URL、用户名、密码是硬编码的。原始代码可能是jdbc:mysql://localhost:3306/exam但你的 MySQL 服务运行在 Docker 容器或非 3306 端口。解决用javap -c DBUnitHelper.class反编译查看字节码需 JDK bin 目录在 PATH搜索ldc指令找到类似ldc jdbc:mysql://localhost:3306/exam的字符串修改DBUnitHelper.class的唯一办法是找到原始 Java 源码资源中未提供但论文里有描述或用jclasslib工具打开 class 文件定位static块中的url变量赋值用十六进制编辑器如 HxD直接修改 class 字节码风险高慎用推荐方案在DBUnitHelper.class同级目录新建db.properties文件内容为jdbc.urljdbc:mysql://your-host:3306/exam然后用ClassLoader.getSystemResourceAsStream(db.properties)读取需重编译但资源未给源码故实际操作中我们选择重装 MySQL 到默认配置4.3 现象学生提交试卷后StudentpaperServlet.class报java.sql.SQLException: Parameter index out of range (1 number of parameters)数据库无记录原因StudentpaperServlet.class中拼接 SQL 时用了Statement而非PreparedStatement且?占位符数量与setXXX()方法调用次数不匹配。反编译发现其saveAnswers()方法中sql INSERT INTO answer VALUES (null, ?, ?, ?)但只调用了两次ps.setInt(1, userId)和ps.setInt(2, paperId)漏了第三个参数。解决查看answer表结构确认字段数。标准设计应为(id, user_id, paper_id, answer_json, submit_time)在StudentpaperServlet.class对应的saveAnswers()方法中补全ps.setString(3, answerJson)answerJson是前端传来的 JSON 字符串若无法修改 class可在数据库层面加默认值ALTER TABLE answer MODIFY answer_json TEXT DEFAULT {}4.4 现象教师登录后点击“添加试题”SubjectServlet.class返回HTTP 403 Forbidden但web.xml中未配置该路径的安全约束原因SubjectServlet.class的doPost()方法内手动校验了 session 角色String role (String) session.getAttribute(role); if (!teacher.equals(role) !admin.equals(role)) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; }而学生账号登录后session.getAttribute(role)可能为null因登录失败或 session 超时触发 403。解决在SubjectServlet.class的校验逻辑前增加null安全校验String role (String) session.getAttribute(role); if (role null || (!teacher.equals(role) !admin.equals(role))) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return; }或更彻底在UserServlet.class的doPost()登录成功分支末尾强制设置session.setAttribute(role, student)避免null状态4.5 现象Tomcat 启动后访问任何页面都报HTTP Status 404 – Not Found但web.xml中的servlet-mapping看似正确原因web.xml的 XML 声明头缺失或错误。J2EE 规范要求web.xml必须以标准声明开头?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0而原始web.xml可能只有?xml version1.0 encodingGBK?或缺少xsi:schemaLocation导致 Tomcat 7 无法解析。解决用文本编辑器打开WEB-INF/web.xml删除所有非标准声明严格按上述模板重写第一行及web-app根标签将encodingGBK改为encodingUTF-8避免中文注释乱码保存后重启 Tomcat5. 从DBUnitHelper到StudentpaperServlet用三步验证法确认你的部署真正可用而非表面能跑很多同学部署后看到登录页就以为成功了。但真正的“可用”意味着你能走通一个完整考试闭环学生登录 → 抽题 → 答题 → 提交 → 教师阅卷 → 成绩查询。这需要三层验证接口级验证curl 测试 Servlet、数据级验证直查数据库、行为级验证模拟真实用户操作。下面是我每次帮学生验收必做的三步每步都有可复制的命令和预期结果。5.1 接口级验证用 curl 绕过前端直击UserServlet和StudentpaperServlet的核心能力不要依赖浏览器用curl发送原始 HTTP 请求能最快暴露 Servlet 逻辑缺陷。以下命令均在exam项目部署到http://localhost:8080/exam后执行# 1. 验证 UserServlet 登录接口POST curl -X POST http://localhost:8080/exam/user \ -H Content-Type: application/x-www-form-urlencoded \ -d usernameadmin \ -d password123456 \ -i # -i 参数显示响应头重点看 Set-Cookie: JSESSIONIDxxx # 预期结果HTTP/1.1 302 Found响应头含 Set-Cookie且 Location: /exam/admin/index.jsp # 若返回 500说明 UserServlet.class 与 UserDao.class 或 DBUnitHelper.class 协作失败 # 2. 验证 StudentpaperServlet 试卷生成接口GET需携带 JSESSIONID # 先从上一步响应头中复制 JSESSIONID假设为 ABC123 curl -X GET http://localhost:8080/exam/studentpaper?paperId1 \ -H Cookie: JSESSIONIDABC123 \ -i # 预期结果HTTP/1.1 200 OK响应体为 JSON 格式试卷数据如 {paperId:1,questions:[{id:101,title:Java基础,options:[A,B,C,D]}] # 若返回 403说明 session 中 role 校验失败若返回 404说明 StudentpaperServlet.class 未正确映射 # 3. 验证答案提交接口POST需 JSON body curl -X POST http://localhost:8080/exam/studentpaper \ -H Cookie: JSESSIONIDABC123 \ -H Content-Type: application/json \ -d {paperId:1,answers:{101:A,102:C}} \ -i # 预期结果HTTP/1.1 200 OK响应体为 {code:200,msg:提交成功} # 若返回 400检查 JSON 格式若返回 500说明 StudentpaperServlet.class 的 saveAnswers() 方法中数据库操作异常参数说明-i参数强制显示 HTTP 响应头这是判断 Servlet 是否被 Tomcat 正确加载的关键。Set-Cookie头存在证明HttpSession已创建Location头存在证明重定向逻辑生效。绕过前端直接测试接口能排除 HTML/CSS/JS 的干扰直击 Java 逻辑层。5.2 数据级验证用 MySQL 命令行确认DBUnitHelper真正写入了数据接口返回成功不代表数据落库。必须登录 MySQL直查表内容。以下命令假设数据库名为exam用户名root# 1. 查看用户表确认 admin 用户存在且密码哈希正确 SELECT id, username, password_hash, password_salt, role_name FROM user WHERE username admin; # 预期role_name adminpassword_hash 为 32 位 MD5 字符串如 21232f297a57a5a743894a0e4a801fc3 # 2. 查看试卷表确认 paperId1 的试卷存在且题目数正确 SELECT p.id, p.title, COUNT(q.id) as question_count FROM paper p LEFT JOIN question q ON p.id q.paper_id WHERE p.id 1 GROUP BY p.id; # 预期question_count 0证明 SubjectServlet.class 初始化题库成功 # 3. 查看答案表确认学生提交的答案已持久化 SELECT a.id, a.user_id, a.paper_id, a.answer_json, a.submit_time FROM answer a WHERE a.paper_id 1 AND a.user_id 1 ORDER BY a.submit_time DESC LIMIT 1; # 预期answer_json 字段为 JSON 字符串如 {101:A,102:C}submit_time 为当前时间逻辑说明DBUnitHelper.class的价值在于它封装了Connection和PreparedStatement但最终数据是否写入必须由数据库本身证实。answer_json字段存的是 JSON 字符串而非关系型结构这是 J2EE 原生项目为快速迭代做的妥协——它牺牲了 SQL 查询灵活性换取了前端渲染自由度。验证此字段存在且格式正确就证明StudentpaperServlet.class的saveAnswers()方法调用DBUnitHelper.safeExecuteUpdate()成功。5.3 行为级验证用 Selenium 脚本模拟真实考生捕获页面 JS 错误与网络请求接口和数据都 OK最后一步是模拟真人操作。我用 Python Selenium 写了一个极简脚本它会自动完成登录、抽题、答题、提交全流程并捕获页面控制台错误# test_exam_flow.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver webdriver.Chrome() wait WebDriverWait(driver, 10) try: # 1. 访问登录页 driver.get(http://localhost:8080/exam/login.jsp) # 2. 输入账号密码admin/123456 driver.find_element(By.NAME, username).send_keys(admin) driver.find_element(By.NAME, password).send_keys(123456) driver.find_element(By.XPATH, //input[typesubmit]).click() # 3. 等待跳转到 admin 首页并点击“学生管理” wait.until(EC.url_contains(admin/index.jsp)) driver.find_element(By.LINK_TEXT, 学生管理).click() # 4. 点击第一个学生进入其考试页面 wait.until(EC.presence_of_element_located((By.XPATH, //tr[2]/td[1]/a))) driver.find_element(By.XPATH, //tr[2]/td[1]/a).click() # 假设第二行是学生 # 5. 点击“开始考试”等待试卷加载 wait.until(EC.element_to_be_clickable((By.ID, startExamBtn))) driver.find_element(By.ID, startExamBtn).click() # 6. 捕获页面 JS 错误关键 logs driver.get_log(browser) for log in logs: if log[level] SEVERE: print(JS Error:, log[message]) # 7. 提交试卷 driver.find_element(By.ID, submitPaperBtn).click() wait.until(EC.alert_is_present()) driver.switch_to.alert.accept() print(✅ 行为级验证通过全流程自动化走通) except Exception as e: print(❌ 行为级验证失败, str(e)) finally: driver.quit()技巧说明driver.get_log(browser)是 Selenium 4 的关键能力它能捕获 Chrome 控制台的SEVERE级别错误即 JS 运行时错误。在 J2EE 原生项目中前端 JS 常因document.getElementById(xxx)找不到元素而报错这种错误不会影响后端但会导致学生无法点击提交按钮。运行此脚本若输出JS Error: ...说明前端 HTML 结构与 JS 逻辑不匹配需检查student/exam.jsp中的 DOM ID 是否与 JS 脚本一致。从那以后我每次部署新环境都强制走一遍这个 Selenium 脚本它比人工点十遍都准。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →