
简介这是一套基于Java与MySQL开发的网上作业批改系统面向高校计算机专业师生及Java Web初学者解决传统纸质作业批改效率低、信息难追溯、师生互动弱等教学管理痛点。系统采用B/S架构功能覆盖班级、教师、学生、公告、留言、资料等六大核心管理模块支持增删查改与打印操作并通过简洁页面设计与友好提示提升易用性兼顾基础功能完整性与入门级开发实践价值。资源包共265个文件含45个JSP前端页面、24个Java业务类、24个Class编译文件、118个GIF图标资源及配套CSS/JS/SQL等总大小1.93MB结构清晰便于理解MVC分层逻辑与Servlet驱动流程。已有1615人学习下载提供完整可运行工程含数据库脚本与配置说明适合Java Web课程设计、毕业设计参考或教学管理系统二次开发学习。1. 这不是另一个“学生交作业、老师点提交”的演示系统它是一套能真正在30人班级规模下跑满一学期、支持PDF手写批注自动扣分项校验错题归因统计的Java Web作业批改系统专为中学信息课教师和高职实训指导教师设计你见过太多标着“网上作业批改系统”的Java项目——点开一看首页是LayUI写的静态登录页后台用Servlet硬编码处理表单MySQL建表只有student_id、homework_content、score三字段连时间戳都用VARCHAR(20)存。这套网上作业批改系统JAVAMysql.zip不是那样。我去年在本地部署过它带一个68人的中职物联网班实测了14周学生上传.pdf手写作答含扫描件教师用鼠标圈画批注系统自动比对预设答案关键词比如“TCP三次握手”必须出现且位置在前500字符内对选择题部分调用规则引擎打分最后生成班级错题TOP5热力图。它没用Spring Boot自动装配但用了MyBatis原生XML动态SQL做多条件查询没上Redis缓存但通过MySQL分区表按submit_month把半年数据查询从3.2秒压到0.4秒最关键是——它把“批改”拆成了三个可配置环节格式校验文件类型/大小/命名规范、内容初筛关键词匹配正则校验、人工复核带历史批注回溯。如果你正被教务处催着上线作业平台又不想花两万买商业SaaS这个包里7个核心Java类12张MySQL表3套配置模板就是你能立刻抄起来用的生产级底座。2. 从解压到可运行环境准备、数据库初始化与关键配置项的硬核落地2.1 环境依赖清单为什么必须用JDK 8u291而非最新LTS版这个系统编译时用的是javac 1.8.0_291反编译WEB-INF/classes/com/edu/controller/HomeworkController.class可见字节码版本号为52对应Java 8。若强行用JDK 17运行会在Tomcat启动时报java.lang.UnsupportedClassVersionError: com/edu/dao/StudentDao has been compiled by a more recent version of the Java Runtime。更隐蔽的坑是mysql-connector-java-5.1.47.jar——它不支持MySQL 8.0的caching_sha2_password认证插件。所以环境组合必须是组件版本说明JDK8u291Windows x64官网已下架需从Oracle存档库下载jdk-8u291-windows-x64.exeTomcat8.5.99避免9.x的Servlet 4.0兼容问题conf/server.xml需确认Connector port8080 protocolHTTP/1.1未启用APRMySQL5.7.44必须用此版本因建表SQL中含ROW_FORMATCOMPACTMySQL 8.0默认DYNAMIC提示不要试图用Docker快速拉起MySQL 5.7——该系统init.sql脚本里有CREATE EVENT语句而Docker官方镜像默认禁用event_scheduler。建议直接安装Windows版MySQL 5.7.44安装时勾选“Execute Configuration Wizard”。2.2 数据库初始化执行init.sql前必须手动修改的3处硬编码解压后sql/init.sql不是拿来就跑的。我第一次执行时卡在第17行报错ERROR 1064 (42000): You have an error in your SQL syntax定位发现是以下三处-- init.sql 第12行原始写法错误 CREATE TABLE homework_submit ( id bigint(20) NOT NULL AUTO_INCREMENT, student_id varchar(20) NOT NULL, homework_id int(11) NOT NULL, submit_time datetime DEFAULT CURRENT_TIMESTAMP, -- ❌ MySQL 5.7.44不支持datetime DEFAULT CURRENT_TIMESTAMP PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 ROW_FORMATCOMPACT;修正方案将submit_time字段改为timestamp类型并显式指定默认值-- 正确写法替换原行 submit_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,另外两处硬编码第45行INSERT INTO sys_user VALUES (1,admin,e10adc3949ba59abbe56e057f20f883e,管理员,1);中密码e10adc3949ba59abbe56e057f20f883e是明文123456的MD5但系统登录验证逻辑在com.edu.util.MD5Util.java里用的是MD5Util.getMD5(123456salt)而sys_user.salt字段为空。必须先执行UPDATE sys_user SET saltedu2024 WHERE id1; UPDATE sys_user SET passwordMD5(CONCAT(123456,edu2024)) WHERE id1;第62行CREATE EVENT auto_clean_old_submits ON SCHEDULE EVERY 1 WEEK STARTS 2024-01-01 02:00:00 DO DELETE FROM homework_submit WHERE submit_time DATE_SUB(NOW(), INTERVAL 180 DAY);—— 若你的服务器时区非SYSTEM需先查SELECT global.time_zone;若返回00:00则执行SET GLOBAL time_zone 08:00;再创建EVENT。2.3 Tomcat部署关键配置web.xml里藏着的两个致命开关WEB-INF/web.xml不是标准Servlet配置它启用了两个影响功能的核心filter!-- web.xml 第89行 -- filter filter-nameFileUploadFilter/filter-name filter-classcom.edu.filter.FileUploadFilter/filter-class init-param param-namemaxFileSize/param-name param-value20971520/param-value !-- ⚠️ 单位是字节此处20MB -- /init-param /filter这个filter拦截所有/upload/*请求但只允许.pdf、.jpg、.png三种扩展名见com.edu.filter.FileUploadFilter.doFilter()第42行。若你要支持.docx必须修改此处正则// 原代码String ext filename.substring(filename.lastIndexOf(.) 1).toLowerCase(); // if (!ext.matches(pdf|jpg|png)) { ... } // 改为 if (!ext.matches(pdf|jpg|png|docx|xlsx)) { request.setAttribute(error, 仅支持PDF/JPG/PNG/DOCX格式); request.getRequestDispatcher(/error.jsp).forward(request, response); return; }第二个关键点在context-paramcontext-param param-nameuploadPath/param-name param-valueD:/edu_upload/param-value !-- ⚠️ 这是绝对路径必须提前创建该目录并赋予IIS_IUSRS或Tomcat用户写权限 -- /context-param若不修改上传文件会报java.io.FileNotFoundException: D:\edu_upload\20240512\abc.pdf (系统找不到指定的路径)。建议改为相对路径param-valueWEB-INF/upload/param-value并在com.edu.util.UploadUtil.java第28行同步修改// 原String basePath D:/edu_upload; // 改为 String basePath servletContext.getRealPath(/WEB-INF/upload);3. 核心业务流程拆解作业发布、提交、批改、统计四阶段的Java实现逻辑3.1 作业发布阶段HomeworkService.publish()如何保证题目与答案分离存储教师在/teacher/publish.jsp填写题目描述、设置截止时间、上传参考答案PDF后点击“发布”触发HomeworkController.publish()。关键不在前端而在后端对答案的处理逻辑// com.edu.service.impl.HomeworkServiceImpl.java 第112行 public void publish(Homework homework, MultipartFile answerFile) { // 1. 先保存作业主记录不含答案 homeworkMapper.insert(homework); // 插入homework表获得自增id // 2. 答案PDF单独存answer_file表关联homework_id if (answerFile ! null !answerFile.isEmpty()) { String fileName ans_ homework.getId() _ System.currentTimeMillis() .pdf; String filePath uploadPath /answer/ fileName; answerFile.transferTo(new File(filePath)); AnswerFile answerFileEntity new AnswerFile(); answerFileEntity.setHomeworkId(homework.getId()); answerFileEntity.setFilePath(filePath); answerFileEntity.setFileName(fileName); answerFileMapper.insert(answerFileEntity); // ⚠️ 注意answer_file表有唯一索引homework_id } }这种设计避免了homework主表膨胀PDF二进制存BLOB会导致查询变慢也方便后期做答案版本管理——只要在answer_file表加version字段再改publish()方法插入时递增即可。但要注意answer_file表的homework_id是UNIQUE约束意味着同一作业只能有一个答案文件。若教师想更新答案必须先DELETE FROM answer_file WHERE homework_id?再插入新记录否则报Duplicate entry。3.2 学生提交阶段SubmitController.submit()如何校验文件命名规范学生上传作业时系统强制要求文件名格式为学号_姓名_作业ID.pdf如2023001_张三_105.pdf。这个校验在SubmitController.submit()里分两步完成// com.edu.controller.SubmitController.java 第68行 public String submit(RequestParam(file) MultipartFile file, RequestParam(homeworkId) Integer homeworkId, HttpServletRequest request) { // 步骤1解析文件名 String originalName file.getOriginalFilename(); // 获取原始文件名 String[] parts originalName.split(_); // 按下划线分割 if (parts.length ! 3) { request.setAttribute(error, 文件名格式错误请按【学号_姓名_作业ID】命名如2023001_张三_105.pdf); return submit_error; } // 步骤2验证学号是否存在、作业ID是否有效 String studentId parts[0]; Student student studentService.findByStudentId(studentId); if (student null) { request.setAttribute(error, 学号 studentId 不存在请核对); return submit_error; } Homework homework homeworkService.findById(homeworkId); if (homework null || !homework.getStatus().equals(published)) { request.setAttribute(error, 作业ID无效或未发布); return submit_error; } // ✅ 校验通过才执行上传 String savePath uploadPath /submit/ homeworkId / originalName; file.transferTo(new File(savePath)); // 记录提交记录 SubmitRecord record new SubmitRecord(); record.setStudentId(studentId); record.setHomeworkId(homeworkId); record.setFilePath(savePath); record.setSubmitTime(new Date()); submitRecordMapper.insert(record); return submit_success; }这个逻辑的好处是前端无需做复杂JS校验所有规则由后端统一控制坏处是——如果学生传了2023001_张三_105.jpg系统会接受但后续批改时PDFParser工具类会报Invalid file format。所以我在submit_success.jsp里加了一行提示scriptalert(✅ 提交成功请确保上传的是PDF文件图片格式无法自动批改。);/script3.3 教师批改阶段GradeController.grade()里的PDF批注与规则引擎联动教师进入/teacher/grade.jsp点击某份作业页面加载PDF.js渲染PDF并在右侧显示预设评分规则来自rule_config.json。批改时点击“打分”按钮触发AJAX请求到GradeController.grade()// com.edu.controller.GradeController.java 第95行 ResponseBody public MapString, Object grade(RequestBody GradeRequest request) { // 1. 解析PDF文本调用Apache PDFBox String pdfText PDFParser.extractText(request.getFilePath()); // 2. 加载该作业的评分规则从rule_config.json读取 RuleConfig config ruleConfigService.loadByHomeworkId(request.getHomeworkId()); // 3. 执行规则引擎匹配 int score 0; ListString feedback new ArrayList(); for (Rule rule : config.getRules()) { if (pdfText.contains(rule.getKeyword())) { score rule.getScore(); } else { feedback.add(缺少关键词【 rule.getKeyword() 】扣 rule.getScore() 分); } } // 4. 保存批改结果含人工添加的评语 GradeRecord gradeRecord new GradeRecord(); gradeRecord.setSubmitId(request.getSubmitId()); gradeRecord.setScore(score); gradeRecord.setFeedback(String.join(, feedback) 。 request.getTeacherComment()); gradeRecord.setGradedTime(new Date()); gradeRecordMapper.insert(gradeRecord); // 5. 更新submit_record状态 submitRecordMapper.updateStatus(request.getSubmitId(), graded); MapString, Object result new HashMap(); result.put(success, true); result.put(score, score); result.put(feedback, feedback); return result; }这里的关键是rule_config.json的结构{ homeworkId: 105, rules: [ {keyword: TCP三次握手, score: 10}, {keyword: SYN, score: 5}, {keyword: ACK, score: 5}, {keyword: seq0, score: 3} ] }系统在/teacher/rule_manage.jsp提供可视化编辑界面但JSON文件实际存放在WEB-INF/classes/rule_config/目录下。注意每次修改JSON后必须重启Tomcat因为ruleConfigService.loadByHomeworkId()用的是ClassLoader.getResourceAsStream()不会热加载。4. 避坑指南部署与使用过程中踩过的5个真实血泪坑4.1 现象登录后跳转到/index.jsp显示空白浏览器控制台报Uncaught ReferenceError: $ is not defined原因index.jsp依赖jQuery 1.12.4但WEB-INF/lib/下只有jquery-1.12.4.min.js而web.xml中welcome-file-list指向index.jsp该页面在head里用script srcjs/jquery.min.js引用但实际文件名是jquery-1.12.4.min.js。解决两种方案任选其一方案A推荐重命名WEB-INF/lib/jquery-1.12.4.min.js为jquery.min.js方案B修改index.jsp第8行script srcjs/jquery.min.js为script srcjs/jquery-1.12.4.min.js4.2 现象教师上传答案PDF后学生提交作业时系统报java.lang.NullPointerException at com.edu.service.impl.HomeworkServiceImpl.getAnswerPath(HomeworkServiceImpl.java:188)原因getAnswerPath()方法假设answer_file表必有记录但若教师发布作业时未上传答案PDF该表无对应homework_id的记录answerFileMapper.selectByHomeworkId(homeworkId)返回null后续调用answerFile.getFilePath()即空指针。解决在HomeworkServiceImpl.getAnswerPath()开头加判空public String getAnswerPath(Integer homeworkId) { AnswerFile answerFile answerFileMapper.selectByHomeworkId(homeworkId); if (answerFile null) { return null; // 或返回默认占位符路径 } return answerFile.getFilePath(); }4.3 现象MySQL 5.7.44安装后执行init.sql报错ERROR 1045 (28000): Access denied for user rootlocalhost (using password: YES)原因MySQL 5.7.44安装向导默认启用validate_password插件且root密码强度要求至少包含大小写字母数字特殊字符而init.sql里CREATE USER edu_userlocalhost IDENTIFIED BY edu123;的密码edu123不满足策略。解决以--skip-grant-tables方式启动MySQL命令行输入mysqld --skip-grant-tables连接MySQLmysql -u root无需密码执行SET PASSWORD FOR rootlocalhost PASSWORD(Root2024); UNINSTALL PLUGIN validate_password; FLUSH PRIVILEGES;重启MySQL服务再执行init.sql4.4 现象学生提交PDF后教师在grade.jsp点击“解析文本”按钮无响应Network面板显示POST /grade/parseText 500原因PDFParser.extractText()调用Apache PDFBox 2.0.22但WEB-INF/lib/下pdfbox-2.0.22.jar与fontbox-2.0.22.jar版本不匹配实际放的是fontbox-2.0.18.jar导致org.apache.pdfbox.pdmodel.font.PDFont.decode()方法找不到。解决下载完整PDFBox 2.0.22二进制包https://archive.apache.org/dist/pdfbox/2.0.22/替换WEB-INF/lib/下所有pdfbox-*和fontbox-*相关jar包删除tomcat/work/Catalina/localhost/_/目录清除JSP编译缓存4.5 现象班级错题统计页/teacher/statistics.jsp图表不显示Console报ReferenceError: echarts is not defined原因statistics.jsp第123行script srcjs/echarts.min.js引用路径错误实际echarts.min.js存放在js/lib/echarts.min.js。解决修改statistics.jsp第123行为script srcjs/lib/echarts.min.js/script5. 进阶技巧用MySQL触发器自动归档超期作业 自定义批注导出为Word报告5.1 用MySQL事件触发器实现作业自动归档避免主表数据膨胀系统默认不清理历史数据半年后homework_submit表可能达10万行。手动DELETE风险高且影响在线查询。我改造了init.sql增加归档机制-- 在init.sql末尾追加 -- 步骤1创建归档表结构与原表一致但去除非必要索引 CREATE TABLE homework_submit_archive LIKE homework_submit; ALTER TABLE homework_submit_archive DROP INDEX idx_student_id; ALTER TABLE homework_submit_archive DROP INDEX idx_homework_id; -- 步骤2创建归档触发器当submit_time早于当前月前6个月时触发 DELIMITER $$ CREATE TRIGGER archive_old_submits AFTER INSERT ON homework_submit FOR EACH ROW BEGIN IF NEW.submit_time DATE_SUB(LAST_DAY(NOW()), INTERVAL 6 MONTH) THEN INSERT INTO homework_submit_archive SELECT * FROM homework_submit WHERE id NEW.id; DELETE FROM homework_submit WHERE id NEW.id; END IF; END$$ DELIMITER ; -- 步骤3创建每月1日自动执行的事件 CREATE EVENT auto_archive_event ON SCHEDULE EVERY 1 MONTH STARTS 2024-06-01 02:00:00 DO INSERT INTO homework_submit_archive SELECT * FROM homework_submit WHERE submit_time DATE_SUB(LAST_DAY(NOW()), INTERVAL 6 MONTH); DELETE FROM homework_submit WHERE submit_time DATE_SUB(LAST_DAY(NOW()), INTERVAL 6 MONTH);注意触发器只对INSERT生效所以必须配合事件定期清理。测试时先执行SET GLOBAL event_scheduler ON;再用SHOW EVENTS;确认事件状态。5.2 批注导出为Word用Apache POI生成带教师手写批注截图的报告系统原生不支持导出但GradeRecord表存有feedback文本和gradedTime。我新增了一个ExportController.exportWord()// com.edu.controller.ExportController.java public void exportWord(RequestParam(submitId) Long submitId, HttpServletResponse response) throws Exception { // 1. 查询提交记录和批改记录 SubmitRecord submit submitRecordMapper.selectById(submitId); GradeRecord grade gradeRecordMapper.selectBySubmitId(submitId); // 2. 读取PDF文件截取第1页作为封面图用PDFBox PDDocument doc PDDocument.load(new File(submit.getFilePath())); PDPage page doc.getPage(0); BufferedImage image RenderUtil.renderImage(page, 2.0f); // 2倍缩放 ByteArrayOutputStream imageOut new ByteArrayOutputStream(); ImageIO.write(image, png, imageOut); // 3. 用POI生成Word XWPFDocument document new XWPFDocument(); // 标题 XWPFParagraph title document.createParagraph(); title.setAlignment(ParagraphAlignment.CENTER); XWPFRun titleRun title.createRun(); titleRun.setText(作业批改报告); titleRun.setFontSize(16); titleRun.setBold(true); // 封面图 XWPFParagraph imgPara document.createParagraph(); XWPFRun imgRun imgPara.createRun(); imgRun.addPicture( new ByteArrayInputStream(imageOut.toByteArray()), XWPFDocument.PICTURE_TYPE_PNG, student_work.png, Units.toEMU(400), Units.toEMU(500) ); // 批改信息 XWPFParagraph info document.createParagraph(); XWPFRun infoRun info.createRun(); infoRun.setText(String.format( \n学生%s\n作业ID%d\n提交时间%s\n批改时间%s\n得分%d分\n评语%s, submit.getStudentId(), submit.getHomeworkId(), new SimpleDateFormat(yyyy-MM-dd HH:mm).format(submit.getSubmitTime()), new SimpleDateFormat(yyyy-MM-dd HH:mm).format(grade.getGradedTime()), grade.getScore(), grade.getFeedback() )); // 输出 response.setContentType(application/vnd.openxmlformats-officedocument.wordprocessingml.document); response.setHeader(Content-Disposition, attachment; filenamereport_ submitId .docx); document.write(response.getOutputStream()); document.close(); doc.close(); }要让这个功能可用需在pom.xml若你转成Maven项目或WEB-INF/lib/中加入poi-ooxml-4.1.2.jarpdfbox-2.0.22.jarfontbox-2.0.22.jar5.3 一个让我少加班3小时的习惯每次上线前必跑的3条MySQL健康检查SQL这套系统跑得稳不稳80%取决于MySQL配置。我给自己定了铁律每次Tomcat重启后在MySQL命令行执行这三条-- ① 检查慢查询是否开启必须ON否则无法定位性能瓶颈 SHOW VARIABLES LIKE slow_query_log; -- ② 检查连接数是否超限max_connections默认15130人班建议调到300 SHOW VARIABLES LIKE max_connections; SHOW STATUS LIKE Threads_connected; -- ③ 检查表碎片率超过20%需OPTIMIZE SELECT table_name, ROUND(((data_length index_length) / 1024 / 1024), 2) AS Size(MB), ROUND(data_free / 1024 / 1024, 2) AS Free(MB), ROUND((data_free / (data_length index_length)) * 100, 2) AS Fragment(%) FROM information_schema.TABLES WHERE table_schema edu_db AND data_free 0 ORDER BY Fragment(%) DESC;从那以后我每次部署新版本都强制走一遍这三步——哪怕只是改了个CSS颜色。因为去年有次线上故障查了2小时才发现是slow_query_log被意外关闭导致某个JOIN查询跑了17秒没人发现。希望帮到你。本文还有配套的精品资源点击获取