ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SSM+JSP在线考试系统与LD算法编程题自动判分实战

SSM+JSP在线考试系统与LD算法编程题自动判分实战 简介这是一套基于SSM框架SpringSpringMVCMyBatis、JSP前端与MySQL数据库开发的在线考试系统核心亮点在于集成LDLevenshtein Distance字符串编辑距离算法实现编程题自动判分有效支撑代码相似度比对与基础逻辑验证专为本科毕业设计、高校课程设计及中小型教学类项目开发量身打造。资源包共685个文件涵盖73个Java业务逻辑类、47个JSP页面、32个XML配置文件、55个JS交互脚本及153个GIF动图多用于后台管理界面操作示意辅以101个Jar依赖库和73个编译后Class文件结构完整、模块清晰压缩包大小为57.77MB。目前已有67人学习下载资源经严格测试可直接运行提供含学生/科目管理、在线组卷、限时考试、自动阅卷含编程题LD比对、成绩统计等全链路功能源码并附带ASP/ASHX等兼容性接口文件便于拓展Web服务集成与跨平台调用。1. 为什么毕业设计选“SSMJSPMySQLLD算法的在线考试系统”能稳过答辩、还能真跑起来不是所有毕设都叫“能上线”。我带过三届计科/软工本科生做毕业设计翻车最多的是两类一类是“SpringBootVue”看着时髦结果前端跨域调不通、部署到Tomcat报404、答辩现场连登录页都打不开另一类是“纯理论判分”说“用Levenshtein Distance算代码相似度”但没写一行判分逻辑答辩老师问“你比对的是token还是AST空格和换行怎么处理”当场哑火。而这个标题——基于SSMJSPMySQLLD算法实现的在线考试系统编程题自动判分——恰恰卡在“有技术深度、有工程闭环、有可演示亮点”的黄金交叉点上SSMSpringSpringMVCMyBatis是Java Web最扎实的分层架构JSP在Tomcat里零配置就能渲染页面MySQL支撑高并发小事务毫无压力最关键的是LD算法Levenshtein Distance不是PPT里的名词而是你能在JudgeService.java里亲手写出getEditDistance(String s1, String s2)并调试通过的真实判分引擎。它不追求AI大模型式炫技但能让你在答辩时打开后台管理页点开某道编程题的判分日志指着distance3, similarity0.85说清楚“学生答案比标准答案多写了两个空格、少了一个分号所以扣1分”。适合想踏实做、能动手调、靠细节赢过答辩的开发者——尤其适合用IDEA新建传统Web项目、不碰Docker和Nginx、只靠一台Windows笔记本就能从零搭起全链路的同学。2. 搭建SSMJSP环境绕开IDEA新建JSP项目的5个经典陷阱2.1 用IDEA创建“正宗”SSM Web项目不是选Spring Initializr很多同学第一步就错在IDEA里点“New Project”→“Spring Initializr”生成一个SpringBoot项目再硬塞JSP进去。结果发现% page contentTypetext/html;charsetUTF-8 %报红webapp/WEB-INF/web.xml被忽略Controller返回的JSP路径死活404。SSMJSP必须走传统Web Application路线。正确步骤如下File → New → Project → Java Enterprise → Web Application勾选Create web.xml在Project SDK选你装好的JDK 1.8注意JDK 11默认不支持JSP毕设务必用JDK 1.8点击Next不要勾选任何框架模板手动配SSM完成后在Project Structure → Modules → Dependencies里添加spring-webmvc-5.3.39.jarmybatis-3.4.6.jarmysql-connector-java-5.1.47.jarjstl-1.2.jarJSP标签库否则c:if报错提示所有jar包统一放webapp/WEB-INF/lib/下别放lib文件夹或Maven依赖里——JSP编译器只认WEB-INF/lib。2.2 配置web.xml让SpringMVC接管JSP请求的3个生死节点webapp/WEB-INF/web.xml是整个项目的“宪法”漏掉任意一行JSP就是白纸。以下是精简但必填的配置?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 !-- 1. Spring容器监听器加载applicationContext.xml -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:applicationContext.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener !-- 2. SpringMVC前端控制器拦截所有*.do请求 -- servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern*.do/url-pattern /servlet-mapping !-- 3. JSP中文乱码过滤器解决表单提交中文变?? -- filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping /web-app关键参数说明url-pattern*.do/url-pattern强制所有业务请求走.do后缀如/exam/start.do避免与静态资源冲突param-valueclasspath:applicationContext.xml/param-valueSpring核心配置必须放在src/main/resources/下且文件名严格为applicationContext.xmlparam-valueUTF-8/param-valueforceEncodingtrue确保GET/POST请求全部UTF-8解码否则学生姓名“张三”存进MySQL变成“å¼ ä¸‰”。2.3 SSM三层结构落地Controller→Service→Mapper的最小可行代码链光有配置不行得让代码真正跑通。以下是最小闭环示例以“获取考试列表”为例Controller层ExamController.javaController public class ExamController { Autowired private ExamService examService; RequestMapping(/exam/list.do) public String listExam(Model model) { ListExam exams examService.getAllExams(); model.addAttribute(exams, exams); // 传给JSP return exam/list; // 对应 webapp/WEB-INF/jsp/exam/list.jsp } }逻辑说明Controller标识这是MVC控制器RequestMapping绑定URLmodel.addAttribute()把数据塞进JSP上下文return exam/list是逻辑视图名SpringMVC会自动拼成/WEB-INF/jsp/exam/list.jsp。Service层ExamService.java ExamServiceImpl.java// 接口 public interface ExamService { ListExam getAllExams(); } // 实现类 Service public class ExamServiceImpl implements ExamService { Autowired private ExamMapper examMapper; // MyBatis Mapper接口 Override public ListExam getAllExams() { return examMapper.selectAll(); // 调用Mapper方法 } }参数说明Service让Spring管理该BeanAutowired自动注入ExamMapperService层不直接操作数据库只协调业务逻辑。Mapper层ExamMapper.java ExamMapper.xml// Mapper接口 public interface ExamMapper { ListExam selectAll(); }!-- ExamMapper.xml -- mapper namespacecom.example.mapper.ExamMapper select idselectAll resultTypecom.example.entity.Exam SELECT id, title, start_time, duration FROM exam /select /mapper关键点namespace必须与Mapper接口全限定名一致resultType指向实体类需有对应getter/setterSQL写在XML里不写在Java中——这是MyBatis的核心约定。3. MySQL建库建表按考试系统真实场景设计的5张核心表3.1 数据库初始化字符集、排序规则、用户权限三步到位别用phpMyAdmin点点点。毕设MySQL必须命令行初始化否则答辩时老师问“你用的什么字符集”答不上来直接扣分。执行以下命令# 1. 登录MySQL假设root密码为123456 mysql -u root -p123456 # 2. 创建数据库显式指定字符集关键 CREATE DATABASE online_exam DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 3. 创建应用专用用户比root安全答辩时能体现工程素养 CREATE USER exam_userlocalhost IDENTIFIED BY exam123; GRANT SELECT,INSERT,UPDATE,DELETE ON online_exam.* TO exam_userlocalhost; # 4. 刷新权限 FLUSH PRIVILEGES;注意utf8mb4支持emoji和生僻字如学生姓名“䶮”utf8在MySQL里实际是utf8mb3不支持4字节Unicodeexam_user权限仅限online_exam库符合最小权限原则。3.2 五张核心表DDL覆盖考试、题目、学生、作答、判分全链路考试系统不是CRUD练习表结构要反映真实业务约束。以下是经答辩验证的5张表含注释-- 1. 考试主表exam CREATE TABLE exam ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL COMMENT 考试标题, description TEXT COMMENT 考试说明, start_time DATETIME NOT NULL COMMENT 开始时间, duration INT NOT NULL COMMENT 持续分钟数如90, status TINYINT DEFAULT 1 COMMENT 状态0-禁用1-启用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 2. 题目表question支持单选、多选、编程题混合 CREATE TABLE question ( id INT PRIMARY KEY AUTO_INCREMENT, exam_id INT NOT NULL COMMENT 所属考试ID, type TINYINT NOT NULL COMMENT 题型1-单选2-多选3-编程题, content TEXT NOT NULL COMMENT 题目描述含代码片段, options JSON COMMENT 选项JSON{A:int,B:String}编程题为空, answer VARCHAR(500) NOT NULL COMMENT 标准答案单选存A编程题存标准代码, score INT DEFAULT 10 COMMENT 分值, FOREIGN KEY (exam_id) REFERENCES exam(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 3. 学生表student CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL COMMENT 学号, password VARCHAR(100) NOT NULL COMMENT BCRYPT加密密码, name VARCHAR(50) NOT NULL COMMENT 真实姓名, class_name VARCHAR(50) COMMENT 班级, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 4. 作答记录表submission CREATE TABLE submission ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL COMMENT 学生ID, question_id INT NOT NULL COMMENT 题目ID, answer TEXT NOT NULL COMMENT 学生提交的答案编程题为完整代码, submit_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 提交时间, score DECIMAL(5,2) DEFAULT 0.00 COMMENT 判分得分, is_judged TINYINT DEFAULT 0 COMMENT 是否已判分0-未判1-已判, FOREIGN KEY (student_id) REFERENCES student(id), FOREIGN KEY (question_id) REFERENCES question(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 5. 判分日志表judge_log——答辩时展示判分过程的关键表 CREATE TABLE judge_log ( id INT PRIMARY KEY AUTO_INCREMENT, submission_id INT NOT NULL COMMENT 关联作答ID, standard_code TEXT NOT NULL COMMENT 标准代码脱敏存储, student_code TEXT NOT NULL COMMENT 学生代码脱敏存储, edit_distance INT NOT NULL COMMENT LD算法计算出的编辑距离, similarity DECIMAL(5,4) NOT NULL COMMENT 相似度 1 - distance/max(len1,len2), judge_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (submission_id) REFERENCES submission(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;设计理由question.answer存标准代码而非ID编程题答案就是代码本身无需额外表关联submission.answer用TEXT类型学生可能提交上百行代码judge_log独立建表答辩时可直接SELECT * FROM judge_log WHERE submission_id123展示判分依据ON DELETE CASCADE删除考试时自动清空题目和作答避免脏数据。3.3 连接池配置Druid比C3P0更稳且能监控SQL慢查询别用DriverManager.getConnection()硬编码。毕设必须用连接池否则并发一高就报Too many connections。在applicationContext.xml中配置Druid!-- Druid数据源 -- bean iddataSource classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose property nameurl valuejdbc:mysql://localhost:3306/online_exam?useSSLfalseamp;serverTimezoneAsia/Shanghaiamp;allowPublicKeyRetrievaltrue/ property nameusername valueexam_user/ property namepassword valueexam123/ property nameinitialSize value5/ property nameminIdle value5/ property namemaxActive value20/ property namemaxWait value60000/ property nametimeBetweenEvictionRunsMillis value60000/ property nameminEvictableIdleTimeMillis value300000/ property namevalidationQuery valueSELECT 1/ property nametestWhileIdle valuetrue/ property namefilters valuestat,wall/ /bean参数说明maxActive20足够应付毕设演示50人并发testWhileIdletrue保证空闲连接有效性filtersstat,wall开启Druid监控页访问http://localhost:8080/druid看SQL执行时间——答辩时打开这个页面老师立刻信服你懂性能。4. LD算法实现编程题自动判分从字符串比对到生产级鲁棒性改造4.1 基础LD算法手写动态规划理解比调包更重要网上一堆apache-commons-text的LevenshteinDistance但毕设答辩时老师会问“你改过源码吗空格和换行怎么处理”。必须自己写且要能讲清每行逻辑。以下是经过答辩验证的JudgeService.java核心方法Service public class JudgeService { /** * 计算两段代码的Levenshtein Distance * param s1 标准代码 * param s2 学生代码 * return 编辑距离 */ public int getEditDistance(String s1, String s2) { if (s1 null || s2 null) return Integer.MAX_VALUE; if (s1.equals(s2)) return 0; // 预处理去除首尾空格统一换行符为\n关键 s1 normalizeCode(s1); s2 normalizeCode(s2); int len1 s1.length(); int len2 s2.length(); // dp[i][j] 表示 s1[0..i-1] 与 s2[0..j-1] 的最小编辑距离 int[][] dp new int[len1 1][len2 1]; // 初始化s1变空串需删i次s2变空串需删j次 for (int i 0; i len1; i) dp[i][0] i; for (int j 0; j len2; j) dp[0][j] j; // 状态转移 for (int i 1; i len1; i) { for (int j 1; j len2; j) { if (s1.charAt(i - 1) s2.charAt(j - 1)) { dp[i][j] dp[i - 1][j - 1]; // 字符相同不操作 } else { dp[i][j] Math.min( Math.min(dp[i - 1][j] 1, // 删除s1[i-1] dp[i][j - 1] 1), // 插入s2[j-1] dp[i - 1][j - 1] 1 // 替换s1[i-1]为s2[j-1] ); } } } return dp[len1][len2]; } /** * 代码标准化去除多余空格、统一换行、忽略连续空白符 */ private String normalizeCode(String code) { if (code null) return ; // 1. 统一换行符为\n code code.replace(\r\n, \n).replace(\r, \n); // 2. 去除每行首尾空格合并连续空白符为单个空格 String[] lines code.split(\n); StringBuilder sb new StringBuilder(); for (String line : lines) { line line.trim().replaceAll(\\s, ); if (!line.isEmpty()) { sb.append(line).append(\n); } } return sb.toString().trim(); } }逻辑说明normalizeCode()是成败关键——学生复制代码时可能带IDE自动缩进、多余空行、制表符\t不处理会导致distance虚高dp[i][j]二维数组是动态规划标准写法空间复杂度O(mn)毕设数据量小完全可接受。4.2 相似度计算与分数映射让LD结果变成可解释的“扣分项”LD算法输出的是整数距离但老师要看到“为什么扣2分”。需转换为百分制分数并给出可读日志/** * 根据编辑距离计算相似度并映射为得分 * param standard 标准代码 * param student 学生代码 * param fullScore 题目满分 * return 判分结果对象 */ public JudgeResult judgeCode(String standard, String student, int fullScore) { int distance getEditDistance(standard, student); int maxLength Math.max(standard.length(), student.length()); double similarity maxLength 0 ? 1.0 : 1.0 - (double) distance / maxLength; // 分数映射相似度≥0.95得满分0.8~0.95线性扣分0.8得0分 double score; if (similarity 0.95) { score fullScore; } else if (similarity 0.8) { score fullScore * (0.2 (similarity - 0.8) * 4); // 0.8→0.2*full, 0.95→1.0*full } else { score 0.0; } return new JudgeResult(distance, similarity, Math.round(score * 100.0) / 100.0); } // 判分结果封装类 public static class JudgeResult { public final int distance; public final double similarity; public final double score; public JudgeResult(int distance, double similarity, double score) { this.distance distance; this.similarity similarity; this.score score; } }参数说明similarity 1 - distance/max(len1,len2)是业界通用公式分数映射采用三段式≥0.95几乎一致给满分0.8~0.95有语法错误但逻辑对线性扣分0.8完全跑偏0分——答辩时可指着这个逻辑说“学生少写了一个for循环distance15similarity0.82所以得8.4分”。4.3 生产级加固应对学生“花式作答”的3种防御策略学生不会老老实实交标准格式代码。我在毕设指导中见过太多“翻车现场”有人交Python代码题干要求Java、有人把答案藏在注释里、有人用System.out.println(hello)代替return。LD算法必须加防护/** * 增强版判分先做合法性校验再LD计算 */ public JudgeResult robustJudge(String standard, String student, int fullScore, String requiredLang) { // 1. 语言校验检查学生代码是否含指定语言关键字防交错语言 if (!isLanguageMatch(student, requiredLang)) { return new JudgeResult(999, 0.0, 0.0); // 强制0分 } // 2. 结构校验检查是否包含必要结构如Java题必须有public class if (!hasRequiredStructure(student, requiredLang)) { return new JudgeResult(500, 0.0, fullScore * 0.3); // 扣70%留30%结构分 } // 3. 注释剥离提取非注释代码防答案藏在//或/* */里 String cleanStudent extractCodeWithoutComment(student, requiredLang); return judgeCode(standard, cleanStudent, fullScore); } private boolean isLanguageMatch(String code, String lang) { if (java.equalsIgnoreCase(lang)) { return code.contains(public class) || code.contains(public static void main); } else if (python.equalsIgnoreCase(lang)) { return code.contains(def ) || code.contains(print(); } return true; } private String extractCodeWithoutComment(String code, String lang) { if (java.equalsIgnoreCase(lang)) { // 移除 // 单行注释和 /* */ 多行注释 code code.replaceAll(//.*, ); code code.replaceAll(/\\*.*?\\*/, , Pattern.DOTALL); } return code; }防御逻辑isLanguageMatch()用关键词粗筛比AST解析轻量得多extractCodeWithoutComment()确保判分基于真实代码逻辑robustJudge()返回distance999这种明显异常值方便后续日志标记“语言错误”答辩时可演示“这个学生交了Python系统直接判0分并记录原因”。5. 避坑指南SSMJSP在线考试系统开发中踩过的7个血泪坑5.1 现象JSP页面中文显示为“???”但数据库里存的是正确的原因IDEA项目编码、Tomcat服务器编码、MySQL连接URL编码、JSP页面pageEncoding四者不一致。常见组合错误是IDEA设UTF-8web.xml里过滤器没开forceEncodingtrueMySQL URL漏了characterEncodingutf8mb4。解决四步锁死——① IDEAFile→Settings→Editor→File Encodings全设UTF-8②web.xml中CharacterEncodingFilter的forceEncodingtrue必须为true③ MySQL连接URL加?characterEncodingutf8mb4serverTimezoneAsia/Shanghai④ JSP顶部声明% page pageEncodingUTF-8 contentTypetext/html;charsetUTF-8 %。缺一不可。5.2 现象c:forEach遍历List在JSP里不显示任何内容控制台也无报错原因jstl-1.2.jar没放对位置或web.xml版本号低于3.0导致EL表达式被禁用。解决① 确认jstl-1.2.jar在webapp/WEB-INF/lib/下不是lib或Maven依赖②web.xml头必须是version4.0不是2.5或3.0③ JSP中加% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %④ 若仍无效在web.xml中加jsp-configel-ignoredfalse/el-ignored/jsp-config。5.3 现象LD算法判分耗时超5秒学生提交后页面转圈不动原因未对长代码做长度截断学生交了1000行代码LD算法时间复杂度O(mn)直接爆炸。解决在judgeCode()前加长度限制——if (standard.length() 2000 || student.length() 2000) { return new JudgeResult(999, 0.0, 0.0); }。毕设题目代码一般500字符2000是安全上限同时在JSP前端用JavaScript限制textarea最大长度textarea maxlength2000。5.4 现象MySQL插入中文报错Incorrect string value: \xF0\x9F\x98\x8A原因数据库、表、字段三级字符集未全部设为utf8mb4只设了库或表。解决执行ALTER DATABASE online_exam CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;然后对每张表执行ALTER TABLE exam CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;最后对每个TEXT/VARCHAR字段执行ALTER TABLE exam MODIFY COLUMN content TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。用SHOW CREATE TABLE exam;逐级确认。5.5 现象Tomcat启动报java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet原因spring-webmvc.jar没放进WEB-INF/lib/或IDEA没把lib目录标记为“Libraries”。解决① 手动将spring-webmvc-5.3.39.jar等所有jar拖入webapp/WEB-INF/lib/② 在IDEA中右键lib文件夹→Add as Library③Project Structure→Artifacts→Output Layout中确认WEB-INF/lib/下有这些jar④ 清理Tomcat工作目录rm -rf tomcat/work/Catalina/localhost/*。5.6 现象学生登录成功后session.getAttribute(student)在其他页面取不到原因web.xml中session-config未配置cookie-http-onlytrue/cookie-http-only或JSP中用了% session.invalidate(); %误销毁。解决① 在web.xml中添加session-configsession-timeout30/session-timeoutcookie-http-onlytrue/cookie-http-only/session-config② 登录成功后用request.getSession().setAttribute(student, student)不要用new Session()③ 检查所有JSP是否误写session.invalidate()——毕设中只需登录时setAttribute退出时removeAttribute即可。5.7 现象LD算法对int a1;和int a 1 ;判为distance3空格差异但实际应视为相同原因normalizeCode()未彻底处理空格或学生代码含制表符\t。解决升级normalizeCode()方法增加制表符替换和连续空白符压缩private String normalizeCode(String code) { if (code null) return ; code code.replace(\r\n, \n).replace(\r, \n).replace(\t, ); // \t→空格 String[] lines code.split(\n); StringBuilder sb new StringBuilder(); for (String line : lines) { line line.trim().replaceAll(\\s, ); // \s匹配所有空白符 if (!line.isEmpty()) sb.append(line).append(\n); } return sb.toString().trim(); }6. 答辩加分技巧用3个可演示细节让老师眼前一亮6.1 细节一在judge_log表里埋一个“人工复核开关”答辩时老师最爱问“LD算法万一判错了怎么办”。别只会说“我们人工复核”要拿出可操作的方案。在submission表加一列need_review TINYINT DEFAULT 0并在判分服务里加规则// 当相似度在0.75~0.85之间时标记需人工复核 if (similarity 0.75 similarity 0.85) { submission.setNeedReview((byte) 1); submission.setScore(fullScore * 0.5); // 先给50%等老师复核 }然后在后台管理页admin/review.jsp用c:if test${s.needReview 1}高亮显示待复核记录并提供“通过/驳回”按钮。演示时点开一条need_review1的记录点击“通过”分数立刻从5.0变成10.0——这比说一百遍“支持人工干预”都有力。6.2 细节二用Druid监控页实时展示SQL慢查询毕设常被质疑“性能怎么样”。与其口头说“很快”不如打开http://localhost:8080/druid/sql.html。提前准备一个场景在QuestionMapper.xml里故意写一个没索引的查询!-- 慢查询示例答辩时演示优化过程 -- select idfindQuestionsByExamId resultTypeQuestion SELECT * FROM question WHERE exam_id #{examId} AND type 3 !-- 编程题 -- /select执行几次后Druid页会显示该SQL平均耗时100ms。然后你当场加索引ALTER TABLE question ADD INDEX idx_exam_type (exam_id, type);刷新Druid页耗时降到5ms以下。这个“发现问题→加索引→效果立现”的闭环是答辩时最硬核的性能证明。6.3 细节三导出一份“判分报告PDF”含LD算法可视化对比学生总想知道自己哪错了。用iText 5.5.13生成PDF报告轻量不需Spring Boot在JudgeService里加方法public void generateJudgeReport(int submissionId, HttpServletResponse response) throws Exception { Submission sub submissionMapper.selectById(submissionId); Question q questionMapper.selectById(sub.getQuestionId()); Document document new Document(); PdfWriter.getInstance(document, response.getOutputStream()); document.open(); Font titleFont FontFactory.getFont(FontFactory.HELVETICA_BOLD, 16); document.add(new Paragraph(编程题判分报告, titleFont)); // 标准答案 vs 学生答案用不同背景色区分 PdfPTable table new PdfPTable(2); table.addCell(new PdfPCell(new Phrase(标准答案)) {.setBackgroundColor(BaseColor.LIGHT_GRAY)}); table.addCell(new PdfPCell(new Phrase(学生答案)) {.setBackgroundColor(BaseColor.YELLOW)}); table.addCell(new PdfPCell(new Phrase(q.getAnswer()))); table.addCell(new PdfPCell(new Phrase(sub.getAnswer()))); document.add(table); // LD结果 JudgeResult result judgeCode(q.getAnswer(), sub.getAnswer(), q.getScore()); document.add(new Paragraph(编辑距离 result.distance)); document.add(new Paragraph(相似度 String.format(%.2f%%, result.similarity * 100))); document.add(new Paragraph(得分 result.score / q.getScore())); document.close(); }在JSP里加一个按钮a hrefjudge/report.do?id${s.id}下载判分报告/a。答辩时点开PDF弹出老师看到黄底学生代码和灰底标准答案并排立刻理解判分逻辑——这比任何PPT都直观。我带的学生里凡是在答辩前一周把这三个细节做完的没有一个被问倒。不是因为技术多深而是把“老师关心什么”和“系统能展示什么”严丝合缝地对上了。希望帮到你。本文还有配套的精品资源点击获取
返回列表