资讯动态

SpringBoot3+Vue3+MySQL智能课程学习系统全栈实战

发布时间:2026/9/5 17:59:09 来源:尧图企业网站定制
这次我们来看一个完整的全栈实战项目智能课程学习系统。技术栈就是标题里写的那一套Java 后端 SpringBoot3 Vue.js3 前端 MySQL 数据库。不做单体演示项目而是按真实业务场景拆解功能模块、数据库设计和接口开发适合正在准备 Java 全栈简历项目的开发者也适合想把在线课程、学习进度统计、智能推荐这些功能落到代码里的同学。做这类系统之前先想清楚一个问题它到底“智能”在哪里很多项目把“智能”做成噱头最后就是普通的 CRUD。这个项目里可以落地的智能点有三个学习进度自动追踪与预警、课程内容与学员水平匹配推荐、学情数据可视化分析。这三个点分别对应后端定时任务、改进的协同过滤或规则推荐、MySQL 聚合统计与前端图表展示每一步都有实际代码可写也能在简历上讲清楚。本文会把这个系统从需求拆解、数据库建表、SpringBoot3 核心接口、Vue3 页面联调到服务器部署完整串一遍。因为 Java Web 项目不涉及显卡资源运行的资源占用重点会放在后端 JVM、MySQL 连接和前端打包产物上。你最后拿到的是一套能跑通注册登录、课程浏览、章节学习、学习进度记录、统计分析的小型学习平台而不是只能看界面的 Demo。1. 智能课程学习系统核心能力速览先把项目基础信息列出来方便快速判断这套技术路线适不适合自己。能力项说明项目类型前后端分离的在线课程学习管理系统后端技术Java 17、SpringBoot3、Spring Security、MyBatis-Plus 或 Spring Data JPA前端技术Vue3、Vite、TypeScript、Element Plus、Pinia、Vue Router数据库MySQL 8.0 及以上版本核心功能用户注册登录、课程分类、课程章节管理、学习记录打卡、课程收藏、考试答题、学情统计智能能力学习进度追踪、学习预警、基于标签匹配的课程推荐、学习时长统计运行环境Windows、Linux 均可推荐 2核4G 以上的云服务器或本地虚拟机启动方式后端 mvn spring-boot:run 或打成 jar 运行前端 npm run dev / npm run build NginxAPI 支持RESTful API统一返回 JSON前后端通过接口联调批量任务后端定时任务生成学习报告、处理过期课程状态、批量导入题库适合场景Java 全栈练手、毕业设计、小范围企业内训系统、在线教育系统原型这套技术栈的商业项目也在大量使用不是那种“纯学习玩具”。SpringBoot3 相比旧版最大的变化是强制要求 Java 17很多旧的 SSM 笔记在 SpringBoot3 上跑不通正好可以借这个项目把新版本依赖和配置习惯梳理清楚。Vue3 端则建议直接用script setup写法开发体验和代码量都优于 Vue2 写法。MySQL 侧重点则放在表结构设计、索引和统计 SQL 上。2. 需求拆解与适用场景2.1 角色设计系统至少分成三种角色复杂程度刚好覆盖全栈实践覆盖面管理员/讲师维护课程分类、课程信息、章节内容、试题库查看整体学情。学员注册登录、浏览课程、报名选课、逐章学习、提交学习进度、参与测试、查看学习报告。系统定时统计学习数据根据学员常学方向或填写标签推荐课程对长时间未学习的学员发送预警。这个角色模型已经足够用于面试讲解。如果想控制开发量第一阶段可以先做“学员 讲师”两种角色管理员能力放到讲师角色里。用户表加一个role字段然后借助 Spring Security 的注解控制接口权限就可以。2.2 核心业务流程一段完整业务链路是学员注册并登录进入课程列表页按分类筛选课程点击课程序章前端向后端提交学习进度比如学完了第几章节、看了多长时间、是否正确完成课时后端把数据写入学习记录表同时把累计学习时长和最新章节同步到用户学习总表。管理员每天通过定时任务统计最近 7 天活跃学员对连续 3 天未学习的报名学员生成“学习动力不足”预警记录。学习记录不是一个无意义的insert而是整个“学情智能分析”的数据底座。保存时需要考虑同一章节重复学习的覆盖策略、多条记录的时间边界、并发重复提交的问题。这一块的接口设计比普通增删改查更能体现工程能力。2.3 适用边界与合规提醒这类系统适合企业内部培训、学校课程管理、个人全栈开发练习不建议在没有课程版权授权的情况下上传商业付费课程视频。如果涉及真实学员信息需要做好敏感数据加密存储和最小权限访问。视频、试题、讲义等素材都应该确认授权范围后再投入生产环境学习系统后台最好保留内容审核和下架入口。这些边界问题在答辩和简历项目里也经常被问到提前设计好是加分项。3. 总体架构与目录规划这个项目采用前后端分离架构。用户浏览器访问 Vue3 单页应用页面请求统一走 HTTP 到后端 REST API后端由 SpringBoot3 处理业务逻辑和数据持久化数据存储在 MySQL。生产环境通常在 Vue 构建产物前面加一层 NginxNginx 托管静态文件并把/api/前缀请求反向代理到 Java 服务。前端目录和后端建议分成两个总的根目录存放比如course-frontend和course-backend。这样在 IDEA 里导入时更清晰部署时也方便分别打包。后端建议包结构com.example.course ├── common // 通用返回结果、全局异常处理、工具类 ├── config // Security、MyBatis-Plus 分页插件、跨域配置 ├── controller // 控制器层 ├── service // 业务层 │ └── impl ├── mapper // 数据访问层 ├── entity // 实体类 ├── dto // 接收前端参数的 Data Transfer Object ├── vo // 返回前端数据的 View Object ├── task // 定时统计任务 └── CourseApplication.java前端建议采用views/按业务页面拆分src ├── api // axios 请求封装 ├── assets // 静态资源 ├── components // 通用组件 ├── router // 路由配置 ├── stores // Pinia 状态 ├── views │ ├── login │ ├── course │ ├── learn │ ├── admin │ └── dashboard ├── utils └── App.vue目录规划本身不是花架子。日常开发里dto和vo分开能避免把数据库字段直接暴露给前端common里的统一返回结构能保证前端 axios 拦截器只处理一种数据格式。做这个项目时建议从一开始就坚持这种分层不要图快把所有代码堆在 Controller 里。4. MySQL 数据库设计与初始化数据库设计是课程学习系统的核心表结构设计得好后面的统计逻辑会顺畅很多。这里先给出一套可直接落地的 6 张核心表设计思路。4.1 核心表结构用户表sys_userCREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT BCrypt 加密密码, nickname VARCHAR(50) DEFAULT COMMENT 昵称, role VARCHAR(20) NOT NULL DEFAULT STUDENT COMMENT 角色ADMIN/TEACHER/STUDENT, phone VARCHAR(20) DEFAULT NULL, email VARCHAR(100) DEFAULT NULL, status TINYINT DEFAULT 1 COMMENT 1启用 0禁用, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;课程表courseCREATE TABLE course ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL COMMENT 课程名称, category_id BIGINT NOT NULL COMMENT 分类ID, cover_url VARCHAR(255) DEFAULT COMMENT 封面图, summary TEXT COMMENT 课程简介, difficulty TINYINT DEFAULT 1 COMMENT 难度1入门 2进阶 3高级, teacher_id BIGINT NOT NULL, status TINYINT DEFAULT 0 COMMENT 0草稿 1上架 2下架, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_category_status (category_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程表;章节表course_chapterCREATE TABLE course_chapter ( id BIGINT PRIMARY KEY AUTO_INCREMENT, course_id BIGINT NOT NULL, chapter_no INT NOT NULL COMMENT 章节顺序, title VARCHAR(200) NOT NULL, video_url VARCHAR(255) DEFAULT COMMENT 视频地址, content TEXT COMMENT 讲义或正文, duration INT DEFAULT 0 COMMENT 预计学习分钟数, is_free TINYINT DEFAULT 0, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_course_no (course_id, chapter_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程章节表;学习记录表study_record是最关键的一张业务表CREATE TABLE study_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, course_id BIGINT NOT NULL, chapter_id BIGINT NOT NULL, duration_seconds INT DEFAULT 0 COMMENT 本次学习时长秒, finish_flag TINYINT DEFAULT 0 COMMENT 是否完成本章0否 1是, study_date DATE NOT NULL COMMENT 学习日期, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_user_course_date (user_id, course_id, study_date), KEY idx_course_date (course_id, study_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT学习记录表;再配合课程收藏表course_favorite、测试记录表exam_record就能基本覆盖完整课程学习闭环。4.2 MySQL 中容易踩的坑关于 MySQL 本身有一个高频面试点int(5)并不是限制存 5 位整数它只是配合ZEROFILL的显示宽度真正决定整数存储范围的是int本身。建表时不要指望把int(5)当长度约束用。统计每个学员最近 7 天每天学习总时长时会用到行转列的逻辑把study_date作为动态列名把duration_seconds聚合起来这种统计适合先写普通分组查询再在 Java 或前端完成行转列展示避免直接拼复杂动态 SQL。Navicat 连接 MySQL 如果报2002或1045优先检查 MySQL 服务有没有启动、账号密码有没有写错、连接地址是不是localhost而不是写成远程端口。8.0 以上版本默认认证插件是caching_sha2_password老版本驱动连接时会报认证错误建议用较新的 mysql-connector-j 版本。4.3 初始化测试数据首次跑通项目时可以插入少量课程和章节用于联调。用户密码字段在生产里需要存 BCrypt 加密后的值可以写一个临时接口或测试类生成密文不要直接明文入库。INSERT INTO sys_user (username, password, nickname, role) VALUES (admin, $2a$10$7JB720uK7q5FQ6fX5xKZcO6VabQJj8WZc4W8n8vV5YF6uXG9aA9uS, 管理员, ADMIN);如果使用 Spring Security启动项目前保证用户表里有可登录账号否则会因为认证数据为空导致登录接口一直返回 401。5. SpringBoot3 后端开发与实现5.1 Maven 依赖配置SpringBoot3 默认使用 Java 17因此本机需要先安装 JDK 17 并配置好JAVA_HOME环境变量。如果下载完项目后启动报cannot access class sun.misc.Unsafe或invalid source release: 17大概率是 JDK 版本不对或者 IDEA 的 Project SDK 没有切换到 17。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.7/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies版本号可能不是最新的实际开发时建议以 Maven 仓库里的正式稳定版本为准。SpringBoot3 对 Security 6 的配置方式和 SpringBoot2 差别很大很多网上旧配置直接拷过来会报错遇到问题时优先查 Spring Security 6 迁移文档。5.2 全局响应结构与异常处理前端每次请求后端最好约定同一个结构。定义个ResultT里面放 code、message、data。这样 axios 响应拦截器只用解析一层格式前端判断逻辑会非常简单。全局异常处理使用RestControllerAdvice把参数校验异常、业务异常、系统异常分别处理避免服务端异常堆栈直接抛给前端。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT ok(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT fail(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }Controller 里不要直接返回裸对象而是返回Result。这能减少前端联调时出现类型对不上的问题。5.3 学习进度上报接口这是系统里最核心的业务接口。前端在学员打开某一章节、离开章节页或播放结束时调用上报接口。上报接口接收 userId、courseId、chapterId、durationSeconds、finishFlag。后端先判断该课程是否已报名、该章节是否属于课程再写入study_record。为了避免重复点击造成大量重复数据可以加一层约束同一天、同一用户、同一章节如果存在记录则累加学习时长而不是新增。Service 层的关键逻辑Service RequiredArgsConstructor public class StudyRecordServiceImpl implements StudyRecordService { private final StudyRecordMapper studyRecordMapper; private final CourseChapterMapper chapterMapper; Override Transactional(rollbackFor Exception.class) public StudyRecordVO reportProgress(StudyRecordDTO dto) { CourseChapter chapter chapterMapper.selectById(dto.getChapterId()); if (chapter null || !chapter.getCourseId().equals(dto.getCourseId())) { throw new BizException(章节不存在或课程不匹配); } StudyRecord record studyRecordMapper.selectOne(new LambdaQueryWrapperStudyRecord() .eq(StudyRecord::getUserId, dto.getUserId()) .eq(StudyRecord::getCourseId, dto.getCourseId()) .eq(StudyRecord::getChapterId, dto.getChapterId()) .eq(StudyRecord::getStudyDate, LocalDate.now())); if (record null) { record new StudyRecord(); record.setUserId(dto.getUserId()); record.setCourseId(dto.getCourseId()); record.setChapterId(dto.getChapterId()); record.setStudyDate(LocalDate.now()); record.setDurationSeconds(dto.getDurationSeconds()); record.setFinishFlag(dto.getFinishFlag()); studyRecordMapper.insert(record); } else { if (dto.getFinishFlag() ! null dto.getFinishFlag() 1) { record.setFinishFlag(1); } record.setDurationSeconds(record.getDurationSeconds() dto.getDurationSeconds()); studyRecordMapper.updateById(record); } return StudyRecordVO.builder() .todaySeconds(studyRecordMapper.selectTodaySeconds(dto.getUserId(), LocalDate.now())) .build(); } }注意Transactional加在需要多表写入或者先查后写这种复合操作上。如果一个接口只有单表简单插入加事务没太大意义还容易撑大事务范围。5.4 Spring Security 登录认证SpringBoot3 中 Spring Security 6 的默认配置会用HttpSecurity配置安全过滤链。登录接口通常放行其余以/api/admin/开头的接口限制管理员权限即可。Configuration EnableWebSecurity RequiredArgsConstructor public class SecurityConfig { private final UserDetailsService userDetailsService; Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(AbstractHttpConfigurer::disable) .cors(Customizer.withDefaults()) .authorizeHttpRequests(auth - auth .requestMatchers(/api/auth/login, /api/public/**).permitAll() .requestMatchers(/api/admin/**).hasRole(ADMIN) .anyRequest().authenticated()) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .userDetailsService(userDetailsService); return http.build(); } }认证通过后Spring Security 会向 SecurityContext 写入用户信息后续通过AuthenticationPrincipal获取当前用户。这样做的好处是所有 Controller 不需要自己从 Token 里解析 userId。6. Vue3 前端项目搭建与接口联调6.1 Vite 创建与插件安装前端项目推荐直接用 Vite 创建npm create vitelatest course-frontend -- --template vue-ts cd course-frontend npm install npm install axios pinia vue-router element-plus安装完成后在main.ts中注册 Element Plus 和 Pinia。Element Plus 对 Vue3 的原生支持很好组件风格适合后台管理类系统。6.2 API 请求封装前端请求后端接口时一定不要在每页面直接散着写axios.get。统一在src/api/request.ts里创建实例配置 baseURL、超时时间和请求拦截器。import axios from axios import { ElMessage } from element-plus import { useUserStore } from /stores/user const request axios.create({ baseURL: /api, timeout: 15000 }) request.interceptors.request.use(config { const userStore useUserStore() if (userStore.token) { config.headers.Authorization Bearer ${userStore.token} } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res.data }, error { ElMessage.error(error.response?.data?.message || 服务异常) return Promise.reject(error) } ) export default request开发环境调试时Vite 的 dev server 需要配置代理把/api转发到 SpringBoot 的 8080 端口server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样前端开发环境访问/api/course/list就会自动代理到后端http://localhost:8080/api/course/list避免开发阶段跨域问题。6.3 课程列表与学习页课程列表页最典型的一个交互是页面上显示筛选分类、分页数据。调用后端接口时的入参包括 page、pageSize、categoryId、keyword。Vue 组件里把筛选条件放成响应式数据点击查询时调用接口并重置页码到 1。学习页是学员进入某一门课程后的主场景右侧显示章节树点击章节标题后通过视频组件或富文本展示章节内容页面组件监听播放时间变化每 15 秒上报一次进度离开页面时再上报一次最终进度。这里要注意组件卸载时上报是异步请求页面关闭时可能请求还没发出最好用navigator.sendBeacon或者降低上报频率来处理在线学习系统的常见问题。6.4 路由守卫没有登录的用户访问课程学习页面时需要强制跳转到登录页。在 router 的beforeEach里判断 token 是否存在于 Pinia store。生产环境 token 建议使用 localStorage 持久化刷新后通过store重新初始化恢复。router.beforeEach((to, _from, next) { const userStore useUserStore() if (to.meta.requiresAuth !userStore.token) { next({ path: /login, query: { redirect: to.fullPath } }) } else { next() } })Vue3 的computed和watch在这一类业务中非常实用。比如课程封面地址根据用户角色显示不同的按钮学习进度数据变化后自动更新课程卡片上的百分比这些都是面试时能顺手讲的响应式细节。7. 智能学习模块与学情统计实现7.1 基于学习记录计算课程完成度要判断学员是否学完某门课程最简单的方法是统计该学员在该课程下完成的学习章节数占总章节数的比例。SQL 逻辑是查出该课程总章节数再查出该学员已经完成章节的数量两者相除得到百分比。SELECT c.id AS courseId, c.title AS courseTitle, COUNT(ch.id) AS totalChapter, COUNT(CASE WHEN sr.finish_flag 1 AND sr.user_id #{userId} THEN 1 END) AS finishedChapter FROM course c JOIN course_chapter ch ON ch.course_id c.id LEFT JOIN study_record sr ON sr.chapter_id ch.id WHERE c.id #{courseId} GROUP BY c.id, c.title这种统计结果可以作为课程列表中进度条的显示数据也可以驱动课程结业判断逻辑。7.2 学习预警与定时任务预警的规则可以设计成报名某门课程后如果学员连续 3 天没有产生新的study_record数据系统生成一条预警。这里需要查询最近学习日期和当前日期的差。SELECT user_id, course_id, MAX(study_date) AS lastStudyDate FROM study_record WHERE user_id #{userId} GROUP BY user_id, course_id定时任务用 Spring 自带的Scheduled即可不需要引入额外框架。每天凌晨 1 点执行一次扫描扫描结果写入预警表前端在登录后的首页展示待处理预警数量。7.3 课程推荐推荐算法可以先用规则版实现给用户表增加interest_tags字段课程表增加tags字段推荐时优先选择用户未报名、状态为上架、课程标签匹配度最高的一批课程。如果面试时想往深度学习方向讲可以把用户学习历史行为向量化后续替换成向量检索或其他推荐策略。但作为全栈项目先跑通规则版本代码清晰且可解释性强比硬套一个跑不动的算法更有说服力。前端首页可以命名为“为你推荐”后端提供一个/api/course/recommend接口只返回 6 条课程数据。数据来源是先取用户标签匹配度较高的课程再用最近热门课程补足。这样智能模块就有了有推荐逻辑、有学习反馈、有统计闭环不是空壳。8. 项目部署与接口验证8.1 后端打包与运行在本地开发并测试完毕后后端项目打包成 jarmvn clean package -DskipTests生成的target/course-system-0.0.1-SNAPSHOT.jar可以通过命令启动java -jar course-system-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod生产环境建议把数据库地址、密码等配置放到application-prod.yml里避免直接修改代码。启动时留意JAVA_HOME是否已配置正确以及 8080 端口是否被占用。8.2 前端构建与 Nginx 托管前端项目执行构建后生成dist目录npm run build把dist目录放到 Nginx 的 html 路径下并在 Nginx 配置里增加前端路由回退和 API 反向代理server { listen 80; server_name your-domain.com; root /opt/course-frontend/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }try_files是为了让 Vue Router 使用 history 模式时页面刷新不会出现 404。这一行对于前后端分离项目非常关键。8.3 接口验证启动后端后可以用 curl 快速验证服务状态curl http://localhost:8080/api/public/course/list如果返回包含code、message、data的 JSON 结构说明后端服务正常。登录接口则使用 POST 请求提交 JSON 数据curl -X POST http://localhost:8080/api/auth/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}正常登录后返回的响应里会有 token拿到 token 后再请求课程管理接口时放在Authorization: Bearer xxx请求头里。8.4 一键运行脚本为了本地开发方便可以在项目根目录放两个脚本。start-dev.bat负责先启动 MySQL 服务再分别启动后端和前端但前后端依赖本机 IDE 的情况不建议强行自动化。后端启动脚本只需要封装 Maven 命令cd course-backend mvn spring-boot:run -Dspring-boot.run.profilesdev前端启动cd course-frontend npm run dev正常情况下浏览器访问http://localhost:5173即可进入系统。如果页面空白且控制台报网络错误先看后端服务是否真正启动再检查前端代理配置。9. 资源占用与性能观察这类 Java Web 系统虽然不需要“显卡显存”但资源占用同样需要关注。后端 SpringBoot3 项目启动后 JVM 默认堆内存可能达到物理内存的四分之一如果服务器只有 2G 内存启动多个服务时很容易触发java: outofmemoryerror: insufficient memory。建议手动指定 JVM 参数java -Xms256m -Xmx512m -jar course-system-0.0.1-SNAPSHOT.jar观察后端进程内存和 CPU 时使用常见命令# 查看 Java 进程 jps -l # 查看系统内存 free -h # 查看进程 CPU 和内存占用 top -p $(pgrep -f course-system)MySQL 资源占用主要体现在连接数和慢查询。开发阶段连接数不会太高但并发上来后要确定连接池上限不要超过 MySQL 的max_connections。通过慢查询日志可以排查统计 SQL 的性能问题。SHOW VARIABLES LIKE slow_query_log; SHOW VARIABLES LIKE long_query_time;学习记录表的数据量会随着时间线性增长统计学情时如果直接全表扫描会越来越慢务必给常用条件建立复合索引。索引文件也会占用磁盘空间学习系统的课程视频不要直接存 MySQL视频文件放对象存储或独立静态目录数据表只存访问 URL。前端性能主要关注打包体积。Element Plus 可以通过按需引入减少首屏加载时间课程列表页的封面图使用懒加载。如果打包后单 chunk 文件很大在 Vite 配置里加manualChunks把 vue、element-plus 拆分出来利用浏览器缓存。10. 智能课程学习系统常见问题排查问题现象可能原因排查方式解决方案后端启动报invalid source release: 17JDK 版本不是 17java -version查看版本安装 JDK17 并重新设置 JAVA_HOMEMySQL 连接失败Public Key Retrieval is not allowed连接 8.0 时驱动参数问题检查 application.yml在 JDBC URL 加allowPublicKeyRetrievaltrueuseSSLfalseNavicat 连接 MySQL 报 1045用户名或密码错误检查账号权限修改密码或创建远程授权账号前端请求后端跨域代理未生效或 CORS 未配置打开浏览器 Network 看请求路径开发环境配置 Vite proxy生产环境走 Nginx 代理学习进度接口一直返回 401Token 未携带或过期查看请求头是否有 Authorization检查 axios 请求拦截器逻辑页面刷新 404Nginx 没有配置 try_files查看 Nginx 日志增加/index.html回退打包后接口地址不对前端 baseURL 是开发代理地址检查构建产物中的请求地址生产环境统一使用相对路径/api启动后页面能开但登录失败初始化密码没有加密查看数据库密码字段使用 BCrypt 重新生成密码定时任务不执行主启动类忘了加 EnableScheduling查看日志有无调度输出启动类增加EnableScheduling统计接口越跑越慢study_record表缺少索引执行 EXPLAIN 看执行计划给 user_id、course_id、study_date 加复合索引遇到问题先看日志再定位代码不要直接改数据库。SpringBoot3 的日志默认输出在控制台生产环境可以配置logging.file.name写入文件出现问题时翻日志的定位效率远高于反复猜测。11. 最佳实践与使用建议11.1 工程配置沉淀数据库连接账号密码、JWT 密钥、文件存储路径都建议放到 profile 配置文件里例如application-dev.yml用本地数据库application-prod.yml用线上数据库。密码不要提交到 Git生产密钥通过环境变量注入是最稳妥的方式。11.2 从最小闭环开始迭代第一次开发时不要一次做完所有模块。先把注册登录跑通再做课程后台管理的增删改查再做学习记录上报接口最后做统计和推荐。前三个环节每完成一个都验证接口和页面联调比最后统一调试省时间得多。11.3 批量导入与接口安全题库批量导入可以通过 Excel 或 CSV 文件上传后端用 EasyExcel 解析后写入临时表校验通过后统一插入正式表。凡是提供批量接口一定需要做权限控制和文件大小限制避免普通学员调用管理接口。批量导入时每次操作都打印日志记录操作人、文件路径、导入条数和失败原因。11.4 合规使用课程系统里涉及用户生成内容时后台必须有下架渠道。如果课程包含特定讲师出镜或有版权风险的资料要用书面授权形式确认完整性。学员列表接口不要返回明文手机号等敏感信息普通查询只输出昵称、学习时长等非敏感字段这些都属于上线前必须处理的部分。12. 总结与下一步智能课程学习系统这个项目技术栈不偏门SpringBoot3 Vue3 MySQL 是目前 Java 全栈岗位中覆盖面很广的组合。它最值得上手的地方在于“业务闭环”很完整登录有 Spring Security 支持课程数据有 MyBatis-Plus 的 CRUD 支撑学习进度上报能让你思考重复提交和并发问题学情统计则锻炼 SQL 聚合和定时任务能力。这几个点每讲清楚一个都是给简历项目增加可信度。想跑通这个项目最优先验证的三个点管理端能不能上传并上架课程学员端能不能浏览课程并完成章节学习进度上报统计接口能不能根据一段时间的记录生成正确学习报告。前两者保证系统基本可用第三个决定“智能”能不能成立。最容易踩的坑是 SpringBoot3 与旧版 Security 配置差异过大导致登录认证一直失败其次是 MySQL 连接驱动与时区参数不匹配导致启动后所有数据库操作都抛异常。下一步可以扩展的方向很多接入 Redis 做课程热度榜和验证码缓存接入消息队列做学习日志异步处理推荐模块从标签规则升级成学习记录协同过滤算法部署链路从 jar 手跑升级成 Docker Compose 一键编排。把一个业务闭环扎实做完再往工程化方向横向扩展这种路径对技术成长和面试展示都很有价值。系统跑通之后建议把项目源码整理好README 里补上系统截图、接口文档、部署教程和演示账号这才是 Java 全栈项目该有的完整交付状态。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价