简介这是一套面向教学评估与考试组织场景的局域网考试系统完整源码包适合高校教师、教务管理人员及.NET开发者研究部署与二次定制。系统采用B/S架构覆盖试题库管理、组卷策略、考生信息维护、自动阅卷、成绩统计与防作弊等核心模块并包含模拟考试、错题集等拓展功能可满足局域网内练习与正式测试的双重需求。压缩包共84个文件约4.08MB以cs源码、resx资源文件、exe可执行程序、msi安装包为主辅以ini配置、mdb数据库、sln解决方案及图标素材服务端与客户端结构分明便于按模块阅读与调试。目前已有450人学习下载。通过源码可深入理解考试流程控制、组卷算法与成绩管理实现是学习WinForm项目架构与教育信息化系统开发的实用参考。1. 局域网考试系统断网环境下的考场为什么反而更考验架构机房断网、Wi-Fi 关闭、外网出口封死监考老师拿着一台笔记本当服务器五十台学生机通过交换机连进来答题——这是局域网考试系统最典型的落地场景。它要解决的核心问题不是「怎么把卷子显示出来」而是断网条件下如何保证试卷下发不丢、答案回收不重、交卷时间统一、断电后还能恢复。适合谁用学校机房管理员、企业内训考核负责人、认证机构考务实施人员以及需要在内网做无纸化测评的团队。很多人以为局域网考试系统就是把 Web 应用搬到内网跑真正做过才知道网络隔离带来的时钟同步、并发写入、断线重连、数据一致性才是决定成败的地方。这篇笔记按「先立架构、再动手部署、最后排坑」的顺序把一套可复现的方案讲清楚。2. 局域网考试系统的架构选型B/S 还是 C/S数据库怎么定2.1 三种常见架构的取舍局域网考试系统的架构选择直接决定了后面部署和排障的难度。常见做法有三类纯 B/S浏览器访问、C/S客户端安装、以及 B/S 加本地缓存的混合模式。纯 B/S 部署最省事学生机只要浏览器打开服务器 IP 就能答题但浏览器在断线时的行为不可控刷新即丢答案C/S 客户端可以本地落盘断线重连后补传但每台机器都要装版本更新麻烦混合模式是现在比较稳的方案——浏览器负责渲染前端用 IndexedDB 或 localStorage 做本地暂存定时向服务器同步。我一般会推荐混合模式理由很直接机房网络虽然叫「局域网」但交换机抖动、网线松动、学生误拔线的情况一点都不少。纯 B/S 一旦断线学生答了半小时的题可能全没了这是考务事故。混合模式让答案先落本地再异步上传把「网络可用性」和「答题连续性」解耦。选型时还要考虑并发规模。五十人以内单台服务器加 SQLite 都能扛一百到三百人建议 MySQL 或 PostgreSQL超过五百人同时在线就要考虑读写分离或者把答题写入做成队列。别小看这个数字考试的特点是「同一秒所有人都在提交」瞬时写入压力比日常业务高得多。2.2 数据库与时钟同步的硬性要求局域网考试系统对数据库的要求和普通 Web 应用不太一样。核心是两点写入要能扛住瞬时并发时间字段要能作为判卷依据。我一般用 MySQL 8 的 InnoDB答题记录表按exam_id student_id建联合索引提交时用INSERT ... ON DUPLICATE KEY UPDATE保证同一学生重复提交不会产生脏数据。时钟同步是容易被忽略的坑。局域网里服务器和学生机的系统时间可能差几分钟如果交卷时间以客户端时间为准就会出现「有人提前交、有人超时还在答」的争议。正确做法是所有时间判断以服务器时间为准客户端只负责显示倒计时每次心跳同步一次剩余时间。-- 答题记录表用唯一键保证同一学生同一题只有一条有效记录 CREATE TABLE answer_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, exam_id INT NOT NULL, student_id VARCHAR(32) NOT NULL, question_id INT NOT NULL, answer TEXT, client_ts DATETIME, -- 客户端提交时间仅作参考 server_ts DATETIME DEFAULT CURRENT_TIMESTAMP, -- 服务器落库时间判卷依据 synced TINYINT DEFAULT 0, -- 0本地暂存待同步1已入库 UNIQUE KEY uk_stu_q (exam_id, student_id, question_id), KEY idx_exam_stu (exam_id, student_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段建表语句的关键在UNIQUE KEY uk_stu_q它让重复提交变成更新而不是插入避免断线重连后同一题出现两条记录。server_ts用数据库默认值生成不信任客户端传上来的时间。synced字段配合前端本地缓存使用标记哪些答案还没成功上传。参数上student_id用 VARCHAR 而不是 INT是因为学号常带字母前缀answer用 TEXT 是为了兼容多选、填空、简答等题型。如果考试规模大可以把answer_record按exam_id做分区减少单表体积。2.3 部署拓扑与最小可跑环境一套能跑起来的局域网考试系统最小拓扑是一台服务器可以是普通 PC 或工控机、一台交换机、若干学生机。服务器装 Nginx 应用服务 数据库学生机只需要浏览器。如果做混合模式前端静态资源由 Nginx 直接托管答题接口走应用服务。部署时我习惯把服务器 IP 固定比如192.168.1.100学生机通过这个地址访问。DHCP 也可以但考场环境里固定 IP 更省心避免 IP 变化导致学生找不到入口。下面是一个 Nginx 配置片段用于托管前端并反代答题接口server { listen 80; server_name 192.168.1.100; # 前端静态资源 location / { root /opt/exam/web; index index.html; try_files $uri $uri/ /index.html; } # 答题接口反代到后端 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 30s; # 交卷高峰适当调大 } }try_files那行是为了支持前端路由刷新页面不会 404。proxy_read_timeout默认 60s考试交卷瞬间请求集中如果后端处理慢超时会导致学生看到「提交失败」所以这里显式设置并配合后端异步落库。root指向的目录要提前放好构建产物权限设为 Nginx 用户可读。3. 局域网考试系统怎么部署从零到学生能答题的完整步骤3.1 服务器环境准备与依赖安装先在服务器上装好基础环境。以 Ubuntu 22.04 为例装 JDK 或 Node 运行时、MySQL、Nginx。假设后端用 Spring Boot 打包成 jar前端是 Vue 构建的静态文件。命令按顺序执行# 更新源并安装基础组件 sudo apt update sudo apt install -y openjdk-17-jre mysql-server nginx # 启动并设置开机自启 sudo systemctl enable --now mysql nginx # 创建数据库和专用账号 sudo mysql -e CREATE DATABASE exam_db DEFAULT CHARSET utf8mb4; sudo mysql -e CREATE USER examlocalhost IDENTIFIED BY Exam2024; sudo mysql -e GRANT ALL ON exam_db.* TO examlocalhost; sudo mysql -e FLUSH PRIVILEGES;装完先别急着启动应用确认 MySQL 和 Nginx 都在跑systemctl status mysql和systemctl status nginx。数据库账号密码不要用 root考试系统虽然在内网但学生机数量多弱口令被扫的风险依然存在。Exam2024只是示例实际部署换成强密码并记录在考务手册里。3.2 应用配置与启动参数后端应用的配置文件里重点是数据库连接、端口、以及考试相关的业务参数。下面是一个application.yml的核心片段server: port: 8080 tomcat: max-threads: 200 # 交卷高峰线程数按考生数 1.5 倍设 accept-count: 300 # 等待队列 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/exam_db?useSSLfalseserverTimezoneAsia/Shanghai username: exam password: Exam2024 hikari: maximum-pool-size: 50 # 连接池上限别超过 MySQL max_connections connection-timeout: 3000 exam: duration-minutes: 90 # 考试时长 heartbeat-seconds: 10 # 客户端心跳间隔 autosave-seconds: 15 # 本地暂存间隔 allow-reconnect: true # 允许断线重连max-threads和maximum-pool-size要匹配。如果考生 100 人Tomcat 线程 200 够用但连接池 50 意味着同时只有 50 个请求能拿到数据库连接其余排队。交卷时如果每人都触发一次写库排队时间会拉长。稳妥做法是把交卷写入做成异步接口收到请求先返回「已接收」后台线程池慢慢落库。heartbeat-seconds设 10 秒是为了让服务器能及时发现掉线学生同时不至于心跳包太频繁压垮网络。autosave-seconds设 15 秒是本地暂存的节奏断线时最多丢 15 秒的答案这个损失考务上可以接受。3.3 学生机接入与答题流程验证服务器起来后用一台学生机做全流程验证。浏览器打开http://192.168.1.100登录、选题、答题、交卷每一步都确认。重点验证三个场景正常交卷、答题中断网再恢复、以及服务器重启后学生能否继续。断网恢复的验证方法答题到一半拔掉学生机网线继续答几题再插回网线。观察前端是否提示「离线暂存」恢复后是否自动补传。这个流程能跑通说明混合模式生效了。服务器重启验证考试中途重启后端服务学生端应该显示「连接中断正在重连」服务恢复后自动续上已答内容不丢。// 前端本地暂存与同步的核心逻辑 const AUTOSAVE_KEY exam_answers; // 每 15 秒把当前答案写入 localStorage setInterval(() { const answers collectAnswers(); // 从页面收集当前答案 localStorage.setItem(AUTOSAVE_KEY, JSON.stringify({ examId: EXAM_ID, studentId: STUDENT_ID, data: answers, ts: Date.now() })); }, 15000); // 心跳每 10 秒向服务器同步一次顺便拉取剩余时间 setInterval(async () { try { const res await fetch(/api/heartbeat, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({examId: EXAM_ID, studentId: STUDENT_ID}) }); const {remainSeconds} await res.json(); updateCountdown(remainSeconds); // 以服务器时间为准刷新倒计时 await flushLocalAnswers(); // 把本地暂存补传上去 } catch (e) { showOfflineTip(); // 网络异常提示不阻断答题 } }, 10000);这段代码的关键是「本地暂存」和「心跳补传」分离。暂存不依赖网络心跳失败也不影响答题只是提示离线。flushLocalAnswers在心跳成功时把 localStorage 里的答案批量提交服务端用前面说的唯一键做幂等重复提交不会出错。updateCountdown用服务器返回的剩余秒数刷新避免客户端时间被篡改。4. 局域网考试系统避坑五个真实翻车现场4.1 交卷瞬间服务器 502学生以为没交上现象考试结束前五分钟大量学生点击交卷页面返回 502学生反复点击考务群炸锅。原因交卷接口同步写库瞬时并发超过 Tomcat 线程和连接池上限请求堆积后 Nginx 超时返回 502。解决把交卷改成异步——接口只做参数校验和入队立即返回「已接收」后台消费者慢慢落库同时前端在收到「已接收」后锁定交卷按钮禁止重复点击。Nginx 的proxy_read_timeout调到 30s 以上给排队留时间。4.2 断线重连后答案重复判卷出现两条记录现象学生断网后重连同一道题在数据库里有两条记录判卷时分数算重。原因前端补传时用了INSERT而不是幂等更新或者唯一键没建对。解决答题表必须建(exam_id, student_id, question_id)唯一键提交语句用INSERT ... ON DUPLICATE KEY UPDATE。前端补传前先拉一次服务器已有答案做本地合并减少无效请求。4.3 倒计时不准有人多答了十分钟现象考试结束有学生说自己的倒计时比别人的慢多答了题。原因倒计时用客户端setInterval累加浏览器切到后台标签页时定时器被节流时间走慢。解决倒计时不用累加每次心跳用服务器返回的remainSeconds直接覆盖显示页面visibilitychange事件触发时立即拉一次服务器时间。服务器端判卷以server_ts为准超时提交的答案标记为无效。4.4 服务器 IP 变了全场学生找不到入口现象考场临时换了网段服务器 IP 从192.168.1.100变成192.168.0.100学生机还开着旧地址全部白屏。原因服务器用 DHCP 获取 IP或者考务人员手动改网络没通知。解决服务器必须配静态 IP并在交换机上做 IP-MAC 绑定学生机入口用短域名或 hosts 解析比如exam.localIP 变了只改一处。考前用一台样机全流程验证别等开考才发现。4.5 数据库磁盘满考试中途写入失败现象考试进行到一半学生提交答案报错后台日志显示Disk full。原因MySQL 的 binlog 和临时文件把磁盘占满或者答题记录表没做清理历史数据堆积。解决考前检查磁盘剩余空间至少留 20%binlog 设置过期时间expire_logs_days7答题记录按考试场次归档考完导出后清理。监控脚本在磁盘低于 15% 时告警别等写不进去才发现。5. 局域网考试系统的压测与验收开考前怎么确认它扛得住压测是局域网考试系统上线前最值得花时间的一步。我一般用wrk或JMeter模拟并发交卷重点看三个指标交卷接口的 P99 延迟、数据库连接池等待时间、以及服务器 CPU 和内存。下面是一个用wrk压测交卷接口的示例# 模拟 100 并发持续 60 秒POST 交卷请求 wrk -t4 -c100 -d60s -s submit.lua http://192.168.1.100/api/submit # submit.lua 内容构造交卷请求体 # wrk.method POST # wrk.body {examId:1,studentId:S001,answers:[...]} # wrk.headers[Content-Type] application/json-t4是 4 个线程-c100是 100 个并发连接-d60s持续 60 秒。看输出里的Latency和Requests/sec如果 P99 超过 2 秒说明后端处理不过来要加线程或改异步。压测数据用真实题量构造别用空请求否则测不出数据库写入的压力。验收清单我习惯列成表格考前逐项打勾检查项合格标准验证方法交卷 P99 延迟 2 秒wrk 压测 100 并发断线重连答案不丢不重拔网线答题再插回倒计时准确性与服务器差 1 秒对比服务器时间磁盘剩余 20%df -h数据库连接池无等待超时压测时看日志服务器重启恢复学生可继续答题中途重启后端压测通过不代表万事大吉考场环境还有变量交换机性能、网线质量、学生机浏览器版本。我的习惯是考前一天用真实机房做一次全流程演练让几位老师当「学生」走一遍把问题暴露在开考前。这套方案值不值得做如果每年有多次考试需求一次投入能把考务从「收卷、判卷、登分」里解放出来答案是值得。但别指望部署完就不管考前检查和压测是必须保留的动作这是我踩过坑之后养成的习惯。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
OpenCV 4.8.0在VS2019下动态与静态编译全攻略:从配置到避坑 简介:本资源面向使用 Visual Studio 进行 C 计算机视觉开发的工程师与学习者,提供 OpenCV 4.8.0 在 X64 架构下的完整编译成果:VS2019 动态编译与 VS2022 静态编译两套方案,帮助开发者省去从 CMake 配置到链接器调优的繁琐过程&am… · 2026/9/26 4:39:56
达达麻将Cocos Creator源码二次开发与上线避坑指南 简介:这份资源是面向棋牌游戏开发者与Cocos Creator学习者的达达麻将完整项目源码,适合具备一定JavaScript基础、希望了解网络棋牌游戏前后端架构的中高级开发者参考。项目以Cocos Creator为客户端引擎,结合JavaScript实现麻将规则、用户交互… · 2026/9/26 4:39:56
Kubernetes DaemonSet详解:节点守护、调度策略与生产实践 1. 为什么需要DaemonSet:一批“长在节点上”的守护进程先从一个最朴素的问题说起:Kubernetes里已经有Deployment、StatefulSet、Job这些工作负载,它们能把Pod调度到集群的各个节点上,为什么还要单独搞一个DaemonSet控制器… · 2026/9/26 4:39:56
透彻理解Java泛型:类型擦除、桥接方法与实战代码解析 对于搞 Java 的朋友来说,泛型是个绕不开的话题。日常写业务代码要用到它,面试的时候更是高频考点,最近常见的 Java 面试八股文里,泛型那一栏的出镜率一直不低。我发现一个有意思的现象:很多人写代码能熟练使用 List、M… · 2026/9/26 17:23:37
创业第274天:一个SaaS创业者的日常复盘与决策笔记 2026年1月8日,是我独立创业的第274天。项目是一款叫“店小ai”的SaaS工具,服务本地生活类小商家,帮他们自动回复私信、自动发券、整理顾客评价。这个方向不算性感,但现金流踏实,甲方都是美甲店、理发店、小餐馆的老板&… · 2026/9/26 17:23:37
创业第413天:砍掉低效功能,聚焦核心路径 2026年1月8日,周四。创业第413天,早上七点零三分醒来,窗外雾霾比昨天淡了一些。半小时后我坐到书桌前,打开电脑,开始一天的工作。今天这篇不打算写什么宏大叙事,就想把创业日常里真实的一天,包括… · 2026/9/26 17:23:37
石油炼化回转窑焚烧系统三维动画案例全解析 1. 项目背景与核心需求拆解
1.1 为什么炼化企业需要给回转窑做三维动画 先把这个项目的来龙去脉说清楚。石油炼化行业的危废处理环节里,回转窑焚烧系统是妥妥的“重装备”——它负责处理油泥、废催化剂、污水处理站浮渣这些危险废物,工作温度动辄上千摄… · 2026/9/26 17:23:37
Python3 提取 MySQL 数据并转字典数组:TaoToken 统一 Key 配置与验证 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 17:23:11
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46