SpringBoot + Vue3 在线作业管理系统【附源码+数据库+40接口+ER图+部署+一键启动】
一、项目简介
本项目是一个面向学校和教育机构的在线作业管理平台,覆盖了作业发布 → 学生提交 → 教师批改 → 成绩统计的完整流程。
1🎯 核心亮点:本系统内置作业查重功能,教师可对某次作业的所有提交进行文本相似度检测,有效识别抄袭行为。查重结果以相似度分数呈现,帮助教师快速定位疑似抄袭的作业,维护学术诚信。
1.1 核心角色
| 角色 | 核心功能 |
|---|---|
| 学生 | 查看作业、提交作业(含文件上传)、查看成绩与反馈、修改个人资料(需审批) |
| 教师 | 发布作业(按学生定向分配)、批改作业(评分+评语)、查看班级成绩统计、作业查重检测 |
| 管理员 | 用户管理(增删改查)、审核资料修改申请、全局数据查看 |
1.2 系统功能模块
- 🔐 用户认证:注册/登录/忘记密码(验证码找回)/JWT 令牌 + Refresh Token
- 📝 作业管理:创建、编辑、删除、按班级定向发布、截止时间控制、状态管理(published/expired/withdrawn)
- 📤 作业提交:多格式文件上传(PDF/Word/ZIP/图片等)、截止时间控制、重新提交、附件删除
- ✏️ 作业批改:评分(含满分校验)、评语、教师查看所有提交
- 🔍 作业查重:文本相似度检测、抄袭识别、查重报告、按相似度排序
- 📊 成绩统计:平均分/最高分/最低分、提交率/批改率、学生个人详情、ECharts 可视化图表
- 🔔 消息通知:系统通知、作业提醒、成绩通知、永久消息/临时通知分类
- 📋 申请审批:学生资料修改申请 → 管理员审核(通过/拒绝)
- 📎 文件管理:附件上传、下载(含 Content-Type 自动识别)、文件大小校验
二、环境配置
在开始使用本项目前,请确保以下环境已安装并正确配置。
2.1 环境要求
| 软件 | 最低版本 | 推荐版本 | 说明 |
|---|---|---|---|
| JDK | 24.0.1+ | 24.0.1 | Java 开发工具包 |
| Maven | 3.9.14+ | 3.9.14 | 后端构建工具 |
| Node.js | 24.14.1+ | 24.14.1 | 前端运行时 |
| npm | 11.11.0+ | 11.11.0 | 前端包管理 |
| MySQL | 5.7+ | 8.0+ | 关系数据库 |
| Redis | 6.0+ | 7.0+ | 缓存数据库 |
2.2 环境安装
JDK 24 安装
- 从 Oracle JDK 或 OpenJDK 下载 JDK 24
- 配置环境变量:
JAVA_HOME= JDK 安装路径,PATH中添加%JAVA_HOME%\bin - 验证:
java -version、javac -version
Maven 安装
- 从 Maven 官网 下载 3.9.14+
- 配置环境变量:
MAVEN_HOME= 解压路径,PATH中添加%MAVEN_HOME%\bin - 验证:
mvn -version
Node.js 安装
- 从 Node.js 官网 下载 v24.14.1 LTS 版本
- 验证:
node -v、npm -v - 推荐配置国内镜像:
npm config set registryhttps://registry.npmmirror.com
MySQL 安装
- 从 MySQL 官网 下载安装
- 记住 root 密码(本项目默认配置为
123456) - 确保 MySQL 服务已启动
Redis 安装(Windows)
方式一 — WSL2:
bash
wsl --install
sudo apt update && sudo apt install redis-server
sudo service redis-server start
方式二 — Memurai:Redis-Compatible, Enterprise-Grade In-Memory Caching for Windows | Memurai 下载安装开发版。
三、技术栈
3.1 后端
| 技术 | 版本 | 用途 |
|---|---|---|
| Spring Boot | 3.4.5 | 核心框架 |
| Spring Security + JWT | jjwt 0.12.6 | 认证与授权(无状态 JWT + RBAC) |
| Spring Data JPA | — | ORM 持久层 |
| MyBatis Plus | 3.5.9 | 复杂查询增强 |
| MySQL | 5.7+ | 关系数据库 |
| Redis(Lettuce 连接池) | 6.0+ | 缓存与 Token 管理 |
| Caffeine Cache | 3.2.0 | 本地缓存(用户查询缓存) |
| SpringDoc OpenAPI | 2.8.4 | API 文档自动生成(Swagger UI) |
| Apache POI | 5.4.0 | Excel 导入导出 |
| iText 7 | 9.1.0 | PDF 生成 |
| Lombok | 1.18.38 | 简化代码 |
| Maven | 3.9.14+ | 构建工具 |
3.2 前端
| 技术 | 版本 | 用途 |
|---|---|---|
| Vue | 3.5.13 | 核心框架(Composition API) |
| Pinia | 3.0.1 | 状态管理(替代 Vuex) |
| Vue Router | 4.5.0 | 路由管理(含路由懒加载) |
| Element Plus | 2.9.7 | UI 组件库 |
| @element-plus/icons-vue | 2.3.1 | 图标库 |
| ECharts + vue-echarts | 5.6.0 / 7.0.3 | 数据可视化 |
| Axios | 1.7.9 | HTTP 请求 |
| Vite | 6.0.11 | 构建工具(开发服务器+代理) |
| dayjs | 1.11.13 | 日期处理 |
| NProgress | 0.2.0 | 页面加载进度条 |
| js-cookie | 3.0.5 | Cookie 管理 |
| file-saver + xlsx | — | 文件下载与 Excel 导出 |
| Sass | 1.83.4 | CSS 预处理器 |
| unplugin-auto-import | 19.0.0 | 自动导入 Vue API |
| unplugin-vue-components | 28.0.0 | 自动导入 Element Plus 组件 |
四、项目架构
4.1 目录结构
4.2 前后端交互流程
┌─────────────┐ HTTP/REST ┌─────────────┐ JDBC/JPA ┌──────────┐
│ Vue 3 │ ◄────────────────► │ Spring Boot │ ◄──────────────► │ MySQL │
│ 前端 :3000 │ Axios + Proxy │ 后端 :8080 │ │ 数据库 │
└─────────────┘ └──────┬───────┘ └──────────┘
│
│ Caffeine / Redis
▼
┌──────────┐
│ 缓存层 │
└──────────┘
- 5前端通过 Vite 开发服务器运行在
localhost:3000 - 后端运行在
localhost:8080,context-path 为/api - 跨域通过 Vite proxy 代理解决(开发环境),后端也配置了 CORS(生产环境)
- 认证采用 JWT 无状态 Token,前端存入 Cookie,每次请求通过 Axios 拦截器自动注入
Authorization: Bearer <token>
五、数据库设计
系统包含 6 张核心表,完整建表语句见项目根目录的 online_homework_system_complete.sql。
5.1 users — 用户表
sql
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '密码(BCrypt 加密)',
`name` varchar(255) NOT NULL COMMENT '姓名',
`role` varchar(50) NOT NULL COMMENT '角色(STUDENT/TEACHER/ADMIN)',
`email` varchar(255) COMMENT '邮箱',
`phone` varchar(50) COMMENT '手机号',
`department` varchar(255) COMMENT '院系/部门',
`major` varchar(255) COMMENT '专业',
`student_id` varchar(50) COMMENT '学号',
`avatar` mediumtext COMMENT '头像 URL 或 Base64',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
KEY `idx_role` (`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.2 homework — 作业表
sql
CREATE TABLE `homework` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL COMMENT '作业标题',
`description` text COMMENT '作业描述',
`teacher_id` bigint NOT NULL COMMENT '教师 ID',
`course_name` varchar(255) COMMENT '课程名称',
`deadline` datetime COMMENT '截止时间',
`max_score` double COMMENT '满分',
`allow_modification` tinyint(1) DEFAULT 1 COMMENT '是否允许修改提交',
`status` varchar(50) DEFAULT 'published' COMMENT '状态(published/expired/withdrawn)',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_teacher_id` (`teacher_id`),
KEY `idx_status` (`status`),
KEY `idx_deadline` (`deadline`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.3 homework_student — 作业-学生关联表
sql
CREATE TABLE `homework_student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`homework_id` bigint NOT NULL COMMENT '作业 ID',
`student_id` bigint NOT NULL COMMENT '学生 ID',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_homework_student` (`homework_id`, `student_id`),
KEY `idx_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.4 submissions — 提交表
sql
CREATE TABLE `submissions` (
`id` bigint NOT NULL AUTO_INCREMENT,
`homework_id` bigint NOT NULL COMMENT '作业 ID',
`student_id` bigint NOT NULL COMMENT '学生 ID',
`content` text COMMENT '作业内容',
`file_path` varchar(500) COMMENT '文件路径',
`submitted_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`score` double COMMENT '分数',
`feedback` text COMMENT '评语',
`graded_at` timestamp NULL COMMENT '批改时间',
`status` varchar(50) DEFAULT 'submitted' COMMENT '状态(submitted/graded)',
`similarity_score` double COMMENT '相似度分数',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_homework_student` (`homework_id`, `student_id`),
CONSTRAINT `fk_submission_homework` FOREIGN KEY (`homework_id`) REFERENCES `homework` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_submission_student` FOREIGN KEY (`student_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.5 message — 消息通知表
sql
CREATE TABLE `message` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL COMMENT '消息标题',
`content` text COMMENT '消息内容',
`sender_id` bigint COMMENT '发送者 ID',
`receiver_id` bigint NOT NULL COMMENT '接收者 ID',
`type` varchar(50) DEFAULT 'notification' COMMENT '类型(notification/permanent/system)',
`status` varchar(50) DEFAULT 'active' COMMENT '状态(active/inactive)',
`is_read` tinyint(1) DEFAULT 0 COMMENT '是否已读',
`expire_time` datetime COMMENT '过期时间',
`notification_id` varchar(255) COMMENT '通知 ID(用于批量操作)',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `fk_message_sender` FOREIGN KEY (`sender_id`) REFERENCES `users` (`id`) ON DELETE SET NULL,
CONSTRAINT `fk_message_receiver` FOREIGN KEY (`receiver_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.6 profile_requests — 资料申请审批表
sql
CREATE TABLE `profile_requests` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL COMMENT '用户 ID',
`username` varchar(255) NOT NULL COMMENT '用户名',
`name` varchar(255) NOT NULL COMMENT '姓名',
`email` varchar(255) COMMENT '邮箱',
`phone` varchar(50) COMMENT '手机号',
`department` varchar(255) COMMENT '院系',
`major` varchar(255) COMMENT '专业',
`student_id` varchar(50) COMMENT '学号',
`avatar` mediumtext COMMENT '头像',
`status` varchar(50) NOT NULL DEFAULT 'pending' COMMENT '状态(pending/approved/rejected)',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5.7 ER 关系图(文字版)
users (1) ──────< homework_student >────── (N) homework
│ │
│ (teacher_id) │
└──────────────────────────────────────────────┘
│
├── (1) ────< submissions >──── (N)
│ │
│ └──── (N:1) ──── homework
│
├── (1) ────< message (sender) >──── (N)
├── (1) ────< message (receiver) >─── (N)
│
└── (1) ────< profile_requests >──── (N)
六、核心功能实现
6.1 JWT 认证 + RBAC 权限控制
使用 Spring Security + JWT 实现无状态认证:
java
// SecurityConfig.java — 核心安全配置
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.exceptionHandling(exception -> exception
.authenticationEntryPoint(jwtAuthenticationEntryPoint))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**", "/public/**").permitAll()
.requestMatchers("/users/verification-code", "/users/verify-code",
"/users/reset-password").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/teacher/**").hasAnyRole("TEACHER", "ADMIN")
.requestMatchers("/student/**")
.hasAnyRole("STUDENT", "TEACHER", "ADMIN")
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**",
"/swagger-ui.html").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider())
.addFilterBefore(jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
RBAC 角色设计:基于 ROLE_ADMIN、ROLE_TEACHER、ROLE_STUDENT 三种角色,通过 @PreAuthorize 注解实现方法级权限控制。
@PreAuthorize("hasAnyRole('TEACHER', 'ADMIN')")— 创建/编辑/删除作业@PreAuthorize("hasRole('STUDENT')")— 提交作业@PreAuthorize("hasRole('ADMIN')")— 用户管理、审批
6.2 缓存策略
项目同时使用了 Redis 和 Caffeine 本地缓存:
- Redis:配置在
application.yml中,使用 Lettuce 连接池(max-active: 20 / max-idle: 10 / min-idle: 5),用于分布式场景下的数据共享 - Caffeine 本地缓存:最大 500 条目,30 分钟未访问过期,命中率目标 > 80%
java
// RedisConfig.java — 实际配置的是 Caffeine 本地缓存
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(500)
.expireAfterAccess(30, TimeUnit.MINUTES)
.recordStats());
return cacheManager;
}
}
6.3 全局异常处理
统一的异常处理与返回格式:
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<?>> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(404)
.body(ApiResponse.error(404, ex.getMessage()));
}
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<ApiResponse<?>> handleAccessDenied(AccessDeniedException ex) {
return ResponseEntity.status(403)
.body(ApiResponse.error(403, "权限不足"));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<?>> handleGeneral(Exception ex) {
return ResponseEntity.status(500)
.body(ApiResponse.error(500, "服务器内部错误"));
}
}
统一响应格式:
json
// 成功
{ "code": 200, "message": "操作成功", "data": { ... } }
// 失败
{ "code": 400, "message": "错误信息", "data": null }
6.4 前端 Axios 封装
统一的请求/响应拦截器,自动注入 Token,Token 过期自动跳转登录:
javascript
// utils/request.js
import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router'
const request = axios.create({
baseURL: '/api',
timeout: 10000
})
// 请求拦截器 — 注入 JWT Token
request.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// 响应拦截器 — 统一错误处理
request.interceptors.response.use(
response => response.data,
error => {
if (error.response?.status === 401) {
localStorage.removeItem('token')
router.push('/login')
}
ElMessage.error(error.response?.data?.message || '请求失败')
return Promise.reject(error)
}
)
export default request
6.5 前端路由权限守卫
javascript
// router/index.js
router.beforeEach((to, from, next) => {
NProgress.start()
const userStore = useUserStore()
const token = userStore.token
const userRole = userStore.role
if (to.meta.requiresAuth && !token) {
next({ name: 'Login', query: { redirect: to.fullPath } })
NProgress.done()
} else if (to.meta.requiresAuth && to.meta.roles &&
!to.meta.roles.includes(userRole)) {
ElMessage.error('您没有权限访问该页面')
next({ name: 'Dashboard' })
NProgress.done()
} else {
next()
}
})
6.6 前端 Pinia 状态管理
使用 Pinia 管理用户登录状态,Token 和用户信息持久化到 Cookie(js-cookie):
javascript
// store/user.js
export const useUserStore = defineStore('user', () => {
const token = ref(Cookies.get('token') || '')
const user = ref(/* 从 Cookie 恢复 */)
const role = ref(userInfo?.role || '')
const loginAction = async (loginForm) => {
const res = await login(loginForm)
token.value = res.data.token
user.value = { ...res.data, role: res.data.role?.toUpperCase() }
Cookies.set('token', res.data.token)
Cookies.set('userInfo', JSON.stringify(userData))
return res
}
const logoutAction = async () => {
token.value = ''
user.value = null
Cookies.remove('token')
Cookies.remove('userInfo')
}
return { token, user, role, loginAction, logoutAction, ... }
})
6.7 作业查重功能 🔍
查重是本系统的一大亮点,旨在帮助教师快速识别学生作业中的抄袭行为。核心原理是基于文本相似度的两两比对算法,计算同一作业下不同学生提交内容的相似度分数。
6.7.1 实现原理
查重流程分为三个步骤:
第一步:提取所有提交内容
java
// SubmissionService.java — checkPlagiarism 方法
public List<Submission> checkPlagiarism(Long homeworkId) {
// 1. 获取该作业的所有提交
List<Submission> submissions = submissionRepository.findByHomeworkId(homeworkId);
// 2. 为每个提交提取纯文本内容(去除HTML标签、标点符号等干扰)
for (Submission sub : submissions) {
String plainText = extractPlainText(sub.getContent());
sub.setPlainText(plainText);
}
// 3. 两两比对计算相似度
for (int i = 0; i < submissions.size(); i++) {
for (int j = i + 1; j < submissions.size(); j++) {
double similarity = calculateSimilarity(
submissions.get(i).getPlainText(),
submissions.get(j).getPlainText()
);
// 取该学生与其他所有学生比较的最高相似度
submissions.get(i).setSimilarityScore(
Math.max(submissions.get(i).getSimilarityScore(), similarity)
);
submissions.get(j).setSimilarityScore(
Math.max(submissions.get(j).getSimilarityScore(), similarity)
);
}
}
// 4. 保存相似度结果到数据库
submissionRepository.saveAll(submissions);
// 5. 按相似度降序排列返回
submissions.sort((a, b) ->
Double.compare(b.getSimilarityScore(), a.getSimilarityScore())
);
return submissions;
}
第二步:文本预处理
在计算相似度前,需要对提交内容进行清洗,去除无关信息:
java
private String extractPlainText(String content) {
if (content == null) return "";
// 去除 HTML 标签
String text = content.replaceAll("<[^>]+>", "");
// 去除标点符号和多余空白
text = text.replaceAll("[\\p{P}\\p{S}]", "");
// 统一转小写
text = text.toLowerCase().trim();
// 去除多余空格
text = text.replaceAll("\\s+", " ");
return text;
}
第三步:相似度计算
采用基于词频的余弦相似度算法,这是文本查重领域的经典方法:
java
private double calculateSimilarity(String text1, String text2) {
if (text1.isEmpty() || text2.isEmpty()) return 0.0;
// 分词
String[] words1 = text1.split(" ");
String[] words2 = text2.split(" ");
// 构建词频向量
Map<String, Integer> freq1 = buildWordFrequency(words1);
Map<String, Integer> freq2 = buildWordFrequency(words2);
// 获取所有不重复的词语
Set<String> allWords = new HashSet<>();
allWords.addAll(freq1.keySet());
allWords.addAll(freq2.keySet());
// 计算余弦相似度
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (String word : allWords) {
int count1 = freq1.getOrDefault(word, 0);
int count2 = freq2.getOrDefault(word, 0);
dotProduct += count1 * count2;
norm1 += count1 * count1;
norm2 += count2 * count2;
}
if (norm1 == 0 || norm2 == 0) return 0.0;
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
private Map<String, Integer> buildWordFrequency(String[] words) {
Map<String, Integer> freq = new HashMap<>();
for (String word : words) {
freq.merge(word, 1, Integer::sum);
}
return freq;
}
6.7.2 查重 API 接口
教师通过一个接口即可完成查重操作:
POST /api/submissions/homework/{homeworkId}/plagiarism
权限:TEACHER / ADMIN
返回结果按 similarityScore 降序排列,相似度越高的提交排在越前面,方便教师快速定位疑似抄袭的作业。
6.7.3查重结果呈现
查重完成后,每个提交记录的 similarity_score 字段会被更新,前端在批改列表中可以直观地看到每份作业的相似度分数。通常设定以下阈值:
| 相似度区间 | 判定结果 | 颜色标识 |
|---|---|---|
| 0% ~ 30% | 正常 | 🟢 绿色 |
| 30% ~ 60% | 可疑 | 🟡 黄色 |
| 60% ~ 100% | 高度疑似抄袭 | 🔴 红色 |
💡 本系统的查重基于纯文本内容进行比对。如果作业涉及代码,建议结合专业代码查重工具(如 MOSS、JPlag)使用。
6.8 文件上传与下载
- 上传:支持多格式文件(PDF/Word/ZIP/RAR/图片/文本),100MB 上限,自动校验文件类型和大小
- 下载:自动识别文件 MIME 类型,正确设置 Content-Disposition 头,保留原始文件名和后缀
- 存储:文件存储在
backend/uploads/submissions/目录下,以时间戳_原始文件名命名
七、API 接口一览(完整 40+ 接口)
7.1 认证模块 — 8 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| POST | /api/auth/login |
用户登录,返回 JWT + Refresh Token | 匿名 |
| POST | /api/auth/register |
用户注册 | 匿名 |
| POST | /api/auth/refresh |
刷新令牌 | 匿名 |
| POST | /api/auth/logout |
退出登录 | 认证 |
| POST | /api/auth/forgot-password/send-code |
发送验证码(邮箱/手机) | 匿名 |
| POST | /api/auth/forgot-password/verify-code |
验证验证码 | 匿名 |
| POST | /api/auth/forgot-password/reset |
重置密码 | 匿名 |
| POST | /api/auth/check-username |
检查用户名是否存在 | 匿名 |
| POST | /api/auth/get-user-contacts |
获取用户联系方式(脱敏) | 匿名 |
7.2 用户模块 — 9 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/users/me |
获取当前用户信息 | 认证 |
| GET | /api/users/{id} |
获取指定用户 | 认证 |
| GET | /api/users |
获取所有用户(支持角色筛选) | ADMIN |
| PUT | /api/users/{id} |
更新用户信息 | 认证 |
| DELETE | /api/users/{id} |
删除用户 | ADMIN |
| PUT | /api/users/change-password |
修改密码 | 认证 |
| POST | /api/users/verification-code |
生成验证码 | 匿名 |
| POST | /api/users/verify-code |
校验验证码 | 匿名 |
| POST | /api/users/reset-password |
通过验证码重置密码 | 匿名 |
7.3 作业模块 — 12 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| POST | /api/homework |
创建作业(含学生分配) | TEACHER/ADMIN |
| GET | /api/homework/{id} |
获取作业详情(含教师名) | 认证 |
| GET | /api/homework/teacher/all |
教师作业列表(支持课程/状态筛选) | TEACHER/ADMIN |
| GET | /api/homework/student/all |
学生作业列表(含提交状态) | STUDENT |
| GET | /api/homework |
获取所有作业 | ADMIN |
| GET | /api/homework/status/{status} |
按状态查询作业 | 认证 |
| PUT | /api/homework/{id} |
更新作业 | TEACHER/ADMIN |
| DELETE | /api/homework/{id} |
删除作业 | TEACHER/ADMIN |
| GET | /api/homework/{id}/students |
获取作业分配的学生 ID 列表 | TEACHER/ADMIN |
| PUT | /api/homework/{id}/students |
更新作业分配的学生列表 | TEACHER/ADMIN |
| GET | /api/homework/teacher/with-submissions |
获取有学生提交的作业 | TEACHER/ADMIN |
| GET | /api/homework/expired |
获取过期作业 | TEACHER/ADMIN |
7.4 提交模块 — 12 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| POST | /api/submissions |
提交作业(含文件上传) | STUDENT |
| GET | /api/submissions/{id} |
获取提交详情 | 认证 |
| GET | /api/submissions/student/all |
获取学生的所有提交 | STUDENT |
| GET | /api/submissions/homework/{homeworkId} |
获取作业的所有提交(含学生名) | TEACHER/ADMIN |
| GET | /api/submissions/homework/{homeworkId}/student |
学生获取自己在某作业的提交 | STUDENT |
| GET | /api/submissions/teacher/all |
教师查看所有提交 | TEACHER/ADMIN |
| PUT | /api/submissions/{id}/grade |
批改作业(评分+评语) | TEACHER/ADMIN |
| PUT | /api/submissions/{id} |
更新提交(含文件替换/删除) | STUDENT |
| DELETE | /api/submissions/{id} |
删除提交 | STUDENT |
| POST | /api/submissions/homework/{homeworkId}/plagiarism |
作业查重 | TEACHER/ADMIN |
| GET | /api/submissions/attachment/{id} |
下载附件 | 认证 |
| GET | /api/submissions/homework/{homeworkId}/statistics |
作业成绩统计 | TEACHER/ADMIN |
7.5 消息模块 — 5 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/messages |
获取消息列表 | 认证 |
| GET | /api/messages/{id} |
获取消息详情 | 认证 |
| GET | /api/messages/unread |
获取未读消息 | 认证 |
| PUT | /api/messages/{id}/read |
标记为已读 | 认证 |
| DELETE | /api/messages/{id} |
删除消息 | 认证 |
7.6 审批模块 — 7 个接口
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| POST | /api/profile-requests |
创建资料修改申请 | 认证 |
| GET | /api/profile-requests/my |
获取自己的申请记录 | 认证 |
| GET | /api/profile-requests |
获取所有申请 | ADMIN |
| GET | /api/profile-requests/pending |
获取待审批申请 | ADMIN |
| GET | /api/profile-requests/{id} |
获取申请详情 | 认证 |
| PUT | /api/profile-requests/{id}/approve |
批准申请 | ADMIN |
| PUT | /api/profile-requests/{id}/reject |
拒绝申请 | ADMIN |
完整的 40+ 个 API 接口可通过 Swagger 查看:
启动后端后访问 http://localhost:8080/api/swagger-ui.html
八、快速启动
💡 环境配置请参考 二、环境配置,确保 JDK、Maven、Node.js、MySQL、Redis 均已安装。
8.1 数据库初始化
bash
# 登录 MySQL
mysql -u root -p
# 创建数据库
CREATE DATABASE IF NOT EXISTS online_homework_system
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_general_ci;
exit;
导入表结构和测试数据:
bash
# 推荐导入完整版(含测试账号和示例数据)
mysql -u root -p online_homework_system < online_homework_system_complete.sql
项目提供了两个 SQL 文件:
online_homework_system.sql— 仅表结构online_homework_system_complete.sql— 表结构 + 测试数据(推荐)
导入后包含:4 个测试用户、3 个示例作业、2 条示例提交、3 条示例消息。
8.2 配置后端
修改 backend/src/main/resources/application.yml 中的数据库和 Redis 连接信息:
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/online_homework_system?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root # 改为你的 MySQL 用户名
password: 123456 # 改为你的 MySQL 密码
data:
redis:
host: localhost # Redis 地址
port: 6379 # Redis 端口
password: # Redis 密码(如无则留空)
jwt:
secret: your-default-jwt-secret-key-change-in-production
expiration: 86400000 # Token 有效期(24小时,毫秒)
refresh-expiration: 604800000 # Refresh Token 有效期(7天)
⚠️ 生产环境请务必修改
jwt.secret为自定义密钥!
8.3 启动后端
bash
cd backend
mvn clean install -DskipTests
mvn spring-boot:run
或使用 IDE 启动:
- IntelliJ IDEA:打开
backend目录 → 找到OnlineHomeworkSystemApplication.java→ 右键 Run - VS Code:安装 Extension Pack for Java → 打开
backend→ 按 F5 启动
验证:访问 http://localhost:8080/api/swagger-ui.html,看到 Swagger UI 页面即启动成功。
8.4 启动前端
bash
cd frontend
npm install
npm run dev
Vite 配置说明(vite.config.js 已配置好):
- 开发服务器端口:
3000 - API 代理:
/api→ http://localhost:8080 - 代码分割:Element Plus、Vue 生态、ECharts 独立打包
- 自动导入:Element Plus 组件和 Vue API 按需自动导入
javascript
// vite.config.js 关键配置
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
启动后访问 http://localhost:3000
8.5 测试账号
| 角色 | 用户名 | 密码 |
|---|---|---|
| 管理员 | admin |
admin123 |
| 教师 | teacher1 |
teacher123 |
| 学生 | student1 |
student123 |
| 学生 | student2 |
student123 |
8.6 常见问题排查
Q1:后端启动报 "Access denied for user"
原因:MySQL 用户名或密码不正确。
解决:检查 application.yml 中 spring.datasource.username 和 password 配置。
Q2:后端启动报 "Unknown database"
原因:未创建数据库。
解决:执行 CREATE DATABASE online_homework_system DEFAULT CHARACTER SET utf8mb4;
Q3:Redis 连接失败
原因:Redis 服务未启动或配置错误。
解决:检查 Redis 服务是否运行,确认 application.yml 中 host、port、password 正确。
Q4:npm install 失败
原因:网络问题或 npm 版本问题。
解决:
bash
npm cache clean --force
npm install --registry=https://registry.npmmirror.com
Q5:前端页面空白 / API 请求 404
原因:后端未启动或代理配置问题。
解决:确保后端已启动,通过 npm run dev 启动前端(不要直接打开 index.html)。
Q6:端口被占用
原因:8080 或 3000 端口已被占用。
解决:
bash
netstat -ano | findstr :8080
# 或修改 application.yml 中的 server.port
九、项目亮点总结
9.1 后端亮点
- 完整的安全体系:Spring Security + JWT 无状态认证 + BCrypt 密码加密 + RBAC 角色权限 + CORS 跨域防护
- 双层缓存架构:Redis(分布式)+ Caffeine(本地缓存),兼顾性能与可扩展性
- 完善的异常处理:@RestControllerAdvice 全局异常捕获 + 统一 ApiResponse 响应格式
- RESTful API 设计:规范的路由命名、HTTP 方法语义化、统一的请求响应格式
- Swagger 文档:SpringDoc OpenAPI 自动生成,支持在线调试
- 文件管理:支持多格式上传、Content-Type 自动识别下载、文件大小校验
- 作业查重:内置文本相似度检测
- 成绩统计:自动计算平均分/最高分/最低分/提交率/批改率
9.2 前端亮点
- 现代技术栈:Vue 3 Composition API + Pinia + Vite 6
- 组件按需引入:unplugin-vue-components + unplugin-auto-import,无需手动 import
- 路由懒加载:所有页面组件动态 import,首屏加载快
- 代码分割:Element Plus、Vue 生态、ECharts 分别独立 chunk
- 请求拦截器:自动注入 Token、401 自动跳转登录、统一错误提示
- 路由权限守卫:结合 NProgress 进度条,页面切换流畅
- 响应式布局:基于 Element Plus 栅格系统,适配桌面和移动端
- 状态持久化:使用 js-cookie 持久化 Token 和用户信息
9.3 安全特性
| 安全措施 | 实现方式 |
|---|---|
| 认证安全 | JWT 无状态认证,Token 24h / Refresh Token 7d |
| 密码安全 | BCrypt 加密存储 |
| 权限控制 | RBAC 角色 + @PreAuthorize 方法级注解 |
| SQL 注入防护 | JPA/MyBatis Plus 参数化查询 |
| XSS 防护 | 前端 Element Plus 自动转义 |
| CORS 防护 | 后端白名单配置 + 前端 Vite Proxy |
| CSRF 防护 | 无状态 JWT,禁用 Session |
十、待完善方向
- 📌 富文本编辑器(作业描述支持 Markdown/富文本)
- 📌 文件断点续传(大文件上传优化)
- 📌 Excel 批量导入导出成绩(Apache POI 已引入,待实现页面)
- 📌 邮件通知服务(截止提醒、成绩通知)
- 📌 单元测试覆盖率提升(目标 80%+)
- 📌 Docker 容器化部署
- 📌 WebSocket 实时消息推送
十一、写在最后
这个项目从零搭建到功能完成,花了大约两个月的时间。作为毕设项目,它基本覆盖了企业级开发中的核心知识点:Spring Boot 3、Spring Security、JWT、Redis、Vue 3、Element Plus 等。
项目代码注释详细,每个类和方法都标注了功能说明,适合初学者学习和参考。
如果这个项目对你有所帮助,欢迎给个 Star ⭐,也欢迎提 Issue 交流!
附录:角色页面权限矩阵
| 页面路径 | Admin | Teacher | Student | 说明 |
|---|---|---|---|---|
/dashboard |
✅ | ✅ | ✅ | 控制台首页 |
/profile |
✅ | ✅ | ✅ | 个人资料 |
/change-password |
✅ | ✅ | ✅ | 修改密码 |
/homework |
✅ | ✅ | ✅ | 作业列表 |
/homework/create |
✅ | ✅ | ❌ | 创建作业 |
/homework/:id/edit |
✅ | ✅(仅自己) | ❌ | 编辑作业 |
/submission |
❌ | ❌ | ✅ | 提交作业 |
/grade |
✅ | ✅ | ❌ | 批改列表 |
/grade/:submissionId |
✅ | ✅ | ❌ | 批改详情 |
/statistics |
✅ | ✅ | ❌ | 成绩统计 |
/messages |
✅ | ✅ | ✅ | 消息中心 |
/users |
✅ | ❌ | ❌ | 用户管理 |
/profile-requests |
✅(审核) | ❌ | ❌ | 申请审批 |
本文发布于 CSDN,作者:一孤程
更多推荐
所有评论(0)