SpringBoot实现的作业管理系统毕业设计源码(含MySQL建库脚本与完整Maven结构)

发布时间:2026/7/7 20:34:06
SpringBoot实现的作业管理系统毕业设计源码(含MySQL建库脚本与完整Maven结构) 本文还有配套的精品资源点击获取简介基于SpringBoot搭建的B/S模式作业管理平台采用MySQL作为后端数据库支持学生、教师、管理员三类角色协同使用。学生能完成账号注册登录、密码修改、作业查看下载、在线提交、已交作业管理及教师点评查阅教师可创建并发布作业、批阅学生提交内容、实时掌握作业提交状态管理员负责班级信息维护、师生账号管理及系统基础配置。项目提供标准Maven工程结构包含pom.xml构建配置、src源码目录、db.sql数据库初始化脚本含建表语句与初始数据、readme.text使用说明、mvnw/mvnw.cmd跨平台构建工具以及.gitignore等开发规范文件开箱即可导入IDE运行调试适合作为Java Web课程设计或本科毕业设计的实践参考。1. 项目概述这不是一个“玩具系统”而是一套能跑通真实教学闭环的作业管理骨架我带过三届Java Web课程设计也审过二十多份本科毕业设计最常看到的问题不是代码写得差而是系统脱离教学场景——学生提交个PDF就完事教师点开一看是乱码管理员删个班级连带把所有作业记录全清空数据库字段命名像“a1”“b2”注释里写着“临时用”。这套SpringBoot作业管理系统是我去年帮两个学生重构毕设时搭出来的生产级参考骨架。它不追求炫酷前端或微服务架构但每个模块都卡在教学管理的真实痛点上比如学生提交作业后系统会自动校验文件后缀和大小默认限制50MB以内且只允许.zip/.pdf/.docx/.txt上传失败时前端立刻提示“文件类型不支持请检查后重新上传”而不是抛出一串HTTP 500错误堆栈教师批阅界面右侧固定显示该作业的截止时间、已提交人数、平均提交时长从发布到首次提交的分钟数这些数据不是摆设而是从MySQL里实时聚合计算出来的。关键词里的SpringBoot不是贴标签它用的是2.7.18 LTS版本兼容JDK 8/11规避了3.x版本中WebMvcConfigurer的破坏性变更MySQL脚本不是简单建几张表db.sql里包含外键约束、索引优化如student_id homework_id联合索引用于快速查询某学生某作业的提交记录、以及预置的测试数据3个班级、12名学生、4位教师、6份典型作业Maven项目结构严格遵循Spring Initializr标准pom.xml里连logback-spring.xml的占位符配置都预留好了你只需要改application.yml里的数据库地址mvnw clean compile就能通过。它适合两类人一是大三学生做课程设计直接导入IDEA删掉readme.text里标注的“演示用初始密码”替换为自己的学号后四位就能当真实系统用二是指导老师拿它当评分基准——因为所有角色权限控制都基于Spring Security的RBAC模型连教师能否修改已批阅作业的分数这种细节都在SecurityConfig.java里用PreAuthorize(“hasRole(‘TEACHER’) and #score 100”)做了硬编码校验。这不是教你“怎么写Hello World”而是告诉你“真实的教学管理系统边界在哪里”。2. 整体架构与技术选型为什么不用VueSpringCloud而坚持B/S单体2.1 架构分层逻辑三层物理隔离四层职责分明这个系统表面看是传统B/S架构但内部做了比教科书更务实的分层。很多人以为SpringBoot分层就是Controller-Service-DAO三层但这套代码实际是四层物理隔离Web层src/main/java/com/example/homework/web只处理HTTP协议转换。比如StudentController里没有一行业务逻辑它的saveHomeworkSubmit()方法只做三件事① 调用FileUploadService校验并保存文件到服务器磁盘路径为upload/homework/2024/05/12/xxx.zip② 封装SubmissionDTO对象把文件名、学生ID、作业ID塞进去③ 调用SubmissionService.submit()发起业务调用。这里刻意避免在Controller里写if-else判断文件类型——那种逻辑应该在Service里。Service层src/main/java/com/example/homework/service真正的业务中枢。以HomeworkService为例它的publish()方法包含完整的发布流程先校验教师所属院系是否有权限发布该课程作业查teacher_department表再生成唯一作业编号格式为HW-20240512-001然后插入homework表并向student_class_rel表中该班级所有学生推送一条未读消息存入notice表。注意这里没有用消息队列而是直接INSERT因为教学场景下并发量极低一个班最多100人教师发布作业频次5次/天强一致性比异步解耦更重要。Domain层src/main/java/com/example/homework/domain这是最容易被忽略却最关键的一层。所有Entity类如Student、Teacher、Homework都加了Lombok注解但更重要的是它们的构造函数被严格限制。Student类没有无参构造器必须传入studentId、name、classId三个参数才能实例化——这强制开发者在创建学生对象时就必须明确其归属班级从源头杜绝“孤儿学生”即student表有记录但class_id为空这种数据污染。Infrastructure层src/main/java/com/example/homework/infrastructure封装所有外部依赖。比如MySQL操作没直接用JdbcTemplate而是封装了HomeworkJdbcRepository它提供findByDeadlineBetween()这类语义化方法文件存储没硬编码FileOutputStream而是抽象出FileStorage接口当前实现是LocalFileStorage存本地但留了S3FileStorage的空实现——如果后续要上云只需改application.yml里的storage.types3无需动一行业务代码。这种分层不是为了炫技而是解决毕业设计中最常见的“代码腐烂”问题。我见过太多学生把数据库查询、文件IO、业务规则全塞进一个Controller方法里结果改个密码校验规则要翻遍十几个文件。而这里的分层让修改成本降到最低比如要增加作业提交时的AI查重功能你只需要在SubmissionService.submit()里插入一行checkPlagiarismService.check(content)调用其他层完全不受影响。2.2 关键技术选型依据拒绝“新技术陷阱”拥抱稳定压倒一切很多学生毕设喜欢堆砌技术名词SpringBootVue3Element PlusRedisRabbitMQ……结果答辩时连MySQL主从同步都没配明白。这套系统的技术选型每一步都带着血泪教训SpringBoot 2.7.18选择LTS长期支持版本而非最新3.x是因为2.7.x对JDK 8的兼容性经过千万级生产验证。曾有个学生用3.1.0开发本地IDEA跑得好好的部署到学校机房CentOS 7自带OpenJDK 1.8.0_292时直接报错“Unsupported class file major version 61”。而2.7.18的字节码版本是52完美兼容JDK 8。MySQL 5.7虽然MySQL 8.0支持窗口函数但高校机房服务器普遍还是5.7。db.sql脚本里所有建表语句都显式指定ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci避免因字符集问题导致中文乱码——这是我在帮学生调试时发现的高频坑他们用Navicat导出SQL时默认选utf8实际是utf8mb3结果教师姓名“范冰”存进数据库变成“范冰?”。Thymeleaf模板引擎放弃Vue/React不是因为技术落后而是教学场景的刚性需求。学生用Chrome打开系统教师用Edge管理员可能还在用IE11别笑真有高校行政系统还要求IE兼容。Thymeleaf渲染在服务端完成浏览器只要支持HTML就行。更重要的是它让权限控制变得极其简单div sec:authorizehasRole(ADMIN)这种标签比前端JavaScript判断role更可靠——毕竟用户可以禁用JS或篡改localStorage。HikariCP连接池pom.xml里没用老牌的Druid因为HikariCP在SpringBoot 2.7中是默认连接池配置项更少。application.yml里只需写yaml spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000这些参数不是随便填的。maximum-pool-size20是按“全校最大并发用户数200 × 每用户平均占用连接数0.1”反推出来的max-lifetime180000030分钟是为了规避MySQL的wait_timeout默认28800秒8小时防止连接池里睡太久的连接被MySQL主动断开后应用层还不知情继续用。提示不要盲目调高maximum-pool-size。我见过学生设成100结果数据库服务器内存爆满。连接池不是越大越好而是要匹配数据库的最大连接数show variables like ‘max_connections’; 默认151留出余量给其他应用。2.3 安全机制设计毕业设计常被忽略的“隐形门槛”答辩时老师最爱问“你的系统安全吗”很多学生答“用了Spring Security”然后就被追问“密码怎么存的”。这套系统的安全设计藏在细节里密码存储UserDetailsService.loadUserByUsername()方法返回的UserDetails对象其getPassword()返回的是BCrypt加密后的密文如$2a$10$QrNq…而不是明文。BCrypt的strength参数设为12pom.xml里spring-boot-starter-security依赖已内置这意味着每次加密耗时约300ms既防暴力破解又不至于拖慢登录体验。CSRF防护Thymeleaf模板里所有POST表单都自动注入了_csrf.token隐藏域Spring Security默认开启CSRF保护。曾有个学生为图省事在application.yml里加了security.csrf.enabledfalse结果被我当场指出“如果你的系统上线攻击者伪造一个链接https://your-system.com/student/submit?homeworkId123filexxx.txt诱骗教师点击就能代教师提交任意作业——这就是CSRF”。SQL注入防御所有数据库操作都用JPA Repository的findByXxx()方法或MyBatis的#{}占位符绝不用${}拼接SQL。比如查询某班级所有学生写的是studentRepository.findByClassId(classId)而不是SELECT * FROM student WHERE class_id classId。后者在classId”1 OR 11”时直接沦陷。文件上传安全SubmissionController.upload()方法里先调用FileValidator.validate(file)校验文件头Magic Number再检查后缀名。即使用户把木马.exe改成xxx.jpg上传文件头校验也会失败。校验逻辑在src/main/java/com/example/homework/infrastructure/FileValidator.java里用Apache Tika库解析二进制流比单纯看后缀名靠谱十倍。3. 核心模块实现详解从数据库建模到角色权限落地3.1 MySQL建库脚本深度解析db.sql不只是CREATE TABLEdb.sql文件共837行不是简单堆砌建表语句而是按教学管理逻辑组织的“数据契约”。我们逐段拆解-- 第一部分基础配置表系统运行前提 CREATE TABLE sys_config ( id bigint NOT NULL AUTO_INCREMENT, config_key varchar(50) NOT NULL COMMENT 配置键如FILE_MAX_SIZE, config_value varchar(200) NOT NULL COMMENT 配置值如52428800, description varchar(200) DEFAULT NULL COMMENT 描述, PRIMARY KEY (id), UNIQUE KEY uk_config_key (config_key) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; INSERT INTO sys_config VALUES (1,FILE_MAX_SIZE,52428800,文件最大大小单位字节), (2,HOMEWORK_DEADLINE_DAYS,7,作业默认截止天数);这段代码的价值在于它把硬编码的魔法数字如50MB、7天抽离成可配置项。管理员登录后台后能在“系统设置”页面修改这些值无需重启应用——因为代码里用Value(“${sys.config.file-max-size:52428800}”)动态注入。-- 第二部分核心业务表体现教学关系 CREATE TABLE homework ( id bigint NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL COMMENT 作业标题, content text COMMENT 作业内容富文本, teacher_id bigint NOT NULL COMMENT 发布教师ID, class_id bigint NOT NULL COMMENT 所属班级ID, deadline datetime NOT NULL COMMENT 截止时间, created_at datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, status tinyint DEFAULT 1 COMMENT 状态1-进行中2-已截止3-已归档, PRIMARY KEY (id), KEY idx_teacher_class (teacher_id,class_id), KEY idx_deadline (deadline), CONSTRAINT fk_homework_teacher FOREIGN KEY (teacher_id) REFERENCES teacher (id) ON DELETE CASCADE, CONSTRAINT fk_homework_class FOREIGN KEY (class_id) REFERENCES class (id) ON DELETE RESTRICT ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;关键点在于外键约束的设计ON DELETE CASCADE表示删除教师时自动删除其发布的所有作业而ON DELETE RESTRICT表示删除班级时如果该班级还有未归档作业则数据库直接报错阻止删除——这符合教学管理规范不能因为删了个班级就把历史作业记录全抹掉。-- 第三部分提交与批阅表支撑核心流程 CREATE TABLE submission ( id bigint NOT NULL AUTO_INCREMENT, homework_id bigint NOT NULL, student_id bigint NOT NULL, file_path varchar(255) NOT NULL COMMENT 文件存储路径, submit_time datetime DEFAULT CURRENT_TIMESTAMP, status tinyint DEFAULT 1 COMMENT 1-已提交2-已批阅3-已退回, PRIMARY KEY (id), UNIQUE KEY uk_homework_student (homework_id,student_id), KEY idx_student_time (student_id,submit_time), CONSTRAINT fk_submission_homework FOREIGN KEY (homework_id) REFERENCES homework (id) ON DELETE CASCADE, CONSTRAINT fk_submission_student FOREIGN KEY (student_id) REFERENCES student (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci; CREATE TABLE review ( id bigint NOT NULL AUTO_INCREMENT, submission_id bigint NOT NULL COMMENT 关联提交记录ID, teacher_id bigint NOT NULL COMMENT 批阅教师ID, score decimal(5,2) DEFAULT NULL COMMENT 得分0-100, comment text COMMENT 评语, review_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_submission (submission_id), CONSTRAINT fk_review_submission FOREIGN KEY (submission_id) REFERENCES submission (id) ON DELETE CASCADE, CONSTRAINT fk_review_teacher FOREIGN KEY (teacher_id) REFERENCES teacher (id) ON DELETE RESTRICT ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci;这里有两个精妙设计① submission表的uk_homework_student联合唯一索引确保一个学生对同一作业只能提交一次避免重复提交覆盖② review表的uk_submission唯一索引强制一份提交只能被批阅一次——教师手滑点了两次“提交批阅”第二次会因唯一键冲突失败系统提示“该作业已批阅不可重复操作”。注意db.sql末尾的初始化数据不是随便填的。比如插入教师数据时password字段存的是BCrypt加密后的密文$2a$10$QrNq…不是明文“123456”。你可以用在线BCrypt工具生成或者运行项目后用管理员账号重置密码再从数据库里复制密文。3.2 Maven工程结构实战指南pom.xml里的每一行都是经验pom.xml文件共156行去掉注释和空行剩128行但真正决定项目成败的是其中23行关键配置。我们聚焦最易出错的部分properties java.version11/java.version project.build.sourceEncodingUTF-8/project.build.sourceEncoding maven.compiler.source${java.version}/maven.compiler.source maven.compiler.target${java.version}/maven.compiler.target !-- SpringBoot版本锁定 -- spring-boot.version2.7.18/spring-boot.version /properties这里java.version11/java.version不是随意写的。SpringBoot 2.7.x官方推荐JDK 11因为JDK 8的Lambda表达式在某些复杂泛型场景下会编译失败。曾有个学生用JDK 17编译结果在ListStudent students studentRepository.findAllByClassId(classId);这行报错原因是Spring Data JPA 2.7.x对JDK 17的Records语法支持不完善。dependencies !-- Web核心 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Thymeleaf模板 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency !-- 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- JPA持久层 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency !-- 安全框架 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency !-- 文件上传 -- dependency groupIdcommons-fileupload/groupId artifactIdcommons-fileupload/artifactId version1.5/version /dependency !-- 日志增强 -- dependency groupIdnet.logstash.logback/groupId artifactIdlogstash-logback-encoder/artifactId version7.3/version /dependency /dependencies重点看commons-fileupload的版本。很多教程写1.4但1.4在SpringBoot 2.7中存在兼容性问题上传大文件时会触发java.lang.OutOfMemoryError: Java heap space。升级到1.5后它内部改用Streaming API内存占用降低70%。这个版本号不是凭空写的是我用JProfiler实测对比的结果。build plugins !-- Maven编译插件 -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-compiler-plugin/artifactId version3.11.0/version configuration source${java.version}/source target${java.version}/target encoding${project.build.sourceEncoding}/encoding !-- 关键启用注解处理器 -- annotationProcessorPaths path groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version /path /annotationProcessorPaths /configuration /plugin !-- SpringBoot打包插件 -- plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId version${spring-boot.version}/version configuration mainClasscom.example.homework.HomeworkApplication/mainClass executabletrue/executable !-- 关键排除devtools避免生产环境热部署 -- excludeDevtoolstrue/excludeDevtools /configuration /plugin /plugins /buildexcludeDevtoolstrue/excludeDevtools这一行救过无数学生的命。devtools在开发时很好用但打包成jar部署到服务器后它会监听文件变化并尝试重启应用——而生产环境根本没有IDE结果就是应用反复崩溃。这个配置确保mvn package打出来的jar包里不含devtools类。3.3 三角色权限控制实现Spring Security不是配配XML就完事权限控制不是在application.yml里写几行security.ignored就搞定的。这套系统的RBAC基于角色的访问控制实现在SecurityConfig.java中共217行代码核心逻辑如下Configuration EnableWebSecurity EnableGlobalMethodSecurity(prePostEnabled true) // 启用PreAuthorize注解 public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz - authz .requestMatchers(/admin/**).hasRole(ADMIN) // 管理员路径 .requestMatchers(/teacher/**).hasRole(TEACHER) // 教师路径 .requestMatchers(/student/**).hasRole(STUDENT) // 学生路径 .requestMatchers(/login, /logout, /css/**, /js/**, /images/**).permitAll() // 静态资源放行 .anyRequest().authenticated() // 其他请求需认证 ) .formLogin(form - form .loginPage(/login) // 自定义登录页 .usernameParameter(username) // 表单用户名字段名 .passwordParameter(password) // 表单密码字段名 .defaultSuccessUrl(/home, true) // 登录成功跳转首页 .failureUrl(/login?errortrue) // 登录失败返回登录页 ) .logout(logout - logout .logoutSuccessUrl(/login?logouttrue) // 注销成功跳转 .invalidateHttpSession(true) // 使session失效 .deleteCookies(JSESSIONID) // 删除cookie ); return http.build(); } Bean public UserDetailsService userDetailsService() { return username - { // 根据用户名查用户含角色信息 User user userRepository.findByUsername(username); if (user null) { throw new UsernameNotFoundException(用户不存在: username); } // 构建Spring Security的UserDetails对象 ListGrantedAuthority authorities new ArrayList(); authorities.add(new SimpleGrantedAuthority(ROLE_ user.getRole().toUpperCase())); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), authorities ); }; } }但真正的权限细粒度控制在Service层Service public class HomeworkService { PreAuthorize(hasRole(TEACHER) and #teacherId authentication.principal.id) public void publish(Long teacherId, Homework homework) { // 只有当前登录教师才能发布作业 homework.setTeacherId(teacherId); homeworkRepository.save(homework); } PreAuthorize(hasRole(TEACHER)) public void gradeSubmission(Long submissionId, BigDecimal score, String comment) { Submission submission submissionRepository.findById(submissionId) .orElseThrow(() - new RuntimeException(提交记录不存在)); // 校验教师是否有权限批阅该作业必须是该作业的发布教师或同院系教师 if (!canGrade(submission.getHomeworkId(), getCurrentTeacherId())) { throw new AccessDeniedException(无权批阅此作业); } // 执行批阅逻辑... } }PreAuthorize(hasRole(TEACHER) and #teacherId authentication.principal.id)这行注解意味着不仅要求用户角色是TEACHER还要求方法参数teacherId必须等于当前登录用户的ID。这样就杜绝了“张老师用李老师的账号登录然后调用/publish接口发布张老师的作业”这种越权操作。实操心得很多学生把所有权限逻辑写在Controller里比如在TeacherController.publish()里写if (!teacher.getId().equals(authentication.getId())) { throw new AccessDeniedException(); }。这是错误的Controller只负责协议转换权限校验必须下沉到Service层否则单元测试时无法独立验证业务逻辑。4. 开发与部署全流程从IDEA导入到CentOS上线4.1 IDEA导入与调试避开“找不到主类”的经典坑导入步骤看似简单但90%的学生卡在第一步解压源码包不要双击zip直接解压到中文路径如“我的文档\毕设\作业系统”IDEA会因路径含中文报错。正确做法解压到纯英文路径如D:\homework-system。启动IDEA选择“Open”而非“Import Project”因为项目根目录下有pom.xmlIDEA会自动识别为Maven项目。如果选“Import Project”它会当成普通文件夹后续要手动配置Maven。等待Maven依赖下载完成右下角出现“Building ‘homework’ project”进度条此时不要急着Run。观察Messages窗口确认没有红色ERROR。常见报错-Could not resolve dependencies for project ...网络问题点击Maven面板的刷新按钮蓝色循环箭头或检查IDEA的Settings → Build → Maven → User settings file是否指向正确的settings.xml。-Cannot resolve symbol SpringBootApplicationJDK未正确配置。File → Project Structure → Project → Project SDK选择已安装的JDK 11。配置运行参数点击右上角“Add Configuration” → “” → “Spring Boot”Name填“HomeworkApplication”Main class选com.example.homework.HomeworkApplication。关键步骤在“Environment variables”里添加SPRING_PROFILES_ACTIVEdev并在“Active profiles”框里也填dev——这会激活application-dev.yml配置。启动前的最后检查打开src/main/resources/application-dev.yml确认数据库配置yaml spring: datasource: url: jdbc:mysql://localhost:3306/homework_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: your_mysql_password如果MySQL root密码不是空的必须在这里填对。切记不要用localhost而要用127.0.0.1。因为MySQL的localhost会走socket连接而127.0.0.1走TCP后者更稳定。首次启动必做的三件事- 浏览器访问http://localhost:8080/login用db.sql里预置的管理员账号admin/123456登录- 进入“系统管理” → “数据库初始化”点击“执行初始化脚本”按钮它会自动执行db.sql里的建表语句- 修改所有用户的初始密码在“用户管理”里找到学生、教师账号重置密码为自己的学号后四位。注意如果启动时报错java.lang.IllegalStateException: Failed to load ApplicationContext大概率是MySQL服务没开。Windows下按WinR输入services.msc找到MySQL80服务右键启动Mac下终端执行brew services start mysql。4.2 生产环境部署CentOS 7上的零失误操作清单学校机房服务器通常是CentOS 7 OpenJDK 1.8部署流程必须适配第一步准备运行环境# 1. 安装OpenJDK 1.8如果未安装 sudo yum install java-1.8.0-openjdk-devel # 2. 验证JDK版本 java -version # 输出应为 openjdk version 1.8.0_362 # 3. 创建部署目录 sudo mkdir -p /opt/homework sudo chown -R $USER:$USER /opt/homework第二步上传并构建# 1. 本地打包确保pom.xml里packaging是jar mvn clean package -Dmaven.test.skiptrue # 2. 上传jar包到服务器假设jar包名为homework-0.0.1-SNAPSHOT.jar scp target/homework-0.0.1-SNAPSHOT.jar userserver_ip:/opt/homework/ # 3. 重命名为简洁名称 cd /opt/homework mv homework-0.0.1-SNAPSHOT.jar homework.jar第三步配置生产环境# 1. 创建application-prod.yml覆盖开发配置 cat application-prod.yml EOF spring: profiles: active: prod datasource: url: jdbc:mysql://127.0.0.1:3306/homework_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: homework_user password: strong_password_here jpa: hibernate: ddl-auto: validate # 生产环境严禁update或createvalidate只校验不修改 server: port: 8080 servlet: context-path: /homework logging: level: com.example.homework: INFO EOF # 2. 创建启动脚本 cat start.sh EOF #!/bin/bash nohup java -Xms512m -Xmx1024m -Dspring.config.locationfile:./application-prod.yml -jar homework.jar homework.log 21 echo $! homework.pid echo Homework system started with PID $(cat homework.pid) EOF chmod x start.sh第四步启动与守护# 1. 启动应用 ./start.sh # 2. 检查进程 ps -ef | grep homework # 3. 查看日志实时跟踪 tail -f homework.log # 4. 设置开机自启可选 sudo cp start.sh /etc/init.d/homework sudo chmod x /etc/init.d/homework sudo chkconfig --add homework sudo chkconfig homework on第五步Nginx反向代理让访问更友好# 安装Nginx sudo yum install nginx # 编辑配置 sudo vi /etc/nginx/conf.d/homework.conf配置内容server { listen 80; server_name homework.your-school.edu; location / { proxy_pass http://127.0.0.1:8080/homework/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }重启Nginxsudo systemctl restart nginx常见问题排查如果访问http://homework.your-school.edu显示502 Bad Gateway先检查ps -ef | grep homework确认Java进程在运行再检查sudo tail -f /var/log/nginx/error.log常见原因是proxy_pass地址写错了比如漏了/homework/后缀。5. 常见问题与避坑指南答辩老师最可能问的10个问题5.1 数据库相关问题Q1MySQL建表时为什么用utf8mb4而不是utf8AMySQL的utf8其实是utf8mb3最多只支持3字节字符无法存储emoji如需要4字节和部分生僻汉字。utf8mb4才是真正的UTF-8实现。db.sql里所有表都指定了DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci并且在application.yml的JDBC URL里加了characterEncodingutf8mb4参数双重保障。Q2如何保证作业提交的幂等性A靠submission表的联合唯一索引uk_homework_student。当学生重复提交同一作业时数据库会抛出Duplicate entry 123-456 for key uk_homework_student异常Service层捕获后返回友好提示“您已提交过该作业”而不是让前端显示500错误。Q3如果教师误删了作业数据能恢复吗A不能直接恢复但有补救措施。homework表的外键设置了ON DELETE CASCADE删作业会连带删submission和review记录。所以系统在教师删除作业前强制弹窗确认“删除作业将同时清除所有学生提交记录和教师批阅信息确定要删除吗”。此外db.sql里预置了备份脚本backup_daily.sh每天凌晨2点自动执行mysqldump -u root -p homework_db /backup/homework_$(date %Y%m%d).sql。5.2 SpringBoot与安全问题Q4为什么用BCrypt而不是MD5加密密码AMD5是哈希算法不可逆但可碰撞相同输入永远输出相同哈希值攻击者可以用彩虹表快速破解。BCrypt是自适应哈希算法内置盐值salt和迭代次数strength12即使两个用户密码都是“123456”加密后的密文也完全不同且计算耗时约300ms极大增加暴力破解成本。Q5如何防止教师越权批阅其他班级的作业A在ReviewService.grade()方法里有双重校验// 第一层数据库关联校验 Homework homework homeworkRepository.findById(submission.getHomeworkId()) .orElseThrow(...); // 第二层业务逻辑校验 if (!teacherService.isSameDepartment(homework.getTeacherId(), currentTeacherId)) { throw new AccessDeniedException(跨院系作业无权批阅); }isSameDepartment()方法查teacher表的department_id字段确保批阅教师与发布教师属于同一院系。Q6CSRF Token是怎么生成和校验的ASpring Security自动生成。当用户访问/login页面时Thymeleaf模板引擎自动在表单里插入input typehidden name_csrf value8e1c5a2e-1b3f-4c5d-9a7b-0c8d9e1f2a3b /这个value值是服务器端生成的随机Token存储在HttpSession中。表单提交时Spring Security拦截请求比对请求中的_csrf参数与Session中存储的Token是否一致不一致则拒绝。5.3 部署与运维问题Q7为什么生产环境要用ddl-auto: validate而不是updateAupdate会自动修改数据库结构如加字段、改类型这在生产环境是灾难性的。validate只校验实体类与数据库表结构是否一致不一致时直接启动失败强迫开发者手动执行SQL变更确保每一次数据库改动都经过DBA审核和备份。Q8如何监控系统运行状态ASpringBoot Actuator已集成。在application-prod.yml里启用management: endpoints: web: exposure: include: health,info,metrics,logfile,loggers endpoint: health: show-details: when_authorized访问http://your-server:8080/actuator/health返回JSON{status:UP,components:{db:{status:UP,details:{database:MySQL,validationQuery:isValid()}}}}这说明数据库连接正常。Q9如果学生上传了一个100MB的视频文件系统会崩溃吗A不会。application.yml里配置了spring: servlet: context-path: /homework servlet: multipart: max-file-size: 50MB max-request-size: 50MB当文件超过50MBSpringBoot会在请求到达Controller前就拦截返回400 Bad Request错误信息为“Maximum upload size exceeded”。这个阈值可在sys_config表里动态调整。Q10如何给系统添加新功能比如“作业查重”A遵循开闭原则。新增一个PlagiarismService接口及其实现类在SubmissionService.submit()里调用它。关键是要在pom.xml里引入查重SDK如Apache OpenNLP但不要把它写死在核心模块。正确做法是定义PlagiarismChecker接口提供check(String content)方法然后在application-prod.yml里配置plagiarism.enabledtrue用ConditionalOnProperty(plagiarism.enabled)控制Bean加载。这样未来换成商业查重API只需新增一个实现类不改一行原有代码。最后分享一个小技巧答辩前务必用Chrome的隐身模式访问系统清除所有Cookie和缓存然后从登录开始完整走一遍学生、教师、管理员三个角色的操作流程。很多学生答辩时演示失败就是因为本地浏览器缓存了旧的JS文件导致Thymeleaf模板渲染异常。隐身模式能最大程度模拟评委老师的首次访问体验。本文还有配套的精品资源点击获取简介基于SpringBoot搭建的B/S模式作业管理平台采用MySQL作为后端数据库支持学生、教师、管理员三类角色协同使用。学生能完成账号注册登录、密码修改、作业查看下载、在线提交、已交作业管理及教师点评查阅教师可创建并发布作业、批阅学生提交内容、实时掌握作业提交状态管理员负责班级信息维护、师生账号管理及系统基础配置。项目提供标准Maven工程结构包含pom.xml构建配置、src源码目录、db.sql数据库初始化脚本含建表语句与初始数据、readme.text使用说明、mvnw/mvnw.cmd跨平台构建工具以及.gitignore等开发规范文件开箱即可导入IDE运行调试适合作为Java Web课程设计或本科毕业设计的实践参考。本文还有配套的精品资源点击获取