FEATURED · 精选文章

传统架构在线考试系统开发实践与优化

发布时间 / 2026/9/12 15:01:08
来源 / 创域科博编辑部
栏目 / 资讯中心
传统架构在线考试系统开发实践与优化 1. 项目概述传统架构下的在线考试系统实践十年前我刚入行时参与的第一个企业级项目就是某省级职业资格认证考试系统那会儿前后端分离架构还没现在这么普及。最近接手一个县域教师培训考试平台的需求客户明确要求采用传统架构开发。这让我重新审视了前后端不分离模式在特定场景下的价值。在线考试系统本质上是一个高并发、强一致性的业务系统核心功能模块包括考生管理、题库管理、组卷策略、在线作答、自动阅卷和成绩统计等。采用传统架构意味着所有业务逻辑、页面渲染和数据处理都在服务端完成前端仅负责展示HTML页面和基础交互。这种模式在考试防作弊、快速响应需求变更和降低运维复杂度方面有着独特优势。2. 技术选型与架构设计2.1 基础技术栈选择我们最终确定的方案是后端Java 8 Spring MVC 4.3模板引擎Thymeleaf 3.0数据库MySQL 5.7 Redis 4.0前端jQuery 3.5 Bootstrap 4.6选择这套组合主要基于三个考量技术成熟度这些版本都是经过长期验证的稳定版本团队熟悉度开发成员都有相关项目经验性能表现基准测试显示能满足2000人同时在线的需求重要提示Thymeleaf相比JSP更符合现代开发习惯其自然模板特性可以让HTML保持浏览器直接打开的可读性这对后期维护非常重要。2.2 系统分层架构典型的传统架构分为五层表现层JSP/Thymeleaf模板 静态资源控制层Spring MVC控制器服务层业务逻辑实现持久层MyBatis数据访问存储层MySQL关系型存储这种分层在IDE中对应标准的Maven多模块项目结构exam-system ├── exam-web // 表现层 ├── exam-service // 业务逻辑层 ├── exam-dao // 数据访问层 └── exam-common // 公共组件3. 核心功能实现细节3.1 考试防作弊机制实现在传统架构下实现防作弊比前后端分离方案更可靠我们主要做了这些防护页面防篡改// 在BaseController中增加响应拦截 protected void render(String viewName, Model model) { model.addAttribute(_token, TokenUtil.generate(request.getSession().getId())); //...其他公共参数 return viewName; }定时抓拍监控setInterval(function(){ $.post(/monitor/snapshot, { image: getCanvasImage(), _token: $(#_token).val() }); }, 300000); // 每5分钟上传一次屏幕截图答案加密传输// 使用AES加密考生答案 public String encryptAnswer(String answer) { String key session.getId().substring(0,16); return AESUtil.encrypt(answer, key); }3.2 高并发组卷策略考试系统的核心难点之一是组卷我们实现了三种组卷方式固定试卷预先生成完整试卷随机抽题根据规则实时组卷智能组卷基于知识图谱的推荐随机组卷的SQL示例SELECT * FROM question WHERE subject_id#{subjectId} AND difficulty BETWEEN #{min} AND #{max} ORDER BY RAND() LIMIT #{count}性能提示在大题量场景下10万题库应该先用Redis的SRANDMEMBER命令预筛选ID再到MySQL查询详情。4. 性能优化实战经验4.1 页面加载加速方案传统架构最被诟病的就是页面加载速度我们通过以下手段优化静态资源版本化link href/css/style.css?v20230618 relstylesheet关键CSS内联将首屏渲染必需的CSS直接写在 中智能缓存策略GetMapping(/paper/{id}) public String getPaper(PathVariable Long id, Model model) { String cacheKey paper_ id; Paper paper redisTemplate.opsForValue().get(cacheKey); if(paper null) { paper paperService.getById(id); redisTemplate.opsForValue().set(cacheKey, paper, 2, HOURS); } model.addAttribute(paper, paper); return exam/paper; }4.2 数据库优化技巧试题表垂直拆分-- 基础信息表 CREATE TABLE question ( id BIGINT PRIMARY KEY, type TINYINT, subject_id INT, difficulty TINYINT, -- 其他元数据 ); -- 内容表大字段分离 CREATE TABLE question_content ( qid BIGINT PRIMARY KEY, content TEXT, answer TEXT, analysis TEXT );阅卷结果异步处理Transactional public void submitPaper(Paper paper) { // 1. 保存考生答案 answerDao.save(paper.getAnswers()); // 2. 发送阅卷消息 jmsTemplate.convertAndSend(paper.marking, new MarkingTask(paper.getId())); // 3. 更新考试状态 examDao.updateStatus(paper.getExamId(), SUBMITTED); }5. 踩坑实录与解决方案5.1 文件上传内存溢出初期采用默认配置导致大文件上传时频繁OOM# 正确配置示例application.properties spring.servlet.multipart.max-file-size10MB spring.servlet.multipart.max-request-size20MB server.tomcat.max-swallow-size20MB更优方案是实现分片上传// 前端分片处理 function uploadFile(file) { const chunkSize 1 * 1024 * 1024; // 1MB let chunks Math.ceil(file.size / chunkSize); for(let i0; ichunks; i) { let chunk file.slice(i*chunkSize, (i1)*chunkSize); let formData new FormData(); formData.append(chunk, chunk); formData.append(chunkIndex, i); formData.append(totalChunks, chunks); $.ajax({ url: /upload, data: formData, processData: false, contentType: false, type: POST }); } }5.2 考试倒计时同步问题客户端时间不可靠必须采用服务端时间同步方案!-- 页面加载时获取服务器时间 -- script th:inlinejavascript var serverTime [[${#dates.createNow().time}]]; var clientTime new Date().getTime(); var timeDiff clientTime - serverTime; function getServerTime() { return new Date(new Date().getTime() - timeDiff); } /script定时同步机制// 每5分钟同步一次时间 setInterval(function(){ $.get(/api/time, function(serverTime){ timeDiff new Date().getTime() - serverTime; }); }, 300000);6. 传统架构的现代演进虽然项目采用传统架构但我们仍然引入了一些现代工程实践API混合模式关键业务接口同时提供JSON格式输出GetMapping(/paper/{id}) public String paperDetail(PathVariable Long id, Model model) { Paper paper paperService.getById(id); model.addAttribute(paper, paper); return paper/detail; } GetMapping(/api/paper/{id}) ResponseBody public ResultPaper getPaperApi(PathVariable Long id) { return Result.success(paperService.getById(id)); }前端组件化通过Thymeleaf片段实现组件复用!-- /templates/fragments/header.html -- header th:fragmentmainHeader nav classnavbar.../nav /header !-- 页面引用 -- div th:replace~{fragments/header :: mainHeader}/div构建优化使用webjars管理前端依赖!-- pom.xml -- dependency groupIdorg.webjars/groupId artifactIdjquery/artifactId version3.6.0/version /dependency在项目上线后的性能监测中这套架构成功支撑了单场3500人同时在线的考试平均响应时间保持在1.2秒以内。最大的收获是认识到架构选择没有绝对的好坏关键是要适合业务场景和团队能力。对于需要快速迭代的中小型考试系统传统架构反而能减少沟通协调成本让全栈工程师可以端到端地解决问题。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻