简介这是一套基于JavaWeb的作业提交与批改系统项目源码面向计算机相关专业正在做毕设的学生以及需要项目实战练习的Java学习者可直接作为毕业设计使用。系统采用B/S结构后台基于JSP、Servlet与JDBC实现以MySQL作为数据库开发环境为JDK、Eclipse与Tomcat并划分管理员、教师、学生三种角色。功能上覆盖班级、教师、学生、公告、留言、资料及系统管理七大模块支持信息的录入、查询、删除与打印等操作界面美观、操作简单具备较高的实际应用价值。资源包共3个文件包含项目源码压缩包、数据库脚本sql文件以及项目说明txt文档整体约4.51MB源码与脚本均已严格调试可正常运行。目前已有3583人学习下载适合希望快速搭建作业管理类系统、理解JavaWeb分层开发与数据库设计的读者参考使用。1. 从一份“能跑起来”的作业提交与批改系统说起很多同学做毕设时选题定成“基于JavaWeb的作业提交与批改系统”第一反应是去搜“javaweb项目完整案例mysql”然后复制一份代码改改界面就交差。但真正答辩时被问到“学生提交的作业文件怎么存”“教师批改状态怎么流转”“数据库脚本为什么这样设计”往往答不上来。这个标题背后其实是一套完整的业务闭环学生上传作业、系统记录提交状态、教师下载批阅、回填分数与评语、学生查看结果。它适合计算机毕设选题中偏管理信息系统方向的同学也适合想用SpringBootVue毕设练手全栈开发的人。核心难点不在页面多漂亮而在文件存储策略、状态机设计和数据库表关系是否经得起追问。下面按理论选型、库表设计、后端实现、前端联调、部署排错的顺序把一套可复现的方案讲清楚。2. 作业提交与批改系统的技术选型与数据库脚本设计2.1 为什么用 Spring Boot MyBatis-Plus 而不是纯 Servlet标题写的是 JavaWeb但 2024 年之后的毕设如果还用 JSP Servlet 裸写代码量会膨胀到难以维护。常见做法是保留 JavaWeb 的 MVC 分层思想用 Spring Boot 做容器和自动配置MyBatis-Plus 做数据访问。这样既符合“JavaWeb”的范畴又能让答辩老师看到你对主流框架的掌握。选型理由有三点第一Spring Boot 内嵌 Tomcatidea运行javaweb项目配置时不需要单独装 Tomcat第二MyBatis-Plus 的BaseMapper能省掉大量单表 CRUD第三前后端分离后 Vue 负责交互Java 端只返回 JSON职责清晰。依赖版本建议锁定 Spring Boot 2.7.x 和 MyBatis-Plus 3.5.xJDK 用 8 或 11MySQL 用 5.7 或 8.0。不要盲目追 Spring Boot 3.x因为部分毕设环境里的 JDK 还是 8贸然升级会导致javax包名变成jakarta启动直接报错。2.2 数据库脚本的核心表与字段说明数据库脚本是毕设查重和答辩的重点。作业提交与批改系统至少需要五张表用户表、课程表、作业表、提交记录表、批改记录表。下面给出建表脚本的关键部分可直接在 MySQL 中执行。-- 用户表区分学生、教师、管理员 CREATE TABLE sys_user ( id BIGINT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT BCrypt加密, real_name VARCHAR(50) DEFAULT NULL, role TINYINT NOT NULL COMMENT 1学生 2教师 3管理员, class_id BIGINT DEFAULT NULL COMMENT 学生所属班级, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 作业表教师发布的作业任务 CREATE TABLE homework ( id BIGINT NOT NULL AUTO_INCREMENT, course_id BIGINT NOT NULL, title VARCHAR(200) NOT NULL, content TEXT, deadline DATETIME NOT NULL COMMENT 截止时间, create_by BIGINT NOT NULL COMMENT 教师ID, status TINYINT DEFAULT 1 COMMENT 1进行中 0已截止, PRIMARY KEY (id), KEY idx_course (course_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 提交记录表一个学生一份作业只有一条有效记录 CREATE TABLE submission ( id BIGINT NOT NULL AUTO_INCREMENT, homework_id BIGINT NOT NULL, student_id BIGINT NOT NULL, file_path VARCHAR(255) DEFAULT NULL COMMENT 相对存储路径, file_name VARCHAR(255) DEFAULT NULL, submit_time DATETIME DEFAULT CURRENT_TIMESTAMP, status TINYINT DEFAULT 0 COMMENT 0未批改 1已批改, score DECIMAL(5,1) DEFAULT NULL, comment VARCHAR(500) DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_hw_stu (homework_id,student_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;uk_hw_stu唯一索引是关键它保证同一个学生对同一份作业只能提交一次后续再交就是更新操作。file_path存相对路径而不是绝对路径方便迁移服务器。status字段驱动整个批改流程教师端查询时只查status0的记录。2.3 文件存储路径与上传大小限制作业文件不能存进数据库 BLOB否则备份和查询都会变慢。常见做法是在application.yml里配置本地磁盘目录并用日期分目录避免单目录文件过多。spring: servlet: multipart: max-file-size: 20MB max-request-size: 20MB file: upload-dir: /data/homework/upload/ allowed-ext: pdf,doc,docx,zip,rarmax-file-size限制单文件 20MB超过会抛MaxUploadSizeExceededException需要在全局异常处理器里捕获并返回友好提示。allowed-ext做后缀白名单防止上传可执行文件。存储时用homeworkId/studentId_时间戳.后缀命名既避免重名又便于追溯。3. 后端接口实现提交、批改与状态流转3.1 学生提交作业的接口与文件落盘逻辑学生提交作业的接口需要同时处理文件流和表单字段。用MultipartFile接收文件先校验作业是否已截止再判断是新增还是更新提交记录。PostMapping(/submit) public Result submit(RequestParam Long homeworkId, RequestParam(file) MultipartFile file, HttpServletRequest request) { Long studentId getCurrentUserId(request); Homework hw homeworkMapper.selectById(homeworkId); // 截止时间校验 if (hw.getDeadline().before(new Date())) { return Result.fail(已过截止时间无法提交); } // 后缀白名单 String ext FileUtil.getSuffix(file.getOriginalFilename()); if (!allowedExt.contains(ext)) { return Result.fail(不支持的文件类型); } // 按作业ID分目录存储 String dir uploadDir homeworkId /; String storeName studentId _ System.currentTimeMillis() . ext; File dest new File(dir storeName); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } try { file.transferTo(dest); } catch (IOException e) { return Result.fail(文件保存失败); } // 存在则更新不存在则插入 Submission sub submissionMapper.selectOne( new LambdaQueryWrapperSubmission() .eq(Submission::getHomeworkId, homeworkId) .eq(Submission::getStudentId, studentId)); if (sub null) { sub new Submission(); sub.setHomeworkId(homeworkId); sub.setStudentId(studentId); sub.setFilePath(homeworkId / storeName); sub.setFileName(file.getOriginalFilename()); sub.setStatus(0); submissionMapper.insert(sub); } else { sub.setFilePath(homeworkId / storeName); sub.setFileName(file.getOriginalFilename()); sub.setSubmitTime(new Date()); sub.setStatus(0); // 重新提交后回到未批改 submissionMapper.updateById(sub); } return Result.ok(提交成功); }逻辑说明先查作业是否存在、是否截止再校验后缀然后落盘。落盘目录按homeworkId分文件夹文件名用studentId_时间戳保证唯一。数据库层面用selectOne判断是否已有记录有则更新无则插入。注意重新提交后要把status重置为 0否则教师端看不到新版本。参数homeworkId和file是必传的file为空时 Spring 会直接返回 400前端需要做非空校验。3.2 教师批改接口与分数回填教师批改时传入提交记录 ID、分数和评语后端更新submission表并置status1。PostMapping(/grade) public Result grade(RequestBody GradeDTO dto) { Submission sub submissionMapper.selectById(dto.getSubmissionId()); if (sub null) { return Result.fail(提交记录不存在); } if (dto.getScore() null || dto.getScore() 0 || dto.getScore() 100) { return Result.fail(分数需在0到100之间); } sub.setScore(dto.getScore()); sub.setComment(dto.getComment()); sub.setStatus(1); submissionMapper.updateById(sub); return Result.ok(批改完成); }GradeDTO包含submissionId、score、comment三个字段。分数用BigDecimal或Double接收数据库字段是DECIMAL(5,1)支持一位小数。批改后学生端查询时根据status显示“已批改”并展示分数和评语。这里不要用物理删除保留历史记录便于申诉。3.3 分页查询与多条件筛选教师端需要按课程、作业、状态筛选提交记录学生端需要查看自己的提交历史。用 MyBatis-Plus 的分页插件实现。GetMapping(/page) public Result page(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, Long homeworkId, Integer status) { PageSubmissionVO p new Page(page, size); LambdaQueryWrapperSubmission wrapper new LambdaQueryWrapper(); wrapper.eq(homeworkId ! null, Submission::getHomeworkId, homeworkId) .eq(status ! null, Submission::getStatus, status) .orderByDesc(Submission::getSubmitTime); return Result.ok(submissionMapper.selectPage(p, wrapper)); }page和size控制分页homeworkId和status为可选筛选条件。eq的第一个参数是布尔值条件为真时才拼接 SQL这是 MyBatis-Plus 的条件构造技巧。排序按提交时间倒序最新提交的排前面。返回的SubmissionVO需要关联查询学生姓名和作业标题可以用Select自定义 SQL 或 XML 映射。4. 前端联调与部署排错从 IDEA 到可访问4.1 Vue 端上传组件与请求封装前端用 Vue Element Plus 的el-upload组件设置:http-request自定义上传避免默认行为不受控。// 自定义上传携带 token 和 homeworkId const handleUpload async (options) { const formData new FormData(); formData.append(file, options.file); formData.append(homeworkId, currentHomeworkId.value); try { const res await axios.post(/api/submission/submit, formData, { headers: { Content-Type: multipart/form-data } }); if (res.data.code 200) { ElMessage.success(提交成功); loadList(); } else { ElMessage.error(res.data.msg); } } catch (e) { ElMessage.error(网络异常); } };FormData自动设置multipart/form-data边界不要手动设置Content-Type否则边界丢失会导致后端解析失败。homeworkId从当前作业详情页传入。上传成功后刷新列表让状态实时更新。4.2 IDEA 运行 JavaWeb 项目的常见配置坑在 IDEA 中运行 Spring Boot 项目时常见问题有三个。第一端口被占用改server.port即可第二数据库连接失败检查application.yml中的url是否加了useSSLfalseserverTimezoneAsia/Shanghai第三文件上传目录没有写权限Linux 下用chmod 755授权。如果启动报Table xxx doesnt exist说明数据库脚本没执行完整用idea导出数据库脚本功能反向核对表结构。提示MySQL 8.0 的驱动类名是com.mysql.cj.jdbc.Driver5.7 是com.mysql.jdbc.Driver写错会报ClassNotFoundException。4.3 批改状态不一致的排查思路如果教师批改后学生端仍显示“未批改”按以下顺序排查先查数据库submission表的status字段是否已更新为 1再查后端接口是否返回了最新数据最后查前端是否缓存了旧列表。常见原因是前端用了keep-alive缓存页面切换路由时没有重新请求。解决办法是在activated钩子里重新加载数据或者关闭该页面的缓存。现象可能原因处理方式上传报 413文件超过 max-file-size调大配置或前端限制批改后状态不变前端缓存或事务未提交检查Transactional和刷新逻辑文件下载 404file_path 拼接错误核对存储根路径与相对路径登录后接口 401token 未携带检查 axios 拦截器5. 进阶技巧用状态机与软删除让系统更经得起答辩5.1 把 status 字段升级为显式状态机很多毕设的status只有 0 和 1答辩时被问“如果学生迟交怎么办”“如果教师打回重做怎么办”就卡住了。进阶做法是定义状态枚举0 未提交、1 已提交待批改、2 已批改、3 打回重做、4 迟交。状态流转用服务层方法控制禁止前端直接改status。public enum SubmitStatus { NOT_SUBMITTED(0), SUBMITTED(1), GRADED(2), RETURNED(3), LATE(4); private final int code; SubmitStatus(int code) { this.code code; } public int getCode() { return code; } }在提交接口里判断当前时间是否超过deadline超过则置为LATE教师端可以单独筛选迟交记录。打回重做时把状态改为 3学生端显示“需重新提交”再次提交后回到 1。这样状态流转清晰答辩时能画出完整的状态图。5.2 软删除与数据恢复批改记录和提交记录不建议物理删除。在表里加deleted字段MyBatis-Plus 用TableLogic注解自动处理。TableLogic private Integer deleted;配置后deleteById实际执行UPDATE ... SET deleted1查询时自动追加deleted0。这样误删后还能从数据库恢复也符合毕设对数据完整性的要求。注意唯一索引uk_hw_stu在软删除下会冲突需要把deleted加入唯一索引或者用时间戳标记删除。5.3 用接口文档工具提升联调效率前后端分离后接口字段对不齐是最大时间黑洞。建议引入 Knife4j 或 Swagger在 Controller 上加注解自动生成文档。ApiOperation(学生提交作业) PostMapping(/submit) public Result submit(ApiParam(作业ID) RequestParam Long homeworkId, ApiParam(作业文件) RequestParam MultipartFile file) { ... }启动后访问/doc.html即可看到所有接口和参数说明前端不用反复问后端字段名。导出接口文档 PDF 附在毕设论文附录里也是加分项。最后提醒一点数据库脚本要随源码一起提交并在 README 里写清楚执行顺序和初始账号否则答辩现场跑不起来前面做得再好也会大打折扣。本文还有配套的精品资源点击获取